Signing documents with SunMSCAPI and suppressing the “Enter PIN” dialog

允我心安 提交于 2021-02-05 20:37:12

问题


I am developing a java code that signs documents using a certificate token. So far, everything works great, but I want to suppress the "enter pin" dialog because I am storing the user's pin so he/she does not need to type it every time. The real problem here is that this code will run in batch mode (no user interaction). I know that once typed, the key may be in memory so it does not need to be typed again for a shorty time. But I can't rely on that, I need to provide the PIN. Here the code I have so far (it is only a sample, it may not be complete nor work):

protected KeyStore loadKeyStoreFromSmartCard()  {
  keyStore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
  keyStore.load(null, null);
  return keyStore;
}

public void signDocument(byte[] conteudoParaAssinar, String certAlias) {
    char[] pass = (char[]) null;
    PrivateKey key = (PrivateKey) loadKeyStoreFromSmartCard.getKey(certAlias, pass);
    Certificate[] chain = loadKeyStoreFromSmartCard(true).getCertificateChain(certAlias);
    CertStore certsAndCRLs = CertStore.getInstance("Collection", new CollectionCertStoreParameters(Arrays.asList(chain)), "BC");
    X509Certificate cert = (X509Certificate) chain[0];
    CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
    gen.addSigner(key, cert, CMSSignedDataGenerator.DIGEST_SHA1);
    gen.addCertificatesAndCRLs(certsAndCRLs);
    CMSProcessable data = new CMSProcessableByteArray(conteudoParaAssinar);
    CMSSignedData signed = gen.generate(data, true, "SunMSCAPI");
    byte[] envHex = signed.getEncoded();
}

EDIT

I have heard about CryptSetProvParam PP_KEYEXCHANGE_PIN witch may be the solution, but I dont know how to call it from java. All examples I have found are for .net.


回答1:


I implemented something similar to this once, but unfortunately the smart card driver was buggy and so the driver tried to bring up the native PIN callback implemented in the driver itself at times. But let's assume your driver does better at that.

First of all, you need to implement a CallbackHandler, the documentation gives a good overview of the concept. In your case, it's the PasswordCallback case that's interesting to handle.

Next, create your KeyStore as follows (exception handling omitted)

Provider provider = Security.getProvider("SunMSCAPI");
CallbackHandler cbh = // your implementation
KeyStore.ProtectionParameter protection = new KeyStore.CallbackHandlerProtection(cbh);
//get a handle of the CAPI KeyStore as before
KeyStore.Builder keystoreBuilder = KeyStore.Builder.newInstance("Windows-MY",
                                                                provider, 
                                                                protection);
KeyStore store = keystoreBuilder.getKeyStore();

Then, to access the private key, do this:

KeyStore.Entry ke = store.getEntry(alias, null);
if (!(ke instanceof KeyStore.PrivateKeyEntry))
    throw new RuntimeException("The entry is not a private key.");
PrivateKey key = ((KeyStore.PrivateKeyEntry) ke).getPrivateKey();

The provider will automatically generate the appropriate PasswordCallbacks to be sent to your CallbackHandler. When handling the callback, you would simply pass your cached password.

Needless to say that password caching is generally frowned upon ;)




回答2:


MS CryptoAPI doesn't provide any way at all to specify the PIN. Your only option is to switch from CryptoAPI to PKCS#11 if possible -- PKCS#11 requires you to "logon" to device in code and provide the PIN in code as well.

Update: some CSP (cryptographic service provider) modules shipped by some hardware vendors let you call a special CryptoAPI function (CryptSetProvParam, https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptsetprovparam) and pass PIN to it. You need to contact a vendor for information if your hardware's CSP supports this method of setting a PIN and if it does, what the exact parameter ID is etc. Anyway, you won't be currently capable of setting the PIN in this way from your Java application using the standard SunMSCAPI provider.



来源:https://stackoverflow.com/questions/6496565/signing-documents-with-sunmscapi-and-suppressing-the-enter-pin-dialog

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!