Статус: Новичок
Группы: Участники
Зарегистрирован: 29.11.2022(UTC) Сообщений: 5
|
Доброе время суток. Есть необходимость перевести уже рабочую систему на более новую jcp. Было: Рабочая интеграция с ГИС ЖКХ, включающая в себя jcp 2.0.39014, java 8, wildfly 10. Были предприняты попытки просто подменить библиотеку и запустить все под 11 java. Так или иначе это приводило к выбрасыванию исключения на этапе подписи или отправки(одна из последних ошибок, это NullPointerException внутри проверки jcp своих же jar'ников) На данный момент: Используются: wildfly 15, jcp-2.0.41940-A и java 11. jcp-2.0.41940-A в wildfly вынесен в модули. Основные проблемы были на этапе подключения провейдеров и получения socketFactory из SSLContext. Собственно, эти участки и постарался изменить в соответствии с примерами кода из либы. Фрагмент кода добавления провайдеров/получения фабрики сокетов
Код:
System.setProperty("javax.net.ssl.keyStoreType", Consts.KeyStoreType);
System.setProperty("javax.net.ssl.keyStorePassword", Consts.KeyStorePassword);
System.setProperty("javax.net.ssl.trustStoreType", Consts.KeyStoreTrustedType);
System.setProperty("javax.net.ssl.trustStore", Consts.KeyStoreTrustedFile);
System.setProperty("javax.net.ssl.trustStorePassword", Consts.KeyStoreTrustedPassword);
System.setProperty("javax.net.debug", "ssl");
Security.addProvider(new JCP()); // JCP
Security.addProvider(new CryptoProvider()); // JCryptoP
Security.addProvider(new RevCheck()); // RevCheck
Security.addProvider(new Provider());
keyStore = KeyStore.getInstance(JCP.HD_STORE_NAME);
KeyManagerFactory kf = KeyManagerFactory.getInstance("GostX509");
keyStore.load(null, Consts.KeyStorePassword.toCharArray());
kf.init(keyStore, Consts.KeyStorePassword.toCharArray());
privateKey = (PrivateKey) keyStore.getKey(Consts.KeyAlias, Consts.KeyStorePassword.toCharArray());
cert = (X509Certificate) keyStore.getCertificate(Consts.KeyAlias);
TrustManagerFactory tf = TrustManagerFactory.getInstance("GostX509");
trustStore = KeyStore.getInstance(Consts.KeyStoreTrustedType, Consts.KeyStoreTrustedProvider);
trustStore.load(new FileInputStream(new File(Consts.KeyStoreTrustedFile)), Consts.KeyStoreTrustedPassword.toCharArray());
tf.init(trustStore);
SSLContext ctx = TLSContext.initClientSSL(
Provider.PROVIDER_NAME,
"GostTLS",
JCP.PROVIDER_NAME,
JCP.HD_STORE_NAME,
Consts.KeyStoreTrustedFile,
Consts.KeyStoreTrustedPassword,
tf.getTrustManagers()
);
gostSSLSocketFactory = ctx.getSocketFactory();
Далее gostSSLSocketFactory используется в наследнике java.net.URLStreamHandler, где переопределяется метод openConnection:
Код:
@Override
protected URLConnection openConnection(URL url) throws IOException {
HttpsURLConnection conn = (HttpsURLConnection) local.openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
//была проблема с HandShake, на форуме cryptopro взял это решение
@Override
public boolean verify(String hostname, SSLSession sslSession) {
return true;
}
});
conn.setConnectTimeout(Consts.CONNECT_TIMEOUT);
conn.setReadTimeout(Consts.READ_TIMEOUT);
if (Consts.BASIC_AUTH_REQUIRED) {
conn.setRequestProperty("Authorization", "Basic "+Consts.AUTHBASE64);
}
conn.setSSLSocketFactory(GostConfig.getSSLSocketFactory());
return conn;
}
В окружении wildfly стоит tls_prohibit_disabled_validation = false. Т.к. были проблемы при handShake. В итоге мы отправляем SOAP запрос и получем ответ с сервера ГИС ЖКХ. В ответе присутствует стэктрейс и ошибка такого характера: "Certificate in header is blank: ru.lanit.hcs.integration.common.exception.SoapFaultException: Certificate in header is blank". Было подозрение, что криво заполняется body Soap запроса. В итоге сравнил xml текущую и ту, которая создается на прошлой реализации jcp(2.0.39014) и java(8) - отличий не заметил. Когда снифили пакеты, то заметили отличие только в TLS в запросах. В случае со старой реализацией улетает tls1.0, а в текущей tls1.2. В чем может быть проблема? Что за заголовок с сертификатом им может быть нужен и почему он пустой?
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 06.12.2008(UTC) Сообщений: 3,963 Откуда: Крипто-Про Сказал(а) «Спасибо»: 20 раз Поблагодарили: 704 раз в 665 постах
|
Здравствуйте. SOAP и TLS - разные несвязанные протоколы. Ошибка вида "Certificate in header is blank: ru.lanit.hcs.integration.common.exception.SoapFaultException: Certificate in header is blank" относится к первому. вероятно, что-то не так в структуре документа (не добавлен какой-то сертификат в header сообщения). Если вы указали протокол "GostTLS", то будет TLSv1, если "GostTLSv1.2" - TLSv.1.2.
|
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 29.11.2022(UTC) Сообщений: 5
|
Проблема решилась заменой TLSContext.initClientSSL на sslContext.init. Код:
System.setProperty("javax.net.ssl.keyStoreType", Consts.KeyStoreType);
System.setProperty("javax.net.ssl.keyStorePassword", Consts.KeyStorePassword);
System.setProperty("javax.net.ssl.trustStoreType", Consts.KeyStoreTrustedType);
System.setProperty("javax.net.ssl.trustStore", Consts.KeyStoreTrustedFile);
System.setProperty("javax.net.ssl.trustStorePassword", Consts.KeyStoreTrustedPassword);
System.setProperty("javax.net.debug", "ssl");
Security.addProvider(new JCP()); // JCP
Security.addProvider(new CryptoProvider()); // JCryptoP
Security.addProvider(new RevCheck()); // RevCheck
Security.addProvider(new Provider());
keyStore = KeyStore.getInstance(JCP.HD_STORE_NAME);
KeyManagerFactory kf = KeyManagerFactory.getInstance("GostX509");
keyStore.load(null, Consts.KeyStorePassword.toCharArray());
kf.init(keyStore, Consts.KeyStorePassword.toCharArray());
privateKey = (PrivateKey) keyStore.getKey(Consts.KeyAlias, Consts.KeyStorePassword.toCharArray());
cert = (X509Certificate) keyStore.getCertificate(Consts.KeyAlias);
TrustManagerFactory tf = TrustManagerFactory.getInstance("GostX509");
trustStore = KeyStore.getInstance(Consts.KeyStoreTrustedType, Consts.KeyStoreTrustedProvider);
trustStore.load(new FileInputStream(new File(Consts.KeyStoreTrustedFile)), Consts.KeyStoreTrustedPassword.toCharArray());
tf.init(trustStore);
sslContext.init(kf.getKeyManagers(), tf.getTrustManagers(), null);
gostSSLSocketFactory = sslContext.getSocketFactory();
Если честно, не до конца понял в чем разница, т.к. TLSContext.initClientSSL внутри тоже создает KeyManagerFactory и т.п. Теперь с гиса возвращается успешный ответ, но при проверке подписи вылетает исключение: "urn:getState: The referenced SignedProperties are not contained by the proper QualifyingProperties element: ru.tii.crypto.core.SignException: The referenced SignedProperties are not contained by the proper QualifyingProperties element" В ответе ГИСа нету ошибок, т.к. эти же ответы нормально проходят проверку подписи на старой реализации. И SignedProperties находится внутри QualifyingProperties. Ниже привожу код проверки, который работает на старой реализации(jcp 2.0.39014, java 8) и не работает на новой(jcp 2.0.41940-A, java 11): Код:
final Document verifyDocument = msg.getSOAPPart().getEnvelope().getOwnerDocument();
final NodeList nl = verifyDocument.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
if (nl.getLength() == 0) {
return;
}
MessageDigestEngineProvider messageDigestEngineProvider = new CustomizableMessageDigestEngineProvider();
CertificateValidationProvider certValidator = KeyStoreUtils.createCertificateValidationProvider(GostConfig.trustStore);
XadesVerificationProfile vp = new XadesVerificationProfile(certValidator);
vp.withBinding(MessageDigestEngineProvider.class, messageDigestEngineProvider);
vp.withBinding(QualifyingPropertiesUnmarshaller.class, QualifyingPropertiesUnmarshaller2.class);
vp.withQualifyingPropertyVerifier(SigningTimeData.class, NoSigningTimeVerifier.class);
vp.withQualifyingPropertyVerifier(SigningCertificateData.class, SigningCertificateVerifier2.class);
for (int i = 0; i < nl.getLength(); i++) {
final XadesVerifier verifier = vp.newVerifier();
final SignatureSpecificVerificationOptions verificationOptions = new SignatureSpecificVerificationOptions();
final Element signatureElement = (Element) nl.item(i);
XAdESVerificationResult vr = verifier.verify(signatureElement, verificationOptions);
}
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 06.12.2008(UTC) Сообщений: 3,963 Откуда: Крипто-Про Сказал(а) «Спасибо»: 20 раз Поблагодарили: 704 раз в 665 постах
|
Здравствуйте. А "ru.tii.crypto.core.SignException" - это чей ответ? Приведенный код, предполагаю, относится к xades4j, а JCP только проверяет хэши и подписи. |
|
|
|
|
Статус: Новичок
Группы: Участники
Зарегистрирован: 29.11.2022(UTC) Сообщений: 5
|
Автор: Евгений Афанасьев Здравствуйте. А "ru.tii.crypto.core.SignException" - это чей ответ? Приведенный код, предполагаю, относится к xades4j, а JCP только проверяет хэши и подписи. SignException - наша обертка над исключением. Изначально там вылетает xades4j.verification.QualifyingPropertiesIncorporation. Выбрасывается оно при вызове SignatureUtils.checkSignedPropertiesIncorporation. Код следующий: Код:
static void checkSignedPropertiesIncorporation(Element qualifyingPropsElem, Reference signedPropsRef) throws QualifyingPropertiesIncorporationException
{
Element signedPropsElem = DOMHelper.getFirstChildElement(qualifyingPropsElem);
if (signedPropsElem == null
|| !signedPropsElem.getLocalName().equals(QualifyingProperty.SIGNED_PROPS_TAG)
|| !signedPropsElem.getNamespaceURI().equals(QualifyingProperty.XADES_XMLNS))
{
throw new QualifyingPropertiesIncorporationException("SignedProperties not found as the first child of QualifyingProperties.");
}
DOMHelper.useIdAsXmlId(signedPropsElem);
// Only QualifyingProperties in the signature's document are supported.
// XML-DSIG 4.3.3.2: "a same-document reference is defined as a URI-Reference
// that consists of a hash sign ('#') followed by a fragment"
if (!signedPropsRef.getURI().startsWith("#"))
{
throw new QualifyingPropertiesIncorporationException("Only QualifyingProperties in the signature's document are supported");
}
try
{
Node sPropsNode = signedPropsRef.getNodesetBeforeFirstCanonicalization().getSubNode();
if (sPropsNode == null || sPropsNode.getNodeType() != Node.ELEMENT_NODE)
{
throw new QualifyingPropertiesIncorporationException("The supposed reference over signed properties doesn't cover an element.");
}
// The referenced signed properties element must be the child of qualifying properties.
Element referencedSignedPropsElem = (Element) sPropsNode;
if (referencedSignedPropsElem != signedPropsElem)
{
throw new QualifyingPropertiesIncorporationException("The referenced SignedProperties are not contained by the proper QualifyingProperties element");
}
} catch (XMLSignatureException ex)
{
throw new QualifyingPropertiesIncorporationException("Cannot get the referenced SignedProperties", ex);
}
}
В итоге referencedSignedPropsElem != signedPropsElem, хотя signedPropsElem внутри себя включает объект, на который ссылается referencedSignedPropsElem. Мог ли jcp как-то повлиять на ход этой проверки? Версию xades4j не меняли. При запуске старой версии приложения таких ошибок нету.
|
|
|
|
Быстрый переход
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.
Important Information:
The Форум КриптоПро uses cookies. By continuing to browse this site, you are agreeing to our use of cookies.
More Details
Close