Java security - MSCAPI provider: How to use without password popup? - java

I've managed to use Sun's MSCAPI provider in my application. The problem I'm having now is that it always pops up a window, asking for a password, even though I've provided it in the code. This is a problem, because I need the cryptography functionality in a webservice.
Here's the code I have now:
String alias = "Alias to my PK";
char[] pass = "MyPassword".toCharArray();
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, pass);
Provider p = ks.getProvider();
Signature sig = Signature.getInstance("SHA1withRSA",p);
PrivateKey key = (PrivateKey) ks.getKey(alias, pass)
sig.initSign(key);
sig.update("Testing".getBytes());
sig.sign();
This is working great, but I get a popup asking for the password when the last line is run. How do I prevent that?

The MSCAPI provider does not support providing the password to CAPI:
A compatibility mode is supported for applications that assume a password must be supplied. It permits (but ignores) a non-null password. The mode is enabled by default. (1)
To set the password through CAPI, you must call CryptSetKeyParam with the undocumented KP_KEYEXCHANGE_PIN or KP_SIGNATURE_PIN and hope your underlying hardware token provider supports it. (They are not completely undocumented - the documentation for Windows CE and Windows Mobile mention them (2) and they are included in the header files).

My guess is that Windows is popping up the pop up.
Import your key again using the Certificate Import Wizard, but make sure that you don't check the following option on the "Password" screen.
[_] Enable strong private key protection. You will be prompted every time the private key is used by an application if you enable this option.

I resolved this problem setting the provider as follow:
signeData = gen.generate(content, ks.getProvider());
Where
ks is a KeyStore and
genis a CMSSignedDataGenerator

Related

How to check whether Android phone supports TEE?

