feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
171
jdkSrc/jdk8/sun/security/mscapi/CKey.java
Normal file
171
jdkSrc/jdk8/sun/security/mscapi/CKey.java
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
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.
|
||||
*
|
||||
* @see CPrivateKey
|
||||
* @see CPublicKey
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Stanley Man-Kit Ho
|
||||
*/
|
||||
abstract class CKey implements Key, Length {
|
||||
private static final long serialVersionUID = -1088859394025049194L;
|
||||
|
||||
static class NativeHandles {
|
||||
|
||||
long hCryptProv = 0;
|
||||
long hCryptKey = 0;
|
||||
|
||||
public NativeHandles(long hCryptProv, long hCryptKey) {
|
||||
this.hCryptProv = hCryptProv;
|
||||
this.hCryptKey = hCryptKey;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
synchronized(this) {
|
||||
cleanUp(hCryptProv, hCryptKey);
|
||||
hCryptProv = 0;
|
||||
hCryptKey = 0;
|
||||
}
|
||||
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final NativeHandles handles;
|
||||
|
||||
protected final int keyLength;
|
||||
|
||||
protected final String algorithm;
|
||||
|
||||
private final boolean isPublic;
|
||||
|
||||
protected CKey(String algorithm, NativeHandles handles, int keyLength,
|
||||
boolean isPublic) {
|
||||
this.algorithm = algorithm;
|
||||
this.handles = handles;
|
||||
this.keyLength = keyLength;
|
||||
this.isPublic = isPublic;
|
||||
}
|
||||
|
||||
// Native method to cleanup the key handle.
|
||||
private native static void cleanUp(long hCryptProv, long hCryptKey);
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return keyLength;
|
||||
}
|
||||
|
||||
public long getHCryptKey() {
|
||||
return handles.hCryptKey;
|
||||
}
|
||||
|
||||
public long getHCryptProvider() {
|
||||
return handles.hCryptProv;
|
||||
}
|
||||
|
||||
public String getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String typeStr;
|
||||
if (handles.hCryptKey != 0) {
|
||||
typeStr = getKeyType(handles.hCryptKey) + ", container=" +
|
||||
getContainerName(handles.hCryptProv);
|
||||
} else {
|
||||
typeStr = "CNG";
|
||||
}
|
||||
return algorithm + " " + (isPublic ? "PublicKey" : "PrivateKey") +
|
||||
" [size=" + keyLength + " bits, type=" + typeStr + "]";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
55
jdkSrc/jdk8/sun/security/mscapi/CKeyPair.java
Normal file
55
jdkSrc/jdk8/sun/security/mscapi/CKeyPair.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.mscapi;
|
||||
|
||||
/**
|
||||
* The handle for an RSA public/private keypair using the Microsoft Crypto API.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
class CKeyPair {
|
||||
|
||||
private final CPrivateKey privateKey;
|
||||
|
||||
private final CPublicKey publicKey;
|
||||
|
||||
/**
|
||||
* This method is called by native codes in security.cpp.
|
||||
*/
|
||||
CKeyPair(String alg, long hCryptProv, long hCryptKey, int keyLength) {
|
||||
CKey.NativeHandles handles = new CKey.NativeHandles(hCryptProv, hCryptKey);
|
||||
privateKey = CPrivateKey.of(alg, handles, keyLength);
|
||||
publicKey = CPublicKey.of(alg, handles, keyLength);
|
||||
}
|
||||
|
||||
public CPrivateKey getPrivate() {
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
public CPublicKey getPublic() {
|
||||
return publicKey;
|
||||
}
|
||||
}
|
||||
133
jdkSrc/jdk8/sun/security/mscapi/CKeyPairGenerator.java
Normal file
133
jdkSrc/jdk8/sun/security/mscapi/CKeyPairGenerator.java
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.mscapi;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.security.*;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.spec.RSAKeyGenParameterSpec;
|
||||
|
||||
import sun.security.rsa.RSAKeyFactory;
|
||||
import static sun.security.util.SecurityProviderConstants.DEF_RSA_KEY_SIZE;
|
||||
|
||||
/**
|
||||
* RSA keypair generator.
|
||||
*
|
||||
* Standard algorithm, minimum key length is 512 bit, maximum is 16,384.
|
||||
* Generates a private key that is exportable.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract class CKeyPairGenerator extends KeyPairGeneratorSpi {
|
||||
|
||||
protected String keyAlg;
|
||||
|
||||
public CKeyPairGenerator(String keyAlg) {
|
||||
this.keyAlg = keyAlg;
|
||||
}
|
||||
|
||||
public static class RSA extends CKeyPairGenerator {
|
||||
public RSA() {
|
||||
super("RSA");
|
||||
// initialize to default in case the app does not call initialize()
|
||||
initialize(DEF_RSA_KEY_SIZE, null);
|
||||
}
|
||||
|
||||
// Supported by Microsoft Base, Strong and Enhanced Cryptographic Providers
|
||||
static final int KEY_SIZE_MIN = 512; // disallow MSCAPI min. of 384
|
||||
static final int KEY_SIZE_MAX = 16384;
|
||||
|
||||
// size of the key to generate, KEY_SIZE_MIN <= keySize <= KEY_SIZE_MAX
|
||||
private int keySize;
|
||||
|
||||
// initialize the generator. See JCA doc
|
||||
// random is always ignored
|
||||
@Override
|
||||
public void initialize(int keySize, SecureRandom random) {
|
||||
|
||||
try {
|
||||
RSAKeyFactory.checkKeyLengths(keySize, null,
|
||||
KEY_SIZE_MIN, KEY_SIZE_MAX);
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new InvalidParameterException(e.getMessage());
|
||||
}
|
||||
|
||||
this.keySize = keySize;
|
||||
}
|
||||
|
||||
// second initialize method. See JCA doc
|
||||
// random and exponent are always ignored
|
||||
@Override
|
||||
public void initialize(AlgorithmParameterSpec params, SecureRandom random)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
|
||||
int tmpSize;
|
||||
if (params == null) {
|
||||
tmpSize = DEF_RSA_KEY_SIZE;
|
||||
} else if (params instanceof RSAKeyGenParameterSpec) {
|
||||
|
||||
if (((RSAKeyGenParameterSpec) params).getPublicExponent() != null) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Exponent parameter is not supported");
|
||||
}
|
||||
tmpSize = ((RSAKeyGenParameterSpec) params).getKeysize();
|
||||
|
||||
} else {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Params must be an instance of RSAKeyGenParameterSpec");
|
||||
}
|
||||
|
||||
try {
|
||||
RSAKeyFactory.checkKeyLengths(tmpSize, null,
|
||||
KEY_SIZE_MIN, KEY_SIZE_MAX);
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Invalid Key sizes", e);
|
||||
}
|
||||
|
||||
this.keySize = tmpSize;
|
||||
}
|
||||
|
||||
// generate the keypair. See JCA doc
|
||||
@Override
|
||||
public KeyPair generateKeyPair() {
|
||||
|
||||
try {
|
||||
// Generate each keypair in a unique key container
|
||||
CKeyPair keys =
|
||||
generateCKeyPair(keyAlg, keySize,
|
||||
"{" + UUID.randomUUID().toString() + "}");
|
||||
return new KeyPair(keys.getPublic(), keys.getPrivate());
|
||||
|
||||
} catch (KeyException e) {
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static native CKeyPair generateCKeyPair(String alg, int keySize,
|
||||
String keyContainerName) throws KeyException;
|
||||
}
|
||||
}
|
||||
888
jdkSrc/jdk8/sun/security/mscapi/CKeyStore.java
Normal file
888
jdkSrc/jdk8/sun/security/mscapi/CKeyStore.java
Normal file
@@ -0,0 +1,888 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.mscapi;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.AccessController;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyStoreSpi;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecurityPermission;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.interfaces.RSAPrivateCrtKey;
|
||||
import java.util.*;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
|
||||
/**
|
||||
* Implementation of key store for Windows using the Microsoft Crypto API.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
abstract class CKeyStore extends KeyStoreSpi {
|
||||
|
||||
public static final class MY extends CKeyStore {
|
||||
public MY() {
|
||||
super("MY");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ROOT extends CKeyStore {
|
||||
public ROOT() {
|
||||
super("ROOT");
|
||||
}
|
||||
}
|
||||
|
||||
class KeyEntry {
|
||||
private CKey privateKey;
|
||||
private X509Certificate[] certChain;
|
||||
private String alias;
|
||||
|
||||
KeyEntry(CKey key, X509Certificate[] chain) {
|
||||
this(null, key, chain);
|
||||
}
|
||||
|
||||
KeyEntry(String alias, CKey key, X509Certificate[] chain) {
|
||||
this.privateKey = key;
|
||||
this.certChain = chain;
|
||||
/*
|
||||
* The default alias for both entry types is derived from a
|
||||
* hash value intrinsic to the first certificate in the chain.
|
||||
*/
|
||||
if (alias == null) {
|
||||
this.alias = Integer.toString(chain[0].hashCode());
|
||||
} else {
|
||||
this.alias = alias;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the alias for the keystore entry.
|
||||
*/
|
||||
String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alias for the keystore entry.
|
||||
*/
|
||||
void setAlias(String alias) {
|
||||
// TODO - set friendly name prop in cert store
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the private key for the keystore entry.
|
||||
*/
|
||||
CKey getPrivateKey() {
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the private key for the keystore entry.
|
||||
*/
|
||||
void setRSAPrivateKey(Key k)
|
||||
throws InvalidKeyException, KeyStoreException {
|
||||
RSAPrivateCrtKey key = (RSAPrivateCrtKey) k;
|
||||
byte[] modulusBytes = key.getModulus().toByteArray();
|
||||
|
||||
// Adjust key length due to sign bit
|
||||
int keyBitLength = (modulusBytes[0] == 0)
|
||||
? (modulusBytes.length - 1) * 8
|
||||
: modulusBytes.length * 8;
|
||||
|
||||
byte[] keyBlob = generateRSAPrivateKeyBlob(
|
||||
keyBitLength,
|
||||
modulusBytes,
|
||||
key.getPublicExponent().toByteArray(),
|
||||
key.getPrivateExponent().toByteArray(),
|
||||
key.getPrimeP().toByteArray(),
|
||||
key.getPrimeQ().toByteArray(),
|
||||
key.getPrimeExponentP().toByteArray(),
|
||||
key.getPrimeExponentQ().toByteArray(),
|
||||
key.getCrtCoefficient().toByteArray());
|
||||
|
||||
privateKey = storePrivateKey("RSA", Objects.requireNonNull(keyBlob),
|
||||
"{" + UUID.randomUUID().toString() + "}", keyBitLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the certificate chain for the keystore entry.
|
||||
*/
|
||||
X509Certificate[] getCertificateChain() {
|
||||
return certChain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the certificate chain for the keystore entry.
|
||||
*/
|
||||
void setCertificateChain(X509Certificate[] chain)
|
||||
throws CertificateException, KeyStoreException {
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
byte[] encoding = chain[i].getEncoded();
|
||||
if (i == 0 && privateKey != null) {
|
||||
storeCertificate(getName(), alias, encoding,
|
||||
encoding.length, privateKey.getHCryptProvider(),
|
||||
privateKey.getHCryptKey());
|
||||
|
||||
} else {
|
||||
storeCertificate(getName(), alias, encoding,
|
||||
encoding.length, 0L, 0L); // no private key to attach
|
||||
}
|
||||
}
|
||||
certChain = chain;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* An X.509 certificate factory.
|
||||
* Used to create an X.509 certificate from its DER-encoding.
|
||||
*/
|
||||
private CertificateFactory certificateFactory = null;
|
||||
|
||||
/*
|
||||
* Compatibility mode: for applications that assume keystores are
|
||||
* stream-based this mode tolerates (but ignores) a non-null stream
|
||||
* or password parameter when passed to the load or store methods.
|
||||
* The mode is enabled by default.
|
||||
*/
|
||||
private static final String KEYSTORE_COMPATIBILITY_MODE_PROP =
|
||||
"sun.security.mscapi.keyStoreCompatibilityMode";
|
||||
private final boolean keyStoreCompatibilityMode;
|
||||
private static final Debug debug = Debug.getInstance("keystore");
|
||||
|
||||
/*
|
||||
* The keystore entries.
|
||||
* Keys in the map are unique aliases (thus can differ from
|
||||
* KeyEntry.getAlias())
|
||||
*/
|
||||
private Map<String,KeyEntry> entries = new HashMap<>();
|
||||
|
||||
/*
|
||||
* The keystore name.
|
||||
* Case is not significant.
|
||||
*/
|
||||
private final String storeName;
|
||||
|
||||
CKeyStore(String storeName) {
|
||||
// Get the compatibility mode
|
||||
String prop = AccessController.doPrivileged(
|
||||
(PrivilegedAction<String>) () -> System.getProperty(KEYSTORE_COMPATIBILITY_MODE_PROP));
|
||||
|
||||
if ("false".equalsIgnoreCase(prop)) {
|
||||
keyStoreCompatibilityMode = false;
|
||||
} else {
|
||||
keyStoreCompatibilityMode = true;
|
||||
}
|
||||
|
||||
this.storeName = storeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key associated with the given alias.
|
||||
* <p>
|
||||
* A compatibility mode is supported for applications that assume
|
||||
* a password must be supplied. It permits (but ignores) a non-null
|
||||
* <code>password</code>. The mode is enabled by default.
|
||||
* Set the
|
||||
* <code>sun.security.mscapi.keyStoreCompatibilityMode</code>
|
||||
* system property to <code>false</code> to disable compatibility mode
|
||||
* and reject a non-null <code>password</code>.
|
||||
*
|
||||
* @param alias the alias name
|
||||
* @param password the password, which should be <code>null</code>
|
||||
*
|
||||
* @return the requested key, or null if the given alias does not exist
|
||||
* or does not identify a <i>key entry</i>.
|
||||
*
|
||||
* @exception NoSuchAlgorithmException if the algorithm for recovering the
|
||||
* key cannot be found,
|
||||
* or if compatibility mode is disabled and <code>password</code> is
|
||||
* non-null.
|
||||
* @exception UnrecoverableKeyException if the key cannot be recovered.
|
||||
*/
|
||||
public java.security.Key engineGetKey(String alias, char[] password)
|
||||
throws NoSuchAlgorithmException, UnrecoverableKeyException {
|
||||
if (alias == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (password != null && !keyStoreCompatibilityMode) {
|
||||
throw new UnrecoverableKeyException("Password must be null");
|
||||
}
|
||||
|
||||
if (engineIsKeyEntry(alias) == false)
|
||||
return null;
|
||||
|
||||
KeyEntry entry = entries.get(alias);
|
||||
return (entry == null)
|
||||
? null
|
||||
: entry.getPrivateKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the certificate chain associated with the given alias.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @return the certificate chain (ordered with the user's certificate first
|
||||
* and the root certificate authority last), or null if the given alias
|
||||
* does not exist or does not contain a certificate chain (i.e., the given
|
||||
* alias identifies either a <i>trusted certificate entry</i> or a
|
||||
* <i>key entry</i> without a certificate chain).
|
||||
*/
|
||||
public Certificate[] engineGetCertificateChain(String alias) {
|
||||
if (alias == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
KeyEntry entry = entries.get(alias);
|
||||
X509Certificate[] certChain = (entry == null)
|
||||
? null
|
||||
: entry.getCertificateChain();
|
||||
return (certChain == null)
|
||||
? null
|
||||
: certChain.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the certificate associated with the given alias.
|
||||
*
|
||||
* <p>If the given alias name identifies a
|
||||
* <i>trusted certificate entry</i>, the certificate associated with that
|
||||
* entry is returned. If the given alias name identifies a
|
||||
* <i>key entry</i>, the first element of the certificate chain of that
|
||||
* entry is returned, or null if that entry does not have a certificate
|
||||
* chain.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @return the certificate, or null if the given alias does not exist or
|
||||
* does not contain a certificate.
|
||||
*/
|
||||
public Certificate engineGetCertificate(String alias) {
|
||||
if (alias == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
KeyEntry entry = entries.get(alias);
|
||||
X509Certificate[] certChain = (entry == null)
|
||||
? null
|
||||
: entry.getCertificateChain();
|
||||
return (certChain == null || certChain.length == 0)
|
||||
? null
|
||||
: certChain[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the creation date of the entry identified by the given alias.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @return the creation date of this entry, or null if the given alias does
|
||||
* not exist
|
||||
*/
|
||||
public Date engineGetCreationDate(String alias) {
|
||||
if (alias == null) {
|
||||
return null;
|
||||
}
|
||||
return new Date();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the given private key and associated certificate chain in the
|
||||
* keystore.
|
||||
*
|
||||
* <p>The given java.security.PrivateKey <code>key</code> must
|
||||
* be accompanied by a certificate chain certifying the
|
||||
* corresponding public key.
|
||||
*
|
||||
* <p>If the given alias already exists, the keystore information
|
||||
* associated with it is overridden by the given key and certificate
|
||||
* chain. Otherwise, a new entry is created.
|
||||
*
|
||||
* <p>
|
||||
* A compatibility mode is supported for applications that assume
|
||||
* a password must be supplied. It permits (but ignores) a non-null
|
||||
* <code>password</code>. The mode is enabled by default.
|
||||
* Set the
|
||||
* <code>sun.security.mscapi.keyStoreCompatibilityMode</code>
|
||||
* system property to <code>false</code> to disable compatibility mode
|
||||
* and reject a non-null <code>password</code>.
|
||||
*
|
||||
* @param alias the alias name
|
||||
* @param key the private key to be associated with the alias
|
||||
* @param password the password, which should be <code>null</code>
|
||||
* @param chain the certificate chain for the corresponding public
|
||||
* key (only required if the given key is of type
|
||||
* <code>java.security.PrivateKey</code>).
|
||||
*
|
||||
* @exception KeyStoreException if the given key is not a private key,
|
||||
* cannot be protected, or if compatibility mode is disabled and
|
||||
* <code>password</code> is non-null, or if this operation fails for
|
||||
* some other reason.
|
||||
*/
|
||||
public void engineSetKeyEntry(String alias, java.security.Key key,
|
||||
char[] password, Certificate[] chain) throws KeyStoreException {
|
||||
if (alias == null) {
|
||||
throw new KeyStoreException("alias must not be null");
|
||||
}
|
||||
|
||||
if (password != null && !keyStoreCompatibilityMode) {
|
||||
throw new KeyStoreException("Password must be null");
|
||||
}
|
||||
|
||||
if (key instanceof RSAPrivateCrtKey) {
|
||||
|
||||
KeyEntry entry = entries.get(alias);
|
||||
|
||||
X509Certificate[] xchain;
|
||||
if (chain != null) {
|
||||
if (chain instanceof X509Certificate[]) {
|
||||
xchain = (X509Certificate[]) chain;
|
||||
} else {
|
||||
xchain = new X509Certificate[chain.length];
|
||||
System.arraycopy(chain, 0, xchain, 0, chain.length);
|
||||
}
|
||||
} else {
|
||||
xchain = null;
|
||||
}
|
||||
|
||||
if (entry == null) {
|
||||
entry =
|
||||
//TODO new KeyEntry(alias, key, (X509Certificate[]) chain);
|
||||
new KeyEntry(alias, null, xchain);
|
||||
storeWithUniqueAlias(alias, entry);
|
||||
}
|
||||
|
||||
entry.setAlias(alias);
|
||||
|
||||
try {
|
||||
entry.setRSAPrivateKey(key);
|
||||
entry.setCertificateChain(xchain);
|
||||
|
||||
} catch (CertificateException ce) {
|
||||
throw new KeyStoreException(ce);
|
||||
|
||||
} catch (InvalidKeyException ike) {
|
||||
throw new KeyStoreException(ike);
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot assign the key to the given alias.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the given key (that has already been protected) to the given
|
||||
* alias.
|
||||
*
|
||||
* <p>If the protected key is of type
|
||||
* <code>java.security.PrivateKey</code>, it must be accompanied by a
|
||||
* certificate chain certifying the corresponding public key. If the
|
||||
* underlying keystore implementation is of type <code>jks</code>,
|
||||
* <code>key</code> must be encoded as an
|
||||
* <code>EncryptedPrivateKeyInfo</code> as defined in the PKCS #8 standard.
|
||||
*
|
||||
* <p>If the given alias already exists, the keystore information
|
||||
* associated with it is overridden by the given key (and possibly
|
||||
* certificate chain).
|
||||
*
|
||||
* @param alias the alias name
|
||||
* @param key the key (in protected format) to be associated with the alias
|
||||
* @param chain the certificate chain for the corresponding public
|
||||
* key (only useful if the protected key is of type
|
||||
* <code>java.security.PrivateKey</code>).
|
||||
*
|
||||
* @exception KeyStoreException if this operation fails.
|
||||
*/
|
||||
public void engineSetKeyEntry(String alias, byte[] key,
|
||||
Certificate[] chain)
|
||||
throws KeyStoreException {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot assign the encoded key to the given alias.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the given certificate to the given alias.
|
||||
*
|
||||
* <p>If the given alias already exists in this keystore and identifies a
|
||||
* <i>trusted certificate entry</i>, the certificate associated with it is
|
||||
* overridden by the given certificate.
|
||||
*
|
||||
* @param alias the alias name
|
||||
* @param cert the certificate
|
||||
*
|
||||
* @exception KeyStoreException if the given alias already exists and does
|
||||
* not identify a <i>trusted certificate entry</i>, or this operation
|
||||
* fails for some other reason.
|
||||
*/
|
||||
public void engineSetCertificateEntry(String alias, Certificate cert)
|
||||
throws KeyStoreException {
|
||||
if (alias == null) {
|
||||
throw new KeyStoreException("alias must not be null");
|
||||
}
|
||||
|
||||
if (cert instanceof X509Certificate) {
|
||||
|
||||
// TODO - build CryptoAPI chain?
|
||||
X509Certificate[] chain =
|
||||
new X509Certificate[]{ (X509Certificate) cert };
|
||||
KeyEntry entry = entries.get(alias);
|
||||
|
||||
if (entry == null) {
|
||||
entry =
|
||||
new KeyEntry(alias, null, chain);
|
||||
storeWithUniqueAlias(alias, entry);
|
||||
}
|
||||
|
||||
if (entry.getPrivateKey() == null) { // trusted-cert entry
|
||||
entry.setAlias(alias);
|
||||
|
||||
try {
|
||||
entry.setCertificateChain(chain);
|
||||
|
||||
} catch (CertificateException ce) {
|
||||
throw new KeyStoreException(ce);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot assign the certificate to the given alias.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the entry identified by the given alias from this keystore.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @exception KeyStoreException if the entry cannot be removed.
|
||||
*/
|
||||
public void engineDeleteEntry(String alias) throws KeyStoreException {
|
||||
if (alias == null) {
|
||||
throw new KeyStoreException("alias must not be null");
|
||||
}
|
||||
|
||||
KeyEntry entry = entries.remove(alias);
|
||||
if (entry != null) {
|
||||
// Get end-entity certificate and remove from system cert store
|
||||
X509Certificate[] certChain = entry.getCertificateChain();
|
||||
if (certChain != null && certChain.length > 0) {
|
||||
|
||||
try {
|
||||
|
||||
byte[] encoding = certChain[0].getEncoded();
|
||||
removeCertificate(getName(), entry.getAlias(), encoding,
|
||||
encoding.length);
|
||||
|
||||
} catch (CertificateException e) {
|
||||
throw new KeyStoreException("Cannot remove entry: ", e);
|
||||
}
|
||||
}
|
||||
CKey privateKey = entry.getPrivateKey();
|
||||
if (privateKey != null) {
|
||||
destroyKeyContainer(
|
||||
CKey.getContainerName(privateKey.getHCryptProvider()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all the alias names of this keystore.
|
||||
*
|
||||
* @return enumeration of the alias names
|
||||
*/
|
||||
public Enumeration<String> engineAliases() {
|
||||
final Iterator<String> iter = entries.keySet().iterator();
|
||||
|
||||
return new Enumeration<String>() {
|
||||
public boolean hasMoreElements() {
|
||||
return iter.hasNext();
|
||||
}
|
||||
|
||||
public String nextElement() {
|
||||
return iter.next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given alias exists in this keystore.
|
||||
*
|
||||
* @param alias the alias name
|
||||
*
|
||||
* @return true if the alias exists, false otherwise
|
||||
*/
|
||||
public boolean engineContainsAlias(String alias) {
|
||||
return entries.containsKey(alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the number of entries in this keystore.
|
||||
*
|
||||
* @return the number of entries in this keystore
|
||||
*/
|
||||
public int engineSize() {
|
||||
return entries.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the entry identified by the given alias is a
|
||||
* <i>key entry</i>, and false otherwise.
|
||||
*
|
||||
* @return true if the entry identified by the given alias is a
|
||||
* <i>key entry</i>, false otherwise.
|
||||
*/
|
||||
public boolean engineIsKeyEntry(String alias) {
|
||||
|
||||
if (alias == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
KeyEntry entry = entries.get(alias);
|
||||
return entry != null && entry.getPrivateKey() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the entry identified by the given alias is a
|
||||
* <i>trusted certificate entry</i>, and false otherwise.
|
||||
*
|
||||
* @return true if the entry identified by the given alias is a
|
||||
* <i>trusted certificate entry</i>, false otherwise.
|
||||
*/
|
||||
public boolean engineIsCertificateEntry(String alias) {
|
||||
|
||||
if (alias == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
KeyEntry entry = entries.get(alias);
|
||||
return entry != null && entry.getPrivateKey() == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the (alias) name of the first keystore entry whose certificate
|
||||
* matches the given certificate.
|
||||
*
|
||||
* <p>This method attempts to match the given certificate with each
|
||||
* keystore entry. If the entry being considered
|
||||
* is a <i>trusted certificate entry</i>, the given certificate is
|
||||
* compared to that entry's certificate. If the entry being considered is
|
||||
* a <i>key entry</i>, the given certificate is compared to the first
|
||||
* element of that entry's certificate chain (if a chain exists).
|
||||
*
|
||||
* @param cert the certificate to match with.
|
||||
*
|
||||
* @return the (alias) name of the first entry with matching certificate,
|
||||
* or null if no such entry exists in this keystore.
|
||||
*/
|
||||
public String engineGetCertificateAlias(Certificate cert) {
|
||||
|
||||
for (Map.Entry<String,KeyEntry> mapEntry : entries.entrySet()) {
|
||||
KeyEntry entry = mapEntry.getValue();
|
||||
if (entry.certChain != null &&
|
||||
entry.certChain.length > 0 &&
|
||||
entry.certChain[0].equals(cert)) {
|
||||
return entry.getAlias();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* engineStore is currently a no-op.
|
||||
* Entries are stored during engineSetEntry.
|
||||
*
|
||||
* A compatibility mode is supported for applications that assume
|
||||
* keystores are stream-based. It permits (but ignores) a non-null
|
||||
* <code>stream</code> or <code>password</code>.
|
||||
* The mode is enabled by default.
|
||||
* Set the
|
||||
* <code>sun.security.mscapi.keyStoreCompatibilityMode</code>
|
||||
* system property to <code>false</code> to disable compatibility mode
|
||||
* and reject a non-null <code>stream</code> or <code>password</code>.
|
||||
*
|
||||
* @param stream the output stream, which should be <code>null</code>
|
||||
* @param password the password, which should be <code>null</code>
|
||||
*
|
||||
* @exception IOException if compatibility mode is disabled and either
|
||||
* parameter is non-null.
|
||||
*/
|
||||
public void engineStore(OutputStream stream, char[] password)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException {
|
||||
if (stream != null && !keyStoreCompatibilityMode) {
|
||||
throw new IOException("Keystore output stream must be null");
|
||||
}
|
||||
|
||||
if (password != null && !keyStoreCompatibilityMode) {
|
||||
throw new IOException("Keystore password must be null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the keystore.
|
||||
*
|
||||
* A compatibility mode is supported for applications that assume
|
||||
* keystores are stream-based. It permits (but ignores) a non-null
|
||||
* <code>stream</code> or <code>password</code>.
|
||||
* The mode is enabled by default.
|
||||
* Set the
|
||||
* <code>sun.security.mscapi.keyStoreCompatibilityMode</code>
|
||||
* system property to <code>false</code> to disable compatibility mode
|
||||
* and reject a non-null <code>stream</code> or <code>password</code>.
|
||||
*
|
||||
* @param stream the input stream, which should be <code>null</code>.
|
||||
* @param password the password, which should be <code>null</code>.
|
||||
*
|
||||
* @exception IOException if there is an I/O or format problem with the
|
||||
* keystore data. Or if compatibility mode is disabled and either
|
||||
* parameter is non-null.
|
||||
* @exception NoSuchAlgorithmException if the algorithm used to check
|
||||
* the integrity of the keystore cannot be found
|
||||
* @exception CertificateException if any of the certificates in the
|
||||
* keystore could not be loaded
|
||||
* @exception SecurityException if the security check for
|
||||
* <code>SecurityPermission("authProvider.<i>name</i>")</code> does not
|
||||
* pass, where <i>name</i> is the value returned by
|
||||
* this provider's <code>getName</code> method.
|
||||
*/
|
||||
public void engineLoad(InputStream stream, char[] password)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException {
|
||||
if (stream != null && !keyStoreCompatibilityMode) {
|
||||
throw new IOException("Keystore input stream must be null");
|
||||
}
|
||||
|
||||
if (password != null && !keyStoreCompatibilityMode) {
|
||||
throw new IOException("Keystore password must be null");
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the same security check as AuthProvider.login
|
||||
*/
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new SecurityPermission(
|
||||
"authProvider.SunMSCAPI"));
|
||||
}
|
||||
|
||||
// Clear all key entries
|
||||
entries.clear();
|
||||
|
||||
try {
|
||||
|
||||
// Load keys and/or certificate chains
|
||||
loadKeysOrCertificateChains(getName());
|
||||
|
||||
} catch (KeyStoreException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
|
||||
if (debug != null) {
|
||||
debug.println("MSCAPI keystore load: entry count: " +
|
||||
entries.size());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the given entry into the map, making sure
|
||||
* the alias, used as the key is unique.
|
||||
* If the same alias already exists, it tries to append
|
||||
* a suffix (1), (2), etc to it until it finds a unique
|
||||
* value.
|
||||
*/
|
||||
private void storeWithUniqueAlias(String alias, KeyEntry entry) {
|
||||
String uniqAlias = alias;
|
||||
int uniqNum = 1;
|
||||
|
||||
while (true) {
|
||||
if (entries.putIfAbsent(uniqAlias, entry) == null) {
|
||||
break;
|
||||
}
|
||||
uniqAlias = alias + " (" + (uniqNum++) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a certificate chain from the collection of
|
||||
* certificates and stores the result into a key entry.
|
||||
* <p>
|
||||
* This method is called by native codes in security.cpp.
|
||||
*/
|
||||
private void generateCertificateChain(String alias,
|
||||
Collection<? extends Certificate> certCollection) {
|
||||
try {
|
||||
X509Certificate[] certChain =
|
||||
new X509Certificate[certCollection.size()];
|
||||
|
||||
int i = 0;
|
||||
for (Iterator<? extends Certificate> iter =
|
||||
certCollection.iterator(); iter.hasNext(); i++) {
|
||||
certChain[i] = (X509Certificate) iter.next();
|
||||
}
|
||||
|
||||
storeWithUniqueAlias(alias,
|
||||
new KeyEntry(alias, null, certChain));
|
||||
} catch (Throwable e) {
|
||||
// Ignore the exception and skip this entry
|
||||
// TODO - throw CertificateException?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 generateKeyAndCertificateChain(boolean isRSA, String alias,
|
||||
long hCryptProv, long hCryptKey, int keyLength,
|
||||
Collection<? extends Certificate> certCollection) {
|
||||
try {
|
||||
X509Certificate[] certChain =
|
||||
new X509Certificate[certCollection.size()];
|
||||
|
||||
int i = 0;
|
||||
for (Iterator<? extends Certificate> iter =
|
||||
certCollection.iterator(); iter.hasNext(); i++) {
|
||||
certChain[i] = (X509Certificate) iter.next();
|
||||
}
|
||||
storeWithUniqueAlias(alias, new KeyEntry(alias,
|
||||
CPrivateKey.of(isRSA ? "RSA" : "EC", hCryptProv, hCryptKey, keyLength),
|
||||
certChain));
|
||||
} catch (Throwable e) {
|
||||
// Ignore the exception and skip this entry
|
||||
// TODO - throw CertificateException?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates certificates from byte data and stores into cert collection.
|
||||
* <p>
|
||||
* This method is called by native codes in security.cpp.
|
||||
*
|
||||
* @param data Byte data.
|
||||
* @param certCollection Collection of certificates.
|
||||
*/
|
||||
private void generateCertificate(byte[] data,
|
||||
Collection<Certificate> certCollection) {
|
||||
try {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(data);
|
||||
|
||||
// Obtain certificate factory
|
||||
if (certificateFactory == null) {
|
||||
certificateFactory = CertificateFactory.getInstance("X.509", "SUN");
|
||||
}
|
||||
|
||||
// Generate certificate
|
||||
Collection<? extends Certificate> c =
|
||||
certificateFactory.generateCertificates(bis);
|
||||
certCollection.addAll(c);
|
||||
} catch (CertificateException e) {
|
||||
// Ignore the exception and skip this certificate
|
||||
// TODO - throw CertificateException?
|
||||
} catch (Throwable te) {
|
||||
// Ignore the exception and skip this certificate
|
||||
// TODO - throw CertificateException?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the keystore.
|
||||
*/
|
||||
private String getName() {
|
||||
return storeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load keys and/or certificates from keystore into Collection.
|
||||
*
|
||||
* @param name Name of keystore.
|
||||
*/
|
||||
private native void loadKeysOrCertificateChains(String name)
|
||||
throws KeyStoreException;
|
||||
|
||||
/**
|
||||
* Stores a DER-encoded certificate into the certificate store
|
||||
*
|
||||
* @param name Name of the keystore.
|
||||
* @param alias Name of the certificate.
|
||||
* @param encoding DER-encoded certificate.
|
||||
*/
|
||||
private native void storeCertificate(String name, String alias,
|
||||
byte[] encoding, int encodingLength, long hCryptProvider,
|
||||
long hCryptKey) throws CertificateException, KeyStoreException;
|
||||
|
||||
/**
|
||||
* Removes the certificate from the certificate store
|
||||
*
|
||||
* @param name Name of the keystore.
|
||||
* @param alias Name of the certificate.
|
||||
* @param encoding DER-encoded certificate.
|
||||
*/
|
||||
private native void removeCertificate(String name, String alias,
|
||||
byte[] encoding, int encodingLength)
|
||||
throws CertificateException, KeyStoreException;
|
||||
|
||||
/**
|
||||
* Destroys the key container.
|
||||
*
|
||||
* @param keyContainerName The name of the key container.
|
||||
*/
|
||||
private native void destroyKeyContainer(String keyContainerName)
|
||||
throws KeyStoreException;
|
||||
|
||||
/**
|
||||
* Generates a private-key BLOB from a key's components.
|
||||
*/
|
||||
private native byte[] generateRSAPrivateKeyBlob(
|
||||
int keyBitLength,
|
||||
byte[] modulus,
|
||||
byte[] publicExponent,
|
||||
byte[] privateExponent,
|
||||
byte[] primeP,
|
||||
byte[] primeQ,
|
||||
byte[] exponentP,
|
||||
byte[] exponentQ,
|
||||
byte[] crtCoefficient) throws InvalidKeyException;
|
||||
|
||||
private native CPrivateKey storePrivateKey(String alg, byte[] keyBlob,
|
||||
String keyContainerName, int keySize) throws KeyStoreException;
|
||||
}
|
||||
88
jdkSrc/jdk8/sun/security/mscapi/CPrivateKey.java
Normal file
88
jdkSrc/jdk8/sun/security/mscapi/CPrivateKey.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2023, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.mscapi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.security.PrivateKey;
|
||||
|
||||
/**
|
||||
* The handle for a private key using the Microsoft Crypto API.
|
||||
*
|
||||
* @author Stanley Man-Kit Ho
|
||||
* @since 1.6
|
||||
*/
|
||||
class CPrivateKey extends CKey implements PrivateKey {
|
||||
|
||||
private static final long serialVersionUID = 8113152807912338063L;
|
||||
|
||||
private CPrivateKey(String alg, NativeHandles handles, int keyLength) {
|
||||
super(alg, handles, keyLength, false);
|
||||
}
|
||||
|
||||
// Called by native code inside security.cpp
|
||||
static CPrivateKey of(
|
||||
String alg, long hCryptProv, long hCryptKey, int keyLength) {
|
||||
return of(alg, new NativeHandles(hCryptProv, hCryptKey), keyLength);
|
||||
}
|
||||
|
||||
public static CPrivateKey of(String alg, NativeHandles handles, int keyLength) {
|
||||
return new CPrivateKey(alg, handles, keyLength);
|
||||
}
|
||||
|
||||
// this key does not support encoding
|
||||
public String getFormat() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// this key does not support encoding
|
||||
public byte[] getEncoded() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// This class is not serializable
|
||||
private void writeObject(java.io.ObjectOutputStream out)
|
||||
throws java.io.IOException {
|
||||
throw new java.io.InvalidObjectException(
|
||||
"CPrivateKeys are not serializable");
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
* <p>
|
||||
* Deserialization of this object is not supported.
|
||||
*
|
||||
* @param stream the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException(
|
||||
"CPrivateKeys are not deserializable");
|
||||
}
|
||||
}
|
||||
236
jdkSrc/jdk8/sun/security/mscapi/CPublicKey.java
Normal file
236
jdkSrc/jdk8/sun/security/mscapi/CPublicKey.java
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2023, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.mscapi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
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.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public abstract class CPublicKey extends CKey implements PublicKey {
|
||||
|
||||
private static final long serialVersionUID = -2289561342425825391L;
|
||||
|
||||
protected byte[] encoding = null;
|
||||
|
||||
public static class CECPublicKey extends CPublicKey implements ECPublicKey {
|
||||
|
||||
private ECPoint w = null;
|
||||
private static final long serialVersionUID = 12L;
|
||||
|
||||
CECPublicKey(NativeHandles handles, int keyLength) {
|
||||
super("EC", handles, 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(super.toString());
|
||||
sb.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;
|
||||
private BigInteger exponent = null;
|
||||
private static final long serialVersionUID = 12L;
|
||||
|
||||
CRSAPublicKey(NativeHandles handles, int keyLength) {
|
||||
super("RSA", handles, keyLength);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer(super.toString());
|
||||
sb.append("\n modulus: ").append(getModulus())
|
||||
.append("\n public exponent: ").append(getPublicExponent());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getPublicExponent() {
|
||||
if (exponent == null) {
|
||||
try {
|
||||
byte[] publicKeyBlob = getPublicKeyBlob(
|
||||
handles.hCryptProv, handles.hCryptKey);
|
||||
exponent = new BigInteger(1, getExponent(publicKeyBlob));
|
||||
} catch (KeyException e) {
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
}
|
||||
return exponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getModulus() {
|
||||
if (modulus == null) {
|
||||
try {
|
||||
byte[] publicKeyBlob = getPublicKeyBlob(
|
||||
handles.hCryptProv, handles.hCryptKey);
|
||||
modulus = new BigInteger(1, getModulus(publicKeyBlob));
|
||||
} catch (KeyException e) {
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
}
|
||||
return modulus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
if (encoding == null) {
|
||||
try {
|
||||
encoding = RSAPublicKeyImpl.newKey(KeyType.RSA, null,
|
||||
getModulus(), getPublicExponent()).getEncoded();
|
||||
} catch (KeyException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return encoding;
|
||||
}
|
||||
|
||||
private native byte[] getExponent(byte[] keyBlob) throws KeyException;
|
||||
|
||||
private native byte[] getModulus(byte[] keyBlob) throws KeyException;
|
||||
}
|
||||
|
||||
// Called by native code inside security.cpp
|
||||
static CPublicKey of(
|
||||
String alg, long hCryptProv, long hCryptKey, int keyLength) {
|
||||
return of(alg, new NativeHandles(hCryptProv, hCryptKey), keyLength);
|
||||
}
|
||||
|
||||
public static CPublicKey of(
|
||||
String alg, NativeHandles handles, int keyLength) {
|
||||
switch (alg) {
|
||||
case "RSA":
|
||||
return new CRSAPublicKey(handles, keyLength);
|
||||
case "EC":
|
||||
return new CECPublicKey(handles, keyLength);
|
||||
default:
|
||||
throw new AssertionError("Unsupported algorithm: " + alg);
|
||||
}
|
||||
}
|
||||
|
||||
protected CPublicKey(
|
||||
String alg, NativeHandles handles, int keyLength) {
|
||||
super(alg, handles, keyLength, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFormat() {
|
||||
return "X.509";
|
||||
}
|
||||
|
||||
protected Object writeReplace() throws java.io.ObjectStreamException {
|
||||
return new KeyRep(KeyRep.Type.PUBLIC,
|
||||
getAlgorithm(),
|
||||
getFormat(),
|
||||
getEncoded());
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
* <p>
|
||||
* Deserialization of this object is not supported.
|
||||
*
|
||||
* @param stream the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException(
|
||||
"CPublicKeys are not deserializable");
|
||||
}
|
||||
|
||||
// Returns the CAPI or CNG representation of the key.
|
||||
native byte[] getPublicKeyBlob(long hCryptProv, long hCryptKey)
|
||||
throws KeyException;
|
||||
}
|
||||
521
jdkSrc/jdk8/sun/security/mscapi/CRSACipher.java
Normal file
521
jdkSrc/jdk8/sun/security/mscapi/CRSACipher.java
Normal file
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2023, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.mscapi;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.Key;
|
||||
import java.security.interfaces.*;
|
||||
import java.security.spec.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.*;
|
||||
|
||||
import sun.security.rsa.RSAKeyFactory;
|
||||
import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
|
||||
import sun.security.util.KeyUtil;
|
||||
|
||||
/**
|
||||
* Cipher implementation using the Microsoft Crypto API.
|
||||
* Supports RSA en/decryption and signing/verifying using PKCS#1 v1.5 padding.
|
||||
*
|
||||
* Objects should be instantiated by calling Cipher.getInstance() using the
|
||||
* following algorithm name:
|
||||
*
|
||||
* . "RSA/ECB/PKCS1Padding" (or "RSA") for PKCS#1 padding. The mode (blocktype)
|
||||
* is selected based on the en/decryption mode and public/private key used.
|
||||
*
|
||||
* We only do one RSA operation per doFinal() call. If the application passes
|
||||
* more data via calls to update() or doFinal(), we throw an
|
||||
* IllegalBlockSizeException when doFinal() is called (see JCE API spec).
|
||||
* Bulk encryption using RSA does not make sense and is not standardized.
|
||||
*
|
||||
* Note: RSA keys should be at least 512 bits long
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Andreas Sterbenz
|
||||
* @author Vincent Ryan
|
||||
*/
|
||||
public final class CRSACipher extends CipherSpi {
|
||||
|
||||
private static final int ERROR_INVALID_PARAMETER = 0x57;
|
||||
private static final int NTE_INVALID_PARAMETER = 0x80090027;
|
||||
|
||||
// constant for an empty byte array
|
||||
private final static byte[] B0 = new byte[0];
|
||||
|
||||
// mode constant for public key encryption
|
||||
private final static int MODE_ENCRYPT = 1;
|
||||
// mode constant for private key decryption
|
||||
private final static int MODE_DECRYPT = 2;
|
||||
// mode constant for private key encryption (signing)
|
||||
private final static int MODE_SIGN = 3;
|
||||
// mode constant for public key decryption (verifying)
|
||||
private final static int MODE_VERIFY = 4;
|
||||
|
||||
// constant for PKCS#1 v1.5 RSA
|
||||
private final static String PAD_PKCS1 = "PKCS1Padding";
|
||||
private final static int PAD_PKCS1_LENGTH = 11;
|
||||
|
||||
// current mode, one of MODE_* above. Set when init() is called
|
||||
private int mode;
|
||||
|
||||
// active padding type, one of PAD_* above. Set by setPadding()
|
||||
private String paddingType;
|
||||
private int paddingLength = 0;
|
||||
|
||||
// buffer for the data
|
||||
private byte[] buffer;
|
||||
// offset into the buffer (number of bytes buffered)
|
||||
private int bufOfs;
|
||||
|
||||
// size of the output (the length of the key).
|
||||
private int outputSize;
|
||||
|
||||
// the public key, if we were initialized using a public key
|
||||
private CKey publicKey;
|
||||
|
||||
// the private key, if we were initialized using a private key
|
||||
private CKey privateKey;
|
||||
|
||||
// cipher parameter for TLS RSA premaster secret
|
||||
private AlgorithmParameterSpec spec = null;
|
||||
|
||||
private boolean forTlsPremasterSecret = false;
|
||||
|
||||
// the source of randomness
|
||||
private SecureRandom random;
|
||||
|
||||
public CRSACipher() {
|
||||
paddingType = PAD_PKCS1;
|
||||
}
|
||||
|
||||
// modes do not make sense for RSA, but allow ECB
|
||||
// see JCE spec
|
||||
protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
|
||||
if (mode.equalsIgnoreCase("ECB") == false) {
|
||||
throw new NoSuchAlgorithmException("Unsupported mode " + mode);
|
||||
}
|
||||
}
|
||||
|
||||
// set the padding type
|
||||
// see JCE spec
|
||||
protected void engineSetPadding(String paddingName)
|
||||
throws NoSuchPaddingException {
|
||||
if (paddingName.equalsIgnoreCase(PAD_PKCS1)) {
|
||||
paddingType = PAD_PKCS1;
|
||||
} else {
|
||||
throw new NoSuchPaddingException
|
||||
("Padding " + paddingName + " not supported");
|
||||
}
|
||||
}
|
||||
|
||||
// return 0 as block size, we are not a block cipher
|
||||
// see JCE spec
|
||||
protected int engineGetBlockSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return the output size
|
||||
// see JCE spec
|
||||
protected int engineGetOutputSize(int inputLen) {
|
||||
return outputSize;
|
||||
}
|
||||
|
||||
// no iv, return null
|
||||
// see JCE spec
|
||||
protected byte[] engineGetIV() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// no parameters, return null
|
||||
// see JCE spec
|
||||
protected AlgorithmParameters engineGetParameters() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected void engineInit(int opmode, Key key, SecureRandom random)
|
||||
throws InvalidKeyException {
|
||||
init(opmode, key);
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void engineInit(int opmode, Key key,
|
||||
AlgorithmParameterSpec params, SecureRandom random)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
|
||||
if (params != null) {
|
||||
if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Parameters not supported");
|
||||
}
|
||||
spec = params;
|
||||
this.random = random; // for TLS RSA premaster secret
|
||||
this.forTlsPremasterSecret = true;
|
||||
} else {
|
||||
this.forTlsPremasterSecret = false;
|
||||
}
|
||||
init(opmode, key);
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected void engineInit(int opmode, Key key,
|
||||
AlgorithmParameters params, SecureRandom random)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
|
||||
if (params != null) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Parameters not supported");
|
||||
}
|
||||
init(opmode, key);
|
||||
}
|
||||
|
||||
// initialize this cipher
|
||||
private void init(int opmode, Key key) throws InvalidKeyException {
|
||||
|
||||
boolean encrypt;
|
||||
|
||||
switch (opmode) {
|
||||
case Cipher.ENCRYPT_MODE:
|
||||
case Cipher.WRAP_MODE:
|
||||
paddingLength = PAD_PKCS1_LENGTH;
|
||||
encrypt = true;
|
||||
break;
|
||||
case Cipher.DECRYPT_MODE:
|
||||
case Cipher.UNWRAP_MODE:
|
||||
paddingLength = 0; // reset
|
||||
encrypt = false;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidKeyException("Unknown mode: " + opmode);
|
||||
}
|
||||
|
||||
if (!(key instanceof CKey)) {
|
||||
if (key instanceof java.security.interfaces.RSAPublicKey) {
|
||||
java.security.interfaces.RSAPublicKey rsaKey =
|
||||
(java.security.interfaces.RSAPublicKey) key;
|
||||
|
||||
// Convert key to MSCAPI format
|
||||
|
||||
BigInteger modulus = rsaKey.getModulus();
|
||||
BigInteger exponent = rsaKey.getPublicExponent();
|
||||
|
||||
// Check against the local and global values to make sure
|
||||
// the sizes are ok. Round up to the nearest byte.
|
||||
RSAKeyFactory.checkKeyLengths(((modulus.bitLength() + 7) & ~7),
|
||||
exponent, -1, CKeyPairGenerator.RSA.KEY_SIZE_MAX);
|
||||
|
||||
byte[] modulusBytes = modulus.toByteArray();
|
||||
byte[] exponentBytes = exponent.toByteArray();
|
||||
|
||||
// Adjust key length due to sign bit
|
||||
int keyBitLength = (modulusBytes[0] == 0)
|
||||
? (modulusBytes.length - 1) * 8
|
||||
: modulusBytes.length * 8;
|
||||
|
||||
byte[] keyBlob = CSignature.RSA.generatePublicKeyBlob(
|
||||
keyBitLength, modulusBytes, exponentBytes);
|
||||
|
||||
try {
|
||||
key = CSignature.importPublicKey("RSA", keyBlob, keyBitLength);
|
||||
|
||||
} catch (KeyStoreException e) {
|
||||
throw new InvalidKeyException(e);
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new InvalidKeyException("Unsupported key type: " + key);
|
||||
}
|
||||
}
|
||||
|
||||
if (key instanceof PublicKey) {
|
||||
mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY;
|
||||
publicKey = (CKey)key;
|
||||
privateKey = null;
|
||||
outputSize = publicKey.length() / 8;
|
||||
} else if (key instanceof PrivateKey) {
|
||||
mode = encrypt ? MODE_SIGN : MODE_DECRYPT;
|
||||
privateKey = (CKey)key;
|
||||
publicKey = null;
|
||||
outputSize = privateKey.length() / 8;
|
||||
} else {
|
||||
throw new InvalidKeyException("Unknown key type: " + key);
|
||||
}
|
||||
|
||||
bufOfs = 0;
|
||||
buffer = new byte[outputSize];
|
||||
}
|
||||
|
||||
// internal update method
|
||||
private void update(byte[] in, int inOfs, int inLen) {
|
||||
if ((inLen == 0) || (in == null)) {
|
||||
return;
|
||||
}
|
||||
if (bufOfs + inLen > (buffer.length - paddingLength)) {
|
||||
bufOfs = buffer.length + 1;
|
||||
return;
|
||||
}
|
||||
System.arraycopy(in, inOfs, buffer, bufOfs, inLen);
|
||||
bufOfs += inLen;
|
||||
}
|
||||
|
||||
// internal doFinal() method. Here we perform the actual RSA operation
|
||||
private byte[] doFinal() throws IllegalBlockSizeException {
|
||||
if (bufOfs > buffer.length) {
|
||||
throw new IllegalBlockSizeException("Data must not be longer "
|
||||
+ "than " + (buffer.length - paddingLength) + " bytes");
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] data = buffer;
|
||||
switch (mode) {
|
||||
case MODE_SIGN:
|
||||
return encryptDecrypt(data, bufOfs,
|
||||
privateKey.getHCryptKey(), true);
|
||||
|
||||
case MODE_VERIFY:
|
||||
return encryptDecrypt(data, bufOfs,
|
||||
publicKey.getHCryptKey(), false);
|
||||
|
||||
case MODE_ENCRYPT:
|
||||
return encryptDecrypt(data, bufOfs,
|
||||
publicKey.getHCryptKey(), true);
|
||||
|
||||
case MODE_DECRYPT:
|
||||
return encryptDecrypt(data, bufOfs,
|
||||
privateKey.getHCryptKey(), false);
|
||||
|
||||
default:
|
||||
throw new AssertionError("Internal error");
|
||||
}
|
||||
|
||||
} catch (KeyException | BadPaddingException e) {
|
||||
throw new ProviderException(e);
|
||||
|
||||
} finally {
|
||||
bufOfs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
|
||||
update(in, inOfs, inLen);
|
||||
return B0;
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
|
||||
int outOfs) {
|
||||
update(in, inOfs, inLen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
|
||||
throws IllegalBlockSizeException {
|
||||
update(in, inOfs, inLen);
|
||||
return doFinal();
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
|
||||
int outOfs) throws ShortBufferException,
|
||||
IllegalBlockSizeException {
|
||||
if (outputSize > out.length - outOfs) {
|
||||
throw new ShortBufferException
|
||||
("Need " + outputSize + " bytes for output");
|
||||
}
|
||||
update(in, inOfs, inLen);
|
||||
byte[] result = doFinal();
|
||||
int n = result.length;
|
||||
System.arraycopy(result, 0, out, outOfs, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected byte[] engineWrap(Key key) throws InvalidKeyException,
|
||||
IllegalBlockSizeException {
|
||||
|
||||
byte[] encoded = key.getEncoded(); // TODO - unextractable key
|
||||
if ((encoded == null) || (encoded.length == 0)) {
|
||||
throw new InvalidKeyException("Could not obtain encoded key");
|
||||
}
|
||||
if (encoded.length > buffer.length) {
|
||||
throw new InvalidKeyException("Key is too long for wrapping");
|
||||
}
|
||||
update(encoded, 0, encoded.length);
|
||||
return doFinal();
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
@SuppressWarnings("deprecation")
|
||||
protected java.security.Key engineUnwrap(byte[] wrappedKey,
|
||||
String algorithm,
|
||||
int type) throws InvalidKeyException, NoSuchAlgorithmException {
|
||||
|
||||
if (wrappedKey.length > buffer.length) {
|
||||
throw new InvalidKeyException("Key is too long for unwrapping");
|
||||
}
|
||||
|
||||
boolean isTlsRsaPremasterSecret =
|
||||
algorithm.equals("TlsRsaPremasterSecret");
|
||||
Exception failover = null;
|
||||
byte[] encoded = null;
|
||||
|
||||
update(wrappedKey, 0, wrappedKey.length);
|
||||
try {
|
||||
encoded = doFinal();
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
// should not occur, handled with length check above
|
||||
throw new InvalidKeyException("Unwrapping failed", e);
|
||||
}
|
||||
|
||||
try {
|
||||
if (isTlsRsaPremasterSecret) {
|
||||
if (!forTlsPremasterSecret) {
|
||||
throw new IllegalStateException(
|
||||
"No TlsRsaPremasterSecretParameterSpec specified");
|
||||
}
|
||||
|
||||
// polish the TLS premaster secret
|
||||
encoded = KeyUtil.checkTlsPreMasterSecretKey(
|
||||
((TlsRsaPremasterSecretParameterSpec) spec).getClientVersion(),
|
||||
((TlsRsaPremasterSecretParameterSpec) spec).getServerVersion(),
|
||||
random, encoded, encoded == null);
|
||||
}
|
||||
|
||||
return constructKey(encoded, algorithm, type);
|
||||
} finally {
|
||||
if (encoded != null) {
|
||||
Arrays.fill(encoded, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// see JCE spec
|
||||
protected int engineGetKeySize(Key key) throws InvalidKeyException {
|
||||
|
||||
if (key instanceof CKey) {
|
||||
return ((CKey) key).length();
|
||||
|
||||
} else if (key instanceof RSAKey) {
|
||||
return ((RSAKey) key).getModulus().bitLength();
|
||||
|
||||
} else {
|
||||
throw new InvalidKeyException("Unsupported key type: " + key);
|
||||
}
|
||||
}
|
||||
|
||||
// Construct an X.509 encoded public key.
|
||||
private static PublicKey constructPublicKey(byte[] encodedKey,
|
||||
String encodedKeyAlgorithm)
|
||||
throws InvalidKeyException, NoSuchAlgorithmException {
|
||||
|
||||
try {
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm);
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
|
||||
|
||||
return keyFactory.generatePublic(keySpec);
|
||||
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
throw new NoSuchAlgorithmException("No installed provider " +
|
||||
"supports the " + encodedKeyAlgorithm + " algorithm", nsae);
|
||||
|
||||
} catch (InvalidKeySpecException ike) {
|
||||
throw new InvalidKeyException("Cannot construct public key", ike);
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a PKCS #8 encoded private key.
|
||||
private static PrivateKey constructPrivateKey(byte[] encodedKey,
|
||||
String encodedKeyAlgorithm)
|
||||
throws InvalidKeyException, NoSuchAlgorithmException {
|
||||
|
||||
try {
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm);
|
||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
|
||||
|
||||
return keyFactory.generatePrivate(keySpec);
|
||||
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
throw new NoSuchAlgorithmException("No installed provider " +
|
||||
"supports the " + encodedKeyAlgorithm + " algorithm", nsae);
|
||||
|
||||
} catch (InvalidKeySpecException ike) {
|
||||
throw new InvalidKeyException("Cannot construct private key", ike);
|
||||
}
|
||||
}
|
||||
|
||||
// Construct an encoded secret key.
|
||||
private static SecretKey constructSecretKey(byte[] encodedKey,
|
||||
String encodedKeyAlgorithm) {
|
||||
|
||||
return new SecretKeySpec(encodedKey, encodedKeyAlgorithm);
|
||||
}
|
||||
|
||||
private static Key constructKey(byte[] encodedKey,
|
||||
String encodedKeyAlgorithm,
|
||||
int keyType) throws InvalidKeyException, NoSuchAlgorithmException {
|
||||
|
||||
switch (keyType) {
|
||||
case Cipher.PUBLIC_KEY:
|
||||
return constructPublicKey(encodedKey, encodedKeyAlgorithm);
|
||||
case Cipher.PRIVATE_KEY:
|
||||
return constructPrivateKey(encodedKey, encodedKeyAlgorithm);
|
||||
case Cipher.SECRET_KEY:
|
||||
return constructSecretKey(encodedKey, encodedKeyAlgorithm);
|
||||
default:
|
||||
throw new InvalidKeyException("Unknown key type " + keyType);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypt/decrypt a data buffer using Microsoft Crypto API with HCRYPTKEY.
|
||||
* It expects and returns ciphertext data in big-endian form.
|
||||
*/
|
||||
private byte[] encryptDecrypt(byte[] data, int dataSize,
|
||||
long hCryptKey, boolean doEncrypt) throws KeyException, BadPaddingException {
|
||||
int[] returnStatus = new int[1];
|
||||
byte[] result= encryptDecrypt(returnStatus, data, dataSize, hCryptKey, doEncrypt);
|
||||
if ((returnStatus[0] == ERROR_INVALID_PARAMETER) || (returnStatus[0] == NTE_INVALID_PARAMETER)) {
|
||||
if (forTlsPremasterSecret) {
|
||||
result = null;
|
||||
} else {
|
||||
throw new BadPaddingException("Error " + returnStatus[0] + " returned by MSCAPI");
|
||||
}
|
||||
} else if (returnStatus[0] != 0) {
|
||||
throw new KeyException("Error " + returnStatus[0] + " returned by MSCAPI");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
private static native byte[] encryptDecrypt(int[] returnStatus, byte[] data, int dataSize,
|
||||
long key, boolean doEncrypt) throws KeyException;
|
||||
|
||||
}
|
||||
954
jdkSrc/jdk8/sun/security/mscapi/CSignature.java
Normal file
954
jdkSrc/jdk8/sun/security/mscapi/CSignature.java
Normal file
@@ -0,0 +1,954 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
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;
|
||||
import java.security.spec.MGF1ParameterSpec;
|
||||
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.
|
||||
*
|
||||
* Objects should be instantiated by calling Signature.getInstance() using the
|
||||
* following algorithm names:
|
||||
*
|
||||
* . "NONEwithRSA"
|
||||
* . "SHA1withRSA"
|
||||
* . "SHA256withRSA"
|
||||
* . "SHA384withRSA"
|
||||
* . "SHA512withRSA"
|
||||
* . "MD5withRSA"
|
||||
* . "MD2withRSA"
|
||||
* . "RSASSA-PSS"
|
||||
* . "SHA1withECDSA"
|
||||
* . "SHA224withECDSA"
|
||||
* . "SHA256withECDSA"
|
||||
* . "SHA384withECDSA"
|
||||
* . "SHA512withECDSA"
|
||||
*
|
||||
* NOTE: RSA keys must be at least 512 bits long.
|
||||
*
|
||||
* NOTE: NONEwithRSA must be supplied with a pre-computed message digest.
|
||||
* Only the following digest algorithms are supported: MD5, SHA-1,
|
||||
* SHA-256, SHA-384, SHA-512 and a special-purpose digest
|
||||
* algorithm which is a concatenation of SHA-1 and MD5 digests.
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Stanley Man-Kit Ho
|
||||
*/
|
||||
abstract class CSignature extends SignatureSpi {
|
||||
// private key algorithm name
|
||||
protected String keyAlgorithm;
|
||||
|
||||
// message digest implementation we use
|
||||
protected MessageDigest messageDigest;
|
||||
|
||||
// message digest name
|
||||
protected String messageDigestAlgorithm;
|
||||
|
||||
// flag indicating whether the digest has been reset
|
||||
protected boolean needsReset;
|
||||
|
||||
// the signing key
|
||||
protected CPrivateKey privateKey = null;
|
||||
|
||||
// the verification key
|
||||
protected CPublicKey publicKey = null;
|
||||
|
||||
/**
|
||||
* Constructs a new CSignature. Used by subclasses.
|
||||
*/
|
||||
CSignature(String keyName, String digestName) {
|
||||
|
||||
this.keyAlgorithm = keyName;
|
||||
if (digestName != null) {
|
||||
try {
|
||||
messageDigest = MessageDigest.getInstance(digestName);
|
||||
// Get the digest's canonical name
|
||||
messageDigestAlgorithm = messageDigest.getAlgorithm();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
} else {
|
||||
messageDigest = null;
|
||||
messageDigestAlgorithm = null;
|
||||
}
|
||||
needsReset = false;
|
||||
}
|
||||
|
||||
static class RSA extends CSignature {
|
||||
|
||||
public RSA(String digestAlgorithm) {
|
||||
super("RSA", digestAlgorithm);
|
||||
}
|
||||
|
||||
// initialize for signing. See JCA doc
|
||||
@Override
|
||||
protected void engineInitSign(PrivateKey key) throws InvalidKeyException {
|
||||
if (key == null) {
|
||||
throw new InvalidKeyException("Key cannot be null");
|
||||
}
|
||||
if ((key instanceof CPrivateKey) == false
|
||||
|| !key.getAlgorithm().equalsIgnoreCase("RSA")) {
|
||||
throw new InvalidKeyException("Key type not supported: "
|
||||
+ key.getClass() + " " + key.getAlgorithm());
|
||||
}
|
||||
privateKey = (CPrivateKey) key;
|
||||
|
||||
// Check against the local and global values to make sure
|
||||
// the sizes are ok. Round up to nearest byte.
|
||||
RSAKeyFactory.checkKeyLengths(((privateKey.length() + 7) & ~7),
|
||||
null, CKeyPairGenerator.RSA.KEY_SIZE_MIN,
|
||||
CKeyPairGenerator.RSA.KEY_SIZE_MAX);
|
||||
|
||||
this.publicKey = null;
|
||||
resetDigest();
|
||||
}
|
||||
|
||||
// initialize for signing. See JCA doc
|
||||
@Override
|
||||
protected void engineInitVerify(PublicKey key) throws InvalidKeyException {
|
||||
if (key == null) {
|
||||
throw new InvalidKeyException("Key cannot be null");
|
||||
}
|
||||
// This signature accepts only RSAPublicKey
|
||||
if ((key instanceof RSAPublicKey) == false) {
|
||||
throw new InvalidKeyException("Key type not supported: "
|
||||
+ key.getClass());
|
||||
}
|
||||
|
||||
|
||||
if ((key instanceof CPublicKey) == false) {
|
||||
|
||||
// convert key to MSCAPI format
|
||||
java.security.interfaces.RSAPublicKey rsaKey =
|
||||
(java.security.interfaces.RSAPublicKey) key;
|
||||
|
||||
BigInteger modulus = rsaKey.getModulus();
|
||||
BigInteger exponent = rsaKey.getPublicExponent();
|
||||
|
||||
// Check against the local and global values to make sure
|
||||
// the sizes are ok. Round up to the nearest byte.
|
||||
RSAKeyFactory.checkKeyLengths(((modulus.bitLength() + 7) & ~7),
|
||||
exponent, -1, CKeyPairGenerator.RSA.KEY_SIZE_MAX);
|
||||
|
||||
byte[] modulusBytes = modulus.toByteArray();
|
||||
byte[] exponentBytes = exponent.toByteArray();
|
||||
|
||||
// Adjust key length due to sign bit
|
||||
int keyBitLength = (modulusBytes[0] == 0)
|
||||
? (modulusBytes.length - 1) * 8
|
||||
: modulusBytes.length * 8;
|
||||
|
||||
byte[] keyBlob = generatePublicKeyBlob(
|
||||
keyBitLength, modulusBytes, exponentBytes);
|
||||
|
||||
try {
|
||||
publicKey = importPublicKey("RSA", keyBlob, keyBitLength);
|
||||
|
||||
} catch (KeyStoreException e) {
|
||||
throw new InvalidKeyException(e);
|
||||
}
|
||||
|
||||
} else {
|
||||
publicKey = (CPublicKey) key;
|
||||
}
|
||||
|
||||
this.privateKey = null;
|
||||
resetDigest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the signature bytes of all the data
|
||||
* updated so far.
|
||||
* The format of the signature depends on the underlying
|
||||
* signature scheme.
|
||||
*
|
||||
* @return the signature bytes of the signing operation's result.
|
||||
*
|
||||
* @exception SignatureException if the engine is not
|
||||
* initialized properly or if this signature algorithm is unable to
|
||||
* process the input data provided.
|
||||
*/
|
||||
@Override
|
||||
protected byte[] engineSign() throws SignatureException {
|
||||
|
||||
byte[] hash = getDigestValue();
|
||||
|
||||
if (privateKey.getHCryptKey() == 0) {
|
||||
return signCngHash(1, hash, hash.length,
|
||||
0,
|
||||
this instanceof NONEwithRSA ? null : messageDigestAlgorithm,
|
||||
privateKey.getHCryptProvider(), 0);
|
||||
} else {
|
||||
// Omit the hash OID when generating a NONEwithRSA signature
|
||||
boolean noHashOID = this instanceof NONEwithRSA;
|
||||
// Sign hash using MS Crypto APIs
|
||||
byte[] result = signHash(noHashOID, hash, hash.length,
|
||||
messageDigestAlgorithm, privateKey.getHCryptProvider(),
|
||||
privateKey.getHCryptKey());
|
||||
|
||||
// Convert signature array from little endian to big endian
|
||||
return convertEndianArray(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the passed-in signature.
|
||||
*
|
||||
* @param sigBytes the signature bytes to be verified.
|
||||
*
|
||||
* @return true if the signature was verified, false if not.
|
||||
*
|
||||
* @exception SignatureException if the engine is not
|
||||
* initialized properly, the passed-in signature is improperly
|
||||
* encoded or of the wrong type, if this signature algorithm is unable to
|
||||
* process the input data provided, etc.
|
||||
*/
|
||||
@Override
|
||||
protected boolean engineVerify(byte[] sigBytes)
|
||||
throws SignatureException {
|
||||
byte[] hash = getDigestValue();
|
||||
|
||||
if (publicKey.getHCryptKey() == 0) {
|
||||
return verifyCngSignedHash(
|
||||
1, hash, hash.length,
|
||||
sigBytes, sigBytes.length,
|
||||
0,
|
||||
messageDigestAlgorithm,
|
||||
publicKey.getHCryptProvider(),
|
||||
0);
|
||||
} else {
|
||||
return verifySignedHash(hash, hash.length,
|
||||
messageDigestAlgorithm, convertEndianArray(sigBytes),
|
||||
sigBytes.length, publicKey.getHCryptProvider(),
|
||||
publicKey.getHCryptKey());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a public-key BLOB from a key's components.
|
||||
*/
|
||||
// used by CRSACipher
|
||||
static native byte[] generatePublicKeyBlob(
|
||||
int keyBitLength, byte[] modulus, byte[] publicExponent)
|
||||
throws InvalidKeyException;
|
||||
|
||||
}
|
||||
|
||||
// Nested class for NONEwithRSA signatures
|
||||
public static final class NONEwithRSA extends RSA {
|
||||
|
||||
// the longest supported digest is 512 bits (SHA-512)
|
||||
private static final int RAW_RSA_MAX = 64;
|
||||
|
||||
private final byte[] precomputedDigest;
|
||||
private int offset = 0;
|
||||
|
||||
public NONEwithRSA() {
|
||||
super(null);
|
||||
precomputedDigest = new byte[RAW_RSA_MAX];
|
||||
}
|
||||
|
||||
// Stores the precomputed message digest value.
|
||||
@Override
|
||||
protected void engineUpdate(byte b) throws SignatureException {
|
||||
if (offset >= precomputedDigest.length) {
|
||||
offset = RAW_RSA_MAX + 1;
|
||||
return;
|
||||
}
|
||||
precomputedDigest[offset++] = b;
|
||||
}
|
||||
|
||||
// Stores the precomputed message digest value.
|
||||
@Override
|
||||
protected void engineUpdate(byte[] b, int off, int len)
|
||||
throws SignatureException {
|
||||
if (len > (precomputedDigest.length - offset)) {
|
||||
offset = RAW_RSA_MAX + 1;
|
||||
return;
|
||||
}
|
||||
System.arraycopy(b, off, precomputedDigest, offset, len);
|
||||
offset += len;
|
||||
}
|
||||
|
||||
// Stores the precomputed message digest value.
|
||||
@Override
|
||||
protected void engineUpdate(ByteBuffer byteBuffer) {
|
||||
int len = byteBuffer.remaining();
|
||||
if (len <= 0) {
|
||||
return;
|
||||
}
|
||||
if (len > (precomputedDigest.length - offset)) {
|
||||
offset = RAW_RSA_MAX + 1;
|
||||
return;
|
||||
}
|
||||
byteBuffer.get(precomputedDigest, offset, len);
|
||||
offset += len;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetDigest(){
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
// Returns the precomputed message digest value.
|
||||
@Override
|
||||
protected byte[] getDigestValue() throws SignatureException {
|
||||
if (offset > RAW_RSA_MAX) {
|
||||
throw new SignatureException("Message digest is too long");
|
||||
}
|
||||
|
||||
// Determine the digest algorithm from the digest length
|
||||
if (offset == 20) {
|
||||
setDigestName("SHA1");
|
||||
} else if (offset == 36) {
|
||||
setDigestName("SHA1+MD5");
|
||||
} else if (offset == 32) {
|
||||
setDigestName("SHA-256");
|
||||
} else if (offset == 48) {
|
||||
setDigestName("SHA-384");
|
||||
} else if (offset == 64) {
|
||||
setDigestName("SHA-512");
|
||||
} else if (offset == 16) {
|
||||
setDigestName("MD5");
|
||||
} else {
|
||||
throw new SignatureException(
|
||||
"Message digest length is not supported");
|
||||
}
|
||||
|
||||
byte[] result = new byte[offset];
|
||||
System.arraycopy(precomputedDigest, 0, result, 0, offset);
|
||||
offset = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SHA1withRSA extends RSA {
|
||||
public SHA1withRSA() {
|
||||
super("SHA1");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SHA256withRSA extends RSA {
|
||||
public SHA256withRSA() {
|
||||
super("SHA-256");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SHA384withRSA extends RSA {
|
||||
public SHA384withRSA() {
|
||||
super("SHA-384");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SHA512withRSA extends RSA {
|
||||
public SHA512withRSA() {
|
||||
super("SHA-512");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class MD5withRSA extends RSA {
|
||||
public MD5withRSA() {
|
||||
super("MD5");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class MD2withRSA extends RSA {
|
||||
public MD2withRSA() {
|
||||
super("MD2");
|
||||
}
|
||||
}
|
||||
|
||||
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 == null) {
|
||||
throw new InvalidKeyException("Key cannot be null");
|
||||
}
|
||||
if ((key instanceof CPrivateKey) == false
|
||||
|| !key.getAlgorithm().equalsIgnoreCase("EC")) {
|
||||
throw new InvalidKeyException("Key type not supported: "
|
||||
+ key.getClass() + " " + key.getAlgorithm());
|
||||
}
|
||||
privateKey = (CPrivateKey) key;
|
||||
|
||||
this.publicKey = null;
|
||||
resetDigest();
|
||||
}
|
||||
|
||||
// initialize for signing. See JCA doc
|
||||
@Override
|
||||
protected void engineInitVerify(PublicKey key) throws InvalidKeyException {
|
||||
if (key == null) {
|
||||
throw new InvalidKeyException("Key cannot be null");
|
||||
}
|
||||
// This signature accepts only ECPublicKey
|
||||
if ((key instanceof ECPublicKey) == false) {
|
||||
throw new InvalidKeyException("Key type not supported: "
|
||||
+ key.getClass());
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// Workaround: Cannot import raw public key to CNG. This signature
|
||||
// will be used for verification if key is not from MSCAPI.
|
||||
private Signature fallbackSignature;
|
||||
|
||||
public PSS() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineInitSign(PrivateKey key) throws InvalidKeyException {
|
||||
super.engineInitSign(key);
|
||||
fallbackSignature = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineInitVerify(PublicKey key) throws InvalidKeyException {
|
||||
if (key == null) {
|
||||
throw new InvalidKeyException("Key cannot be null");
|
||||
}
|
||||
// This signature accepts only RSAPublicKey
|
||||
if ((key instanceof java.security.interfaces.RSAPublicKey) == false) {
|
||||
throw new InvalidKeyException("Key type not supported: "
|
||||
+ key.getClass());
|
||||
}
|
||||
|
||||
this.privateKey = null;
|
||||
|
||||
if (key instanceof CPublicKey) {
|
||||
fallbackSignature = null;
|
||||
publicKey = (CPublicKey) key;
|
||||
} else {
|
||||
if (fallbackSignature == null) {
|
||||
try {
|
||||
fallbackSignature = Signature.getInstance(
|
||||
"RSASSA-PSS", "SunRsaSign");
|
||||
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
|
||||
throw new InvalidKeyException("Invalid key", e);
|
||||
}
|
||||
}
|
||||
fallbackSignature.initVerify(key);
|
||||
if (pssParams != null) {
|
||||
try {
|
||||
fallbackSignature.setParameter(pssParams);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
throw new InvalidKeyException("Invalid params", e);
|
||||
}
|
||||
}
|
||||
publicKey = null;
|
||||
}
|
||||
resetDigest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte b) throws SignatureException {
|
||||
ensureInit();
|
||||
if (fallbackSignature != null) {
|
||||
fallbackSignature.update(b);
|
||||
} else {
|
||||
messageDigest.update(b);
|
||||
}
|
||||
needsReset = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(byte[] b, int off, int len) throws SignatureException {
|
||||
ensureInit();
|
||||
if (fallbackSignature != null) {
|
||||
fallbackSignature.update(b, off, len);
|
||||
} else {
|
||||
messageDigest.update(b, off, len);
|
||||
}
|
||||
needsReset = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineUpdate(ByteBuffer input) {
|
||||
try {
|
||||
ensureInit();
|
||||
} catch (SignatureException se) {
|
||||
// hack for working around API bug
|
||||
throw new RuntimeException(se.getMessage());
|
||||
}
|
||||
if (fallbackSignature != null) {
|
||||
try {
|
||||
fallbackSignature.update(input);
|
||||
} catch (SignatureException se) {
|
||||
// hack for working around API bug
|
||||
throw new RuntimeException(se.getMessage());
|
||||
}
|
||||
} else {
|
||||
messageDigest.update(input);
|
||||
}
|
||||
needsReset = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineSign() throws SignatureException {
|
||||
ensureInit();
|
||||
byte[] hash = getDigestValue();
|
||||
return signCngHash(2, hash, hash.length,
|
||||
pssParams.getSaltLength(),
|
||||
((MGF1ParameterSpec)
|
||||
pssParams.getMGFParameters()).getDigestAlgorithm(),
|
||||
privateKey.getHCryptProvider(), privateKey.getHCryptKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
|
||||
ensureInit();
|
||||
if (fallbackSignature != null) {
|
||||
needsReset = false;
|
||||
return fallbackSignature.verify(sigBytes);
|
||||
} else {
|
||||
byte[] hash = getDigestValue();
|
||||
return verifyCngSignedHash(
|
||||
2, hash, hash.length,
|
||||
sigBytes, sigBytes.length,
|
||||
pssParams.getSaltLength(),
|
||||
((MGF1ParameterSpec)
|
||||
pssParams.getMGFParameters()).getDigestAlgorithm(),
|
||||
publicKey.getHCryptProvider(),
|
||||
publicKey.getHCryptKey()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineSetParameter(AlgorithmParameterSpec params)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
if (needsReset) {
|
||||
throw new ProviderException
|
||||
("Cannot set parameters during operations");
|
||||
}
|
||||
this.pssParams = validateSigParams(params);
|
||||
if (fallbackSignature != null) {
|
||||
fallbackSignature.setParameter(params);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AlgorithmParameters engineGetParameters() {
|
||||
AlgorithmParameters ap = null;
|
||||
if (this.pssParams != null) {
|
||||
try {
|
||||
ap = AlgorithmParameters.getInstance("RSASSA-PSS");
|
||||
ap.init(this.pssParams);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
throw new ProviderException(gse.getMessage());
|
||||
}
|
||||
}
|
||||
return ap;
|
||||
}
|
||||
|
||||
private void ensureInit() throws SignatureException {
|
||||
if (this.privateKey == null && this.publicKey == null
|
||||
&& fallbackSignature == null) {
|
||||
throw new SignatureException("Missing key");
|
||||
}
|
||||
if (this.pssParams == null) {
|
||||
// Parameters are required for signature verification
|
||||
throw new SignatureException
|
||||
("Parameters required for RSASSA-PSS signatures");
|
||||
}
|
||||
if (fallbackSignature == null && messageDigest == null) {
|
||||
// This could happen if initVerify(softKey), setParameter(),
|
||||
// and initSign() were called. No messageDigest. Create it.
|
||||
try {
|
||||
messageDigest = MessageDigest
|
||||
.getInstance(pssParams.getDigestAlgorithm());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new SignatureException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the specified Signature PSS parameters.
|
||||
*/
|
||||
private PSSParameterSpec validateSigParams(AlgorithmParameterSpec p)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
|
||||
if (p == null) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Parameters cannot be null");
|
||||
}
|
||||
|
||||
if (!(p instanceof PSSParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("parameters must be type PSSParameterSpec");
|
||||
}
|
||||
|
||||
// no need to validate again if same as current signature parameters
|
||||
PSSParameterSpec params = (PSSParameterSpec) p;
|
||||
if (params == this.pssParams) return params;
|
||||
|
||||
// now sanity check the parameter values
|
||||
if (!(params.getMGFAlgorithm().equalsIgnoreCase("MGF1"))) {
|
||||
throw new InvalidAlgorithmParameterException("Only supports MGF1");
|
||||
|
||||
}
|
||||
|
||||
if (params.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Only supports TrailerFieldBC(1)");
|
||||
}
|
||||
|
||||
AlgorithmParameterSpec algSpec = params.getMGFParameters();
|
||||
if (!(algSpec instanceof MGF1ParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Only support MGF1ParameterSpec");
|
||||
}
|
||||
|
||||
MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)algSpec;
|
||||
|
||||
String msgHashAlg = params.getDigestAlgorithm()
|
||||
.toLowerCase(Locale.ROOT).replaceAll("-", "");
|
||||
if (msgHashAlg.equals("sha")) {
|
||||
msgHashAlg = "sha1";
|
||||
}
|
||||
String mgf1HashAlg = mgfSpec.getDigestAlgorithm()
|
||||
.toLowerCase(Locale.ROOT).replaceAll("-", "");
|
||||
if (mgf1HashAlg.equals("sha")) {
|
||||
mgf1HashAlg = "sha1";
|
||||
}
|
||||
|
||||
if (!mgf1HashAlg.equals(msgHashAlg)) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("MGF1 hash must be the same as message hash");
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign hash using CNG API with HCRYPTKEY.
|
||||
* @param type 0 no padding, 1, pkcs1, 2, pss
|
||||
*/
|
||||
native static byte[] signCngHash(
|
||||
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.
|
||||
* @param type 0 no padding, 1, pkcs1, 2, pss
|
||||
*/
|
||||
private native static boolean verifyCngSignedHash(
|
||||
int type, byte[] hash, int hashSize,
|
||||
byte[] signature, int signatureSize,
|
||||
int saltLength, String hashAlgorithm,
|
||||
long hCryptProv, long hKey) throws SignatureException;
|
||||
|
||||
/**
|
||||
* Resets the message digest if needed.
|
||||
*/
|
||||
protected void resetDigest() {
|
||||
if (needsReset) {
|
||||
if (messageDigest != null) {
|
||||
messageDigest.reset();
|
||||
}
|
||||
needsReset = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] getDigestValue() throws SignatureException {
|
||||
needsReset = false;
|
||||
return messageDigest.digest();
|
||||
}
|
||||
|
||||
protected void setDigestName(String name) {
|
||||
messageDigestAlgorithm = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the data to be signed or verified
|
||||
* using the specified byte.
|
||||
*
|
||||
* @param b the byte to use for the update.
|
||||
*
|
||||
* @exception SignatureException if the engine is not initialized
|
||||
* properly.
|
||||
*/
|
||||
@Override
|
||||
protected void engineUpdate(byte b) throws SignatureException {
|
||||
messageDigest.update(b);
|
||||
needsReset = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the data to be signed or verified, using the
|
||||
* specified array of bytes, starting at the specified offset.
|
||||
*
|
||||
* @param b the array of bytes
|
||||
* @param off the offset to start from in the array of bytes
|
||||
* @param len the number of bytes to use, starting at offset
|
||||
*
|
||||
* @exception SignatureException if the engine is not initialized
|
||||
* properly
|
||||
*/
|
||||
@Override
|
||||
protected void engineUpdate(byte[] b, int off, int len)
|
||||
throws SignatureException {
|
||||
messageDigest.update(b, off, len);
|
||||
needsReset = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the data to be signed or verified, using the
|
||||
* specified ByteBuffer.
|
||||
*
|
||||
* @param input the ByteBuffer
|
||||
*/
|
||||
@Override
|
||||
protected void engineUpdate(ByteBuffer input) {
|
||||
messageDigest.update(input);
|
||||
needsReset = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert array from big endian to little endian, or vice versa.
|
||||
*/
|
||||
private static byte[] convertEndianArray(byte[] byteArray) {
|
||||
if (byteArray == null || byteArray.length == 0)
|
||||
return byteArray;
|
||||
|
||||
byte [] retval = new byte[byteArray.length];
|
||||
|
||||
// make it big endian
|
||||
for (int i=0;i < byteArray.length;i++)
|
||||
retval[i] = byteArray[byteArray.length - i - 1];
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign hash using Microsoft Crypto API with HCRYPTKEY.
|
||||
* The returned data is in little-endian.
|
||||
*/
|
||||
private native static byte[] signHash(boolean noHashOID, byte[] hash,
|
||||
int hashSize, String hashAlgorithm, long hCryptProv, long hCryptKey)
|
||||
throws SignatureException;
|
||||
|
||||
/**
|
||||
* Verify a signed hash using Microsoft Crypto API with HCRYPTKEY.
|
||||
*/
|
||||
private native static boolean verifySignedHash(byte[] hash, int hashSize,
|
||||
String hashAlgorithm, byte[] signature, int signatureSize,
|
||||
long hCryptProv, long hCryptKey) throws SignatureException;
|
||||
|
||||
/**
|
||||
* Sets the specified algorithm parameter to the specified
|
||||
* value. This method supplies a general-purpose mechanism through
|
||||
* which it is possible to set the various parameters of this object.
|
||||
* A parameter may be any settable parameter for the algorithm, such as
|
||||
* a parameter size, or a source of random bits for signature generation
|
||||
* (if appropriate), or an indication of whether or not to perform
|
||||
* a specific but optional computation. A uniform algorithm-specific
|
||||
* naming scheme for each parameter is desirable but left unspecified
|
||||
* at this time.
|
||||
*
|
||||
* @param param the string identifier of the parameter.
|
||||
*
|
||||
* @param value the parameter value.
|
||||
*
|
||||
* @exception InvalidParameterException if <code>param</code> is an
|
||||
* invalid parameter for this signature algorithm engine,
|
||||
* the parameter is already set
|
||||
* and cannot be set again, a security exception occurs, and so on.
|
||||
*
|
||||
* @deprecated Replaced by {@link
|
||||
* #engineSetParameter(java.security.spec.AlgorithmParameterSpec)
|
||||
* engineSetParameter}.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
protected void engineSetParameter(String param, Object value)
|
||||
throws InvalidParameterException {
|
||||
throw new InvalidParameterException("Parameter not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this signature engine with the specified algorithm parameter.
|
||||
*
|
||||
* @param params the parameters
|
||||
*
|
||||
* @exception InvalidAlgorithmParameterException if the given
|
||||
* parameter is invalid
|
||||
*/
|
||||
@Override
|
||||
protected void engineSetParameter(AlgorithmParameterSpec params)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
if (params != null) {
|
||||
throw new InvalidAlgorithmParameterException("No parameter accepted");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the specified algorithm parameter.
|
||||
* This method supplies a general-purpose mechanism through which it
|
||||
* is possible to get the various parameters of this object. A parameter
|
||||
* may be any settable parameter for the algorithm, such as a parameter
|
||||
* size, or a source of random bits for signature generation (if
|
||||
* appropriate), or an indication of whether or not to perform a
|
||||
* specific but optional computation. A uniform algorithm-specific
|
||||
* naming scheme for each parameter is desirable but left unspecified
|
||||
* at this time.
|
||||
*
|
||||
* @param param the string name of the parameter.
|
||||
*
|
||||
* @return the object that represents the parameter value, or null if
|
||||
* there is none.
|
||||
*
|
||||
* @exception InvalidParameterException if <code>param</code> is an
|
||||
* invalid parameter for this engine, or another exception occurs while
|
||||
* trying to get this parameter.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
protected Object engineGetParameter(String param)
|
||||
throws InvalidParameterException {
|
||||
throw new InvalidParameterException("Parameter not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the algorithm parameter from this signature engine.
|
||||
*
|
||||
* @return the parameter, or null if no parameter is used.
|
||||
*/
|
||||
@Override
|
||||
protected AlgorithmParameters engineGetParameters() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a public-key BLOB.
|
||||
*/
|
||||
// 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;
|
||||
}
|
||||
99
jdkSrc/jdk8/sun/security/mscapi/PRNG.java
Normal file
99
jdkSrc/jdk8/sun/security/mscapi/PRNG.java
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2013, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.mscapi;
|
||||
|
||||
import java.security.ProviderException;
|
||||
import java.security.SecureRandomSpi;
|
||||
|
||||
/**
|
||||
* Native PRNG implementation for Windows using the Microsoft Crypto API.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public final class PRNG extends SecureRandomSpi
|
||||
implements java.io.Serializable {
|
||||
|
||||
private static final long serialVersionUID = 4129268715132691532L;
|
||||
|
||||
/*
|
||||
* The CryptGenRandom function fills a buffer with cryptographically random
|
||||
* bytes.
|
||||
*/
|
||||
private static native byte[] generateSeed(int length, byte[] seed);
|
||||
|
||||
/**
|
||||
* Creates a random number generator.
|
||||
*/
|
||||
public PRNG() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reseeds this random object. The given seed supplements, rather than
|
||||
* replaces, the existing seed. Thus, repeated calls are guaranteed
|
||||
* never to reduce randomness.
|
||||
*
|
||||
* @param seed the seed.
|
||||
*/
|
||||
@Override
|
||||
protected void engineSetSeed(byte[] seed) {
|
||||
if (seed != null) {
|
||||
generateSeed(-1, seed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a user-specified number of random bytes.
|
||||
*
|
||||
* @param bytes the array to be filled in with random bytes.
|
||||
*/
|
||||
@Override
|
||||
protected void engineNextBytes(byte[] bytes) {
|
||||
if (bytes != null) {
|
||||
if (generateSeed(0, bytes) == null) {
|
||||
throw new ProviderException("Error generating random bytes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given number of seed bytes. This call may be used to
|
||||
* seed other random number generators.
|
||||
*
|
||||
* @param numBytes the number of seed bytes to generate.
|
||||
*
|
||||
* @return the seed bytes.
|
||||
*/
|
||||
@Override
|
||||
protected byte[] engineGenerateSeed(int numBytes) {
|
||||
byte[] seed = generateSeed(numBytes, null);
|
||||
|
||||
if (seed == null) {
|
||||
throw new ProviderException("Error generating seed bytes");
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
185
jdkSrc/jdk8/sun/security/mscapi/SunMSCAPI.java
Normal file
185
jdkSrc/jdk8/sun/security/mscapi/SunMSCAPI.java
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2020, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.mscapi;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.Provider;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import sun.security.action.PutAllAction;
|
||||
|
||||
|
||||
/**
|
||||
* A Cryptographic Service Provider for the Microsoft Crypto API.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public final class SunMSCAPI extends Provider {
|
||||
|
||||
private static final long serialVersionUID = 8622598936488630849L; //TODO
|
||||
|
||||
private static final String INFO = "Sun's Microsoft Crypto API provider";
|
||||
|
||||
static {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
System.loadLibrary("sunmscapi");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public SunMSCAPI() {
|
||||
super("SunMSCAPI", 1.8d, INFO);
|
||||
|
||||
// if there is no security manager installed, put directly into
|
||||
// the provider. Otherwise, create a temporary map and use a
|
||||
// doPrivileged() call at the end to transfer the contents
|
||||
final Map<Object, Object> map =
|
||||
(System.getSecurityManager() == null)
|
||||
? this : new HashMap<Object, Object>();
|
||||
|
||||
/*
|
||||
* Secure random
|
||||
*/
|
||||
map.put("SecureRandom.Windows-PRNG", "sun.security.mscapi.PRNG");
|
||||
|
||||
/*
|
||||
* Key store
|
||||
*/
|
||||
map.put("KeyStore.Windows-MY", "sun.security.mscapi.CKeyStore$MY");
|
||||
map.put("KeyStore.Windows-ROOT", "sun.security.mscapi.CKeyStore$ROOT");
|
||||
|
||||
/*
|
||||
* Signature engines
|
||||
*/
|
||||
// NONEwithRSA must be supplied with a pre-computed message digest.
|
||||
// Only the following digest algorithms are supported: MD5, SHA-1,
|
||||
// SHA-256, SHA-384, SHA-512 and a special-purpose digest
|
||||
// algorithm which is a concatenation of SHA-1 and MD5 digests.
|
||||
map.put("Signature.NONEwithRSA",
|
||||
"sun.security.mscapi.CSignature$NONEwithRSA");
|
||||
map.put("Signature.SHA1withRSA",
|
||||
"sun.security.mscapi.CSignature$SHA1withRSA");
|
||||
map.put("Signature.SHA256withRSA",
|
||||
"sun.security.mscapi.CSignature$SHA256withRSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA");
|
||||
map.put("Signature.SHA384withRSA",
|
||||
"sun.security.mscapi.CSignature$SHA384withRSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.12", "SHA384withRSA");
|
||||
map.put("Signature.SHA512withRSA",
|
||||
"sun.security.mscapi.CSignature$SHA512withRSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.13", "SHA512withRSA");
|
||||
|
||||
map.put("Signature.MD5withRSA",
|
||||
"sun.security.mscapi.CSignature$MD5withRSA");
|
||||
map.put("Signature.MD2withRSA",
|
||||
"sun.security.mscapi.CSignature$MD2withRSA");
|
||||
|
||||
map.put("Signature.RSASSA-PSS",
|
||||
"sun.security.mscapi.CSignature$PSS");
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.10", "RSASSA-PSS");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.10", "RSASSA-PSS");
|
||||
|
||||
map.put("Signature.SHA1withECDSA",
|
||||
"sun.security.mscapi.CSignature$SHA1withECDSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.10045.4.1", "SHA1withECDSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.1", "SHA1withECDSA");
|
||||
map.put("Signature.SHA224withECDSA",
|
||||
"sun.security.mscapi.CSignature$SHA224withECDSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.10045.4.3.1", "SHA224withECDSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.1", "SHA224withECDSA");
|
||||
map.put("Signature.SHA256withECDSA",
|
||||
"sun.security.mscapi.CSignature$SHA256withECDSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.10045.4.3.2", "SHA256withECDSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.2", "SHA256withECDSA");
|
||||
map.put("Signature.SHA384withECDSA",
|
||||
"sun.security.mscapi.CSignature$SHA384withECDSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.10045.4.3.3", "SHA384withECDSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.3", "SHA384withECDSA");
|
||||
map.put("Signature.SHA512withECDSA",
|
||||
"sun.security.mscapi.CSignature$SHA512withECDSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.10045.4.3.4", "SHA512withECDSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.10045.4.3.4", "SHA512withECDSA");
|
||||
|
||||
// supported key classes
|
||||
map.put("Signature.NONEwithRSA SupportedKeyClasses",
|
||||
"sun.security.mscapi.CKey");
|
||||
map.put("Signature.SHA1withRSA SupportedKeyClasses",
|
||||
"sun.security.mscapi.CKey");
|
||||
map.put("Signature.SHA256withRSA SupportedKeyClasses",
|
||||
"sun.security.mscapi.CKey");
|
||||
map.put("Signature.SHA384withRSA SupportedKeyClasses",
|
||||
"sun.security.mscapi.CKey");
|
||||
map.put("Signature.SHA512withRSA SupportedKeyClasses",
|
||||
"sun.security.mscapi.CKey");
|
||||
map.put("Signature.MD5withRSA SupportedKeyClasses",
|
||||
"sun.security.mscapi.CKey");
|
||||
map.put("Signature.MD2withRSA SupportedKeyClasses",
|
||||
"sun.security.mscapi.CKey");
|
||||
|
||||
map.put("Signature.RSASSA-PSS SupportedKeyClasses",
|
||||
"sun.security.mscapi.CKey");
|
||||
|
||||
map.put("Signature.SHA1withECDSA SupportedKeyClasses",
|
||||
"sun.security.mscapi.CKey");
|
||||
map.put("Signature.SHA224withECDSA SupportedKeyClasses",
|
||||
"sun.security.mscapi.CKey");
|
||||
map.put("Signature.SHA256withECDSA SupportedKeyClasses",
|
||||
"sun.security.mscapi.CKey");
|
||||
map.put("Signature.SHA384withECDSA SupportedKeyClasses",
|
||||
"sun.security.mscapi.CKey");
|
||||
map.put("Signature.SHA512withECDSA SupportedKeyClasses",
|
||||
"sun.security.mscapi.CKey");
|
||||
|
||||
/*
|
||||
* Key Pair Generator engines
|
||||
*/
|
||||
map.put("KeyPairGenerator.RSA",
|
||||
"sun.security.mscapi.CKeyPairGenerator$RSA");
|
||||
map.put("KeyPairGenerator.RSA KeySize", "1024");
|
||||
|
||||
/*
|
||||
* Cipher engines
|
||||
*/
|
||||
map.put("Cipher.RSA", "sun.security.mscapi.CRSACipher");
|
||||
map.put("Cipher.RSA/ECB/PKCS1Padding",
|
||||
"sun.security.mscapi.CRSACipher");
|
||||
map.put("Cipher.RSA SupportedModes", "ECB");
|
||||
map.put("Cipher.RSA SupportedPaddings", "PKCS1PADDING");
|
||||
map.put("Cipher.RSA SupportedKeyClasses", "sun.security.mscapi.CKey");
|
||||
|
||||
if (map != this) {
|
||||
AccessController.doPrivileged(new PutAllAction(this, map));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user