Xades4j: хранилище ключей не может быть инициализировано
Я пытаюсь импортировать сертификат, который я недавно установил в Windows, в Java для использования с xades4j. К сожалению, я довольно новичок в том, что касается сертификатов, ключей и всего такого.
Однако каждый раз, когда я запускаю программу, я получаю следующую ошибку:
>xades4j.verification.UnexpectedJCAException: The keystore couldn't be initialized
at xades4j.providers.impl.KeyStoreKeyingDataProvider.ensureInitialized(KeyStoreKeyingDataProvider.java:179)
at xades4j.providers.impl.KeyStoreKeyingDataProvider.getSigningCertificateChain(KeyStoreKeyingDataProvider.java:189)
at xades4j.production.SignerBES.sign(SignerBES.java:159)
at xades4j.production.SignerBES.sign(SignerBES.java:130)
at com.logic.test.signBes(test.java:138)
at com.logic.test.<init>(test.java:80)
at com.view.FrmMenu.<init>(FrmMenu.java:41)
at com.view.FrmMenu$9.run(FrmMenu.java:289)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Caused by: java.security.KeyStoreException: KeyStore instantiation failed
at java.security.KeyStore$Builder$FileBuilder.getKeyStore(KeyStore.java:1862)
at xades4j.providers.impl.KeyStoreKeyingDataProvider.ensureInitialized(KeyStoreKeyingDataProvider.java:175)
... 21 more
Caused by: java.io.IOException: DER input, Integer tag error
at sun.security.util.DerInputStream.getInteger(DerInputStream.java:192)
at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1940)
at java.security.KeyStore.load(KeyStore.java:1445)
at java.security.KeyStore$Builder$FileBuilder$1.run0(KeyStore.java:1848)
at java.security.KeyStore$Builder$FileBuilder$1.run(KeyStore.java:1807)
at java.security.KeyStore$Builder$FileBuilder$1.run(KeyStore.java:1796)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.KeyStore$Builder$FileBuilder.getKeyStore(KeyStore.java:1858)
... 22 more
>
Мне нужно подписать документ XML в формате XaDeS-BES. Я импортировал ключ (или сертификат?) С диска, и он находится в сертификатах доверенных корневых центров сертификации Windows. Я экспортировал его в корень диска C из диспетчера сертификатов Windows (certmgr.msc).
На этом сайте я обнаружил одну публикацию, в которой упоминалось о следующих попытках инициализации хранилища ключей:
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
К сожалению, не было никаких изменений.
Код, который я использовал, основан на примере вики:
private static final String CERT_FOLDER = "C:/";
private static final String CERT = "testkey.cer";
private static final String PASS = "test1234"; //the same in cert and keystorage
private static final String SIGNED = "persistent/xml/001-001-000000000new1.xml";
private static final String DOCUMENT = "persistent/xml/001-001-000000000.xml";
private static void signBes() throws Exception {
Document doc = DocumentBuilderFactory
.newInstance()
.newDocumentBuilder()
.parse(new File(DOCUMENT));
Element elem = doc.getDocumentElement();
DOMHelper.useIdAsXmlId(elem);
KeyingDataProvider kdp = new FileSystemKeyStoreKeyingDataProvider(
"pkcs12",
CERT_FOLDER + CERT,
new FirstCertificateSelector(),
new DirectPasswordProvider(PASS),
new DirectPasswordProvider(PASS),
true);
DataObjectDesc obj = new DataObjectReference("#" + elem.getAttribute("Id"))
.withTransform(new EnvelopedSignatureTransform());
SignedDataObjects dataObjs = new SignedDataObjects().withSignedDataObject(obj);
// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
// ks.load(null, null);
XadesSigner signer = new XadesBesSigningProfile(kdp).newSigner();
signer.sign(dataObjs, elem);
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(SIGNED));
transformer.transform(source, result);
}
Спасибо за любую помощь.
1 ответ
Для выполнения операции подписи вам нужна пара ключ / сертификат, а именно контейнер PKCS12. В Windows эта пара обычно .pfx
или же .p12
файл. Я не уверен, в чем проблема, но вот некоторые соображения, которые могут вам помочь:
- Сертификат, который используется для подписи, обычно является "личным" сертификатом, а не корневым сертификатом доверенного органа.
- Корневой сертификат - это сертификат, принадлежащий объекту, который обычно выдает сертификаты другим субъектам.
- Частью процесса проверки сертификата является установление цепочки доверия от сертификата субъекта до корневого сертификата. В Windows доверенные корневые сертификаты находятся в указанном вами магазине: "Доверенные корневые центры сертификации Windows". Вероятно, там не должно быть вашего сертификата подписи.
- Так как вы делаете операцию со знаком (для подписи BES) и используете
FileSystemKeyStoreKeyingDataProvider
цепочка доверия на самом деле менее актуальна. Это становится актуальным, когда вы проверяете подпись. - Из вашего кода кажется, что у вас есть файл только для сертификата (
.cer
). Я не знаю, как вы получили сертификат в первую очередь, но он должен был быть предоставлен вместе с ключом, вероятно, в комплекте.pfx
файл защищен паролем. - При создании
FileSystemKeyStoreKeyingDataProvider
Вы должны передать файл PKCS12 (например,.pfx
) - Если у вас установлен сертификат в каком-то другом хранилище Windows, попробуйте экспортировать его с ключом (если это возможно; в первую очередь это зависит от того, как он был импортирован).
Надеюсь это поможет.