I have read this two posts: One and Two, but I still have question.
I use KeyStore (Android 9) to generate an AES key, and use isInsideSecureHardware() method to check whether the key isInsideSecureHardware. I got return False. Sample code can be found here, and here.
public boolean isInsideSecureHardware ()
Returns true if the key resides inside secure hardware (e.g., Trusted Execution Environment (TEE) or Secure Element (SE)). Key material of such keys is available in plaintext only inside the secure hardware and is not exposed outside of it.
Thus, I want to further confirm whether my phone device (Huawei P20) supports TEE.
Question:
If the phone supports TEE, the key generated by KeyStore will be store into TEE automatically? Do I Need any manually configuration in Java? I heard that keys will be automatically stored in TEE, as long as you use KeyStore.getInstance(), KeyGenerator
.getInstance(algorithm, KeyStore Name). But I am not sure this is True or Not?
If the answer of Q1 is "Need manually configuration", it becomes the reason of isInsideSecureHardware() returns False, right? If the answer of Q1 is "automatically", ignore Q2.
Any method to directly check whether the phone supports TEE, in Java?
#JensV is correct: if you set setIsStrongBoxBacked on the keyGenParameterSpecBuilder, key generation will fail with a StrongBoxUnavailableException if StrongBox is not supported. However, the intermediate case - where there is a TEE (i.e. keys are generated and used within secure HW), but no support for StrongBox - is more tricky to discern.
In general, the way to go is to actually generate a key on the device, and then perform HW key attestation on it at the server - consulting the signed key properties to examine the exact degree of HW backing:
generate a nonce (random byte string) ON The SERVER, pass it to the device
generate a key on the device, requesting HW attestation by calling setAttestationChallenge on the KeyGenParameterSpec builder and passing in the nonce you get from the server (DO NOT USE A NONCE PRODUCED ON THE DEVICE)
request the attestation chain for the key from the Android Key Store
pass the attestation data (cert chain) to your server
verify the attestation (signature) chain on your server
confirm that the root cert matches a published Google root cert
confirm that no cert in the chain hasn been revoked (check against CRL # https://android.googleapis.com/attestation/status)
examine the properties of the Google Key Attestation extension (OID 1.3.6.1.4.1.11129.2.1.17) of the leaf cert
confirm the nonce matches (attestationChallenge)
consult the attestationSecurityLevel of KeyDescription
SecurityLevel ::= ENUMERATED {
Software (0),
TrustedEnvironment (1),
StrongBox (2),
}
TrustedEnvironment and StrongBox both correspond to hardware-backed keys and crypto operations.
From the Android keystore system docs:
Supported devices running Android 9 (API level 28) or higher installed can have a StrongBox Keymaster, an implementation of the Keymaster HAL that resides in a hardware security module. The module contains the following:
[...]
* Secure storage.
[...]
When checking keys stored in the StrongBox Keymaster, the system corroborates a key's integrity with the Trusted Execution Environment (TEE).
[...]
When generating or importing keys using the KeyStore class, you indicate a preference for storing the key in the StrongBox Keymaster by passing true to the setIsStrongBoxBacked() method.
In my understanding that means when you generate a Key and call keyGenParameterSpecBuilder.setIsStrongBoxBacked(true) for the key configuration you can ensure that it's backed by a TEE. If there is no TEE available, it'll throw a StrongBoxUnavailableException.
So to check if there's a TEE available you could just attempt to generate a key this way and see if it works.

etoken unaccessible after reading

I´m trying to read out the certificate of an etoken. I´ve followed the answer from Keystore from digital signature e-token using java. It´s giving me the certificates installed in the token but after that the token isn´t reachable anymore. Did somebody got something similar while accessing a token?
// Create instance of SunPKCS11 provider
String pkcs11Config = "name=eToken\nlibrary=C:\\path\\to\\your\\pkcs11.dll";
java.io.ByteArrayInputStream pkcs11ConfigStream = new java.io.ByteArrayInputStream(pkcs11Config.getBytes());
sun.security.pkcs11.SunPKCS11 providerPKCS11 = new sun.security.pkcs11.SunPKCS11(pkcs11ConfigStream);
java.security.Security.addProvider(providerPKCS11); // Get provider KeyStore and login with PIN String pin = "11111111";
java.security.KeyStore keyStore = java.security.KeyStore.getInstance("PKCS11", providerPKCS11);
keyStore.load(null, pin.toCharArray()); // Enumerate items (certificates and private keys) in the KeyStore
java.util.Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
System.out.println(alias);
}
The problem persists, after plugging out/in the token is reachable again, but after running the code, the token seems to be locked again. OS Win2k8 Server.
Finally got this clear. After disconnecting other USB devices the Token responds as usual.
The Token should be plugged in to a fully powered port. Best on a separate Host- Bus.

SSL/TLS dynamic key generation

On this project of mine I needed to implement secure connection using SSL/TLS between a client and a server. I found a good article about that so I've managed to do my task without any problem.
This is the article.
My question is pretty simple but I cannot find an answer anywhere. In this particular case, my clients have the same key in the SSL protocol which is created through tutorial on a previous link and put in some kind of a file. Potential problem in this process is that someone can access that file and since every client has that key, someone can listen to all connections.
What I wanted to ask, is there any chance to dynamically generate keys every time some client wants to access the server and put the generated key in the server truststore?
UPDATE
public static final String PATH_TO_ANDROID_KEYSTORE = "and/client.bks";
public static final String PATH_TO_ANDROID_TRUSTSTORE = "and/clienttruststore.bks";
String pathToKeyStore = PATH_TO_ANDROID_KEYSTORE;
String pathToTrustStore = PATH_TO_ANDROID_TRUSTSTORE;
KeyStore keyStoreKeys = KeyStore.getInstance(keyStoreType);
keyStoreKeys.load(Gdx.files.internal(pathToKeyStore).read(), passphrase);
KeyStore keyStoreTrust = KeyStore.getInstance(keyStoreType);
keyStoreTrust.load(Gdx.files.internal(pathToTrustStore).read(), passphrase);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStoreKeys, passphrase);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStoreTrust);
This is the client code and seems like clients have exported server's certificates in their truststores but they actually use the same private key that is generated only once in the keystore using openssl tool.
In this particular case, my clients have the same key in the SSL protocol which is created through tutorial on a previous link and put in some kind of a file.
Unclear. Do you mean they share the same private key? If so, that is a flaw in your system design. Every client should have its own private key. Otherwise the private key isn't, err, private. And access to that key should be via a keystore whose password only the applicion knows, which provides at least another line of defence.
If you just mean that they all have an exported copy of the server's certificate, in their truststores, there is no security risk attached to that at all: it is perfectly normal.
Potential problem in this process is that someone can access that file and since every client has that key, someone can listen to all connections.
No they can't. SSL is immune to man-in-the-middle attacks provided you don't compromise your server's private key, but if you're talking about client private keys they can masquerade as a real client even if they aren't, if they can break through the keystore-password barrier.
What I wanted to ask, is there any chance to dynamically generate keys every time some client wants to access the server and put the generated key in the server truststore?
Not securely, and not online. If your genuine clients can do it, so can an attacker. That's why trust material must be distributed offline.

