8213010: Supporting keys created with certmgr.exe

Reviewed-by: valeriep
This commit is contained in:
Weijun Wang 2018-12-13 17:28:30 +08:00
parent dcb88767a7
commit a438a0766c
8 changed files with 720 additions and 212 deletions

View File

@ -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 @@ public class ECUtil {
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() {}
}

View File

@ -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 @@ abstract class ECDSASignature extends SignatureSpi {
if (p1363Format) {
return sig;
} else {
return encodeSignature(sig);
return ECUtil.encodeSignature(sig);
}
}
@ -476,7 +474,7 @@ abstract class ECDSASignature extends SignatureSpi {
if (p1363Format) {
sig = signature;
} else {
sig = decodeSignature(signature);
sig = ECUtil.decodeSignature(signature);
}
try {
@ -515,79 +513,6 @@ abstract class ECDSASignature extends SignatureSpi {
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.
*

View File

@ -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 @@ abstract class CKey implements Key, Length {
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;
}
}

View File

@ -759,12 +759,12 @@ abstract class CKeyStore extends KeyStoreSpi {
}
/**
* 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 @@ abstract class CKeyStore extends KeyStoreSpi {
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

View File

@ -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 @@ public abstract class CPublicKey extends CKey implements PublicKey {
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 abstract class CPublicKey extends CKey implements PublicKey {
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 abstract class CPublicKey extends CKey implements PublicKey {
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 @@ public abstract class CPublicKey extends CKey implements PublicKey {
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 @@ public abstract class CPublicKey extends CKey implements PublicKey {
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;
}

View File

@ -27,6 +27,7 @@ package sun.security.mscapi;
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.security.spec.PSSParameterSpec;
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 @@ import sun.security.rsa.RSAKeyFactory;
* . "MD5withRSA"
* . "MD2withRSA"
* . "RSASSA-PSS"
* . "SHA1withECDSA"
* . "SHA224withECDSA"
* . "SHA256withECDSA"
* . "SHA384withECDSA"
* . "SHA512withECDSA"
*
* NOTE: RSA keys must be at least 512 bits long.
*
@ -112,7 +119,8 @@ abstract class CSignature extends SignatureSpi {
@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 @@ abstract class CSignature extends SignatureSpi {
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 @@ abstract class CSignature extends SignatureSpi {
}
}
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 @@ abstract class CSignature extends SignatureSpi {
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 @@ abstract class CSignature extends SignatureSpi {
} else {
byte[] hash = getDigestValue();
return verifyCngSignedHash(
hash, hash.length,
2, hash, hash.length,
sigBytes, sigBytes.length,
pssParams.getSaltLength(),
((MGF1ParameterSpec)
@ -599,19 +706,22 @@ abstract class CSignature extends SignatureSpi {
}
/**
* 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 @@ abstract class CSignature extends SignatureSpi {
// 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;
}

View File

@ -106,6 +106,16 @@ public final class SunMSCAPI extends Provider {
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 @@ public final class SunMSCAPI extends Provider {
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
*/

View File

@ -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 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateC
}
// 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 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateC
// 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 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateC
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 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateC
}
// 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 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateC
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 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateC
}
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 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateC
// Free cert chain
if (pCertChainContext)
::CertFreeCertificateChain(pCertChainContext);
} else {
PP("GetCertificateChain failed %d", GetLastError());
}
}
}
@ -768,10 +809,10 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CSignature_signHash
/*
* 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 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CSignature_signCngHash
__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 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CSignature_signCngHash
}
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 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CSignature_signCngHash
if (pHashBuffer)
delete [] pHashBuffer;
if (hk != NULL)
if (hCryptKey != 0 && hk != NULL)
::NCryptFreeObject(hk);
}
@ -961,10 +1029,10 @@ JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_CSignature_verifySignedHash
/*
* 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 @@ JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_CSignature_verifyCngSignedHa
__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 @@ JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_CSignature_verifyCngSignedHa
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 @@ JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_CSignature_verifyCngSignedHa
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 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt
/*
* 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 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CPublicKey_getPublicKeyBlo
{
// 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 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CPublicKey_getPublicKeyBlo
}
// 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
@ -2175,6 +2378,66 @@ JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CKeyStore_storePrivateKey
return privateKey;
}
/*
* 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