8213010: Supporting keys created with certmgr.exe
Reviewed-by: valeriep
This commit is contained in:
parent
dcb88767a7
commit
a438a0766c
@ -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() {}
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user