CKR_DEVICE_ERROR using iaik for digital signature

I'm try to develop a Java Application that is able to do the digital signature on a file with smart card.
I set the PKCS#11 provider in this way:
Security.addProvider(new IAIK());
Properties providerProperties = new Properties();
providerProperties.put("PKCS11_NATIVE_MODULE","path\\asepkcs.dll");
IAIKPkcs11 pkcs11Provider = new IAIKPkcs11(providerProperties);
Security.addProvider(pkcs11Provider);
Module module = Module.getInstance("path\\asepkcs.dll");
After I read the KeyStore that I load in to smart card before, but when I try to use the method for create the digital sign the application catch the follow exception:
java.security.SignatureException: iaik.pkcs.pkcs11.wrapper.PKCS11Exception: CKR_DEVICE_ERROR
at iaik.pkcs.pkcs11.provider.signatures.ExternalHashSignature.pkcs11Sign(ExternalHashSignature.java:294)
at iaik.pkcs.pkcs11.provider.signatures.PKCS11Signature.engineSign(PKCS11Signature.java:638)
at java.security.Signature$Delegate.engineSign(Unknown Source)
at java.security.Signature.sign(Unknown Source)
at sii.tesi.firma.provasc.FirmaScK.main(FirmaScK.java:288)
I'm not be able to understand how I could resolve the CKR_DEVICE_ERROR.
I use for the sign the follow methods:
Signature signAlg = Signature.getInstance("SHA1withRSA");
signAlg.initSign(privateKey);
signAlg.update(toBeEncrypted);
byte[] signatureValue = signAlg.sign();
I fixed CKR_DEVICE_ERROR. The problem was simply that the smartcard was making a bad connection (Omnikey 6121 are badly build)
a paperclip to jam the chip tighter on the board fixed this problem for me.
DId you use the Pkcs11Wrapper as well? If so, did you specify the java.library.path? The Wrapper version should match the Provider version, or check the readme for more details.
Regarding your code, specify the IAIK provider:
Signature.getInstance("SHA1withRSA", iaikProvider)
and try to add the provider like this:
IAIK.addAsProvider(false);
If that doesn't help check the error log generated by the pkcs11 module.

Load Java KeyStore for one alias?

Does anyone know if it is possible to load a KeyStore so that it only prompts for the password for the given alias?
Example:
In my key store i have two private keys: Alice's Encryption Certificate and Bob's Encryption Certificate.
When i load my key store:
keyStore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
keyStore.load(null);
I am prompted for both Alice's and Bob's key store password. Once they are entered i can use getKey("Alice's Encryption Certificate", null); to retrieve Alice's private key. My keys are protected by Entrust's Security Provider, it is who prompts me for the passwords upon loading the key store. If i do not enter Bob's password and try to get his key it will return null, which is fine, but i would like to avoid the password prompt.
Is it possible to somehow specify that i only want Alice's key before loading the key store so i am never prompted for Bob's password?
Thanks.
We had the same issue and couldn't find a way to do it. Basically, you are asking if there is a way to load the keystore partially. It makes things more complicated that MSCAPI provider ignores any password you provide.
We get around the issue by storing only one key With MSCAPI keystore. It turns out this works better with the security model of Smartcard also.

Categories

Resources