Вопрос или проблема
Я разрабатываю прокси-сервер SCEP как приложение Spring Boot, предназначенное для перенаправления запросов SCEP из Java-приложения на сервер SCEP. Прокси обрабатывает GET-запросы, и я сталкиваюсь с проблемой, когда пытаюсь декодировать pkiMessage с помощью jscep. В частности, я вижу, что signerInfo равен null во время операции scepClient.enrol. Во время PKIOperation прокси напрямую перенаправляет GET-запрос на сервер SCEP и возвращает байтовый массив ответа в Java-приложение.
Ниже приведен фрагмент кода Spring Boot приложения-
if ("GetCACert".equalsIgnoreCase(operation)) {
logger.info("Обработка операции GetCACert для сообщения: {}", message);
CertStore caCertStore = scepClient.getCaCertificate(message);
Collection<? extends Certificate> caCertificates = caCertStore.getCertificates(null);
if (!caCertificates.isEmpty()) {
Certificate caCert = caCertificates.iterator().next();
if (caCert instanceof X509Certificate) {
X509Certificate x509Cert = (X509Certificate) caCert;
logCaCertificateDetails(x509Cert);
// Кодирование сертификата в Base64 и установка заголовков
String base64EncodedCert = new String(Base64.encode(x509Cert.getEncoded()));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.asMediaType(MimeType.valueOf("application/x-x509-ca-cert")));
return ResponseEntity.ok().headers(headers).body(x509Cert.getEncoded());
} else {
throw new CertStoreException("Сертификат не является X509Certificate.");
}
} else {
throw new CertStoreException("Сертификаты не найдены в хранилище CA CertStore.");
}
} else if ("PKIOperation".equalsIgnoreCase(operation)) {
logger.info("Обработка PKI операции для сообщения: {}", message);
byte[] responseBytes = forwardGetRequest(operation, message);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.asMediaType(MimeType.valueOf("application/x-pki-message")));
return ResponseEntity.ok().headers(headers).body(responseBytes);
}
Во время PKIOperation я пытаюсь перенаправить запрос и получить байты ответа от сервера SCEP, но при обработке с помощью jscep я сталкиваюсь с null signerInfo.
Соответствующий раздел кода в jscep, где я сталкиваюсь с ошибкой, выглядит следующим образом:
public PkiMessage<?> decode(final CMSSignedData pkiMessage) throws MessageDecodingException {
LOGGER.debug("Декодирование pkiMessage");
validate(pkiMessage);
CMSProcessable signedContent = pkiMessage.getSignedContent();
SignerInformationStore signerStore = pkiMessage.getSignerInfos();
SignerInformation signerInfo = signerStore.get(new JcaSignerId(signer));
if (signerInfo == null) {
throw new MessageDecodingException("Не удалось найти signerInfo для " + signer.getSubjectX500Principal());
}
}
Что я пробовал-
Проверил, что объект CMSSignedData заполнен.
Подтвердил, что сертификат CA корректно извлекается в GetCACert.
Проверил, что сервер SCEP доступен и отвечает.
Без использования прокси SCEP Java-приложение может корректно получить сертификат с сервера без каких-либо ошибок.
Может кто-нибудь указать, где я ошибаюсь, и подсказать, что я могу сделать для отладки вышеизложенного?
Ответ или решение
Ошибка "Could not find signerInfo for signer.getSubjectX500Principal()" при вызове метода scepClient.enrol указывает на то, что информация о подписанте отсутствует в декодированном PKI-сообщении. Это может происходить по нескольким причинам, и в этой статье мы детально разберем возможные источники проблемы и шаги для их устранения.
Разбор проблемы
-
Отсутствие signerInfo:
Ошибка возникает в коде методаdecode()
, когдаsignerInfo
возвращает null. Это указывает на то, что система не может найти информацию о подписанте, что может быть связано с различными факторами в процессе обработки данных. -
Проблемы с PKI-сообщением:
Убедитесь, что сообщение PKI, передаваемое от вашего SCEP-прокси к серверу, корректно сформировано и содержит все необходимые поля. А именно:- Подписанный контент
- Информация о подписанте
-
Не корректная маршрутизация данных:
Проверьте, корректно ли вы пересылаете данные между клиентом и сервером. Возможно, некоторые поля теряются или искажаются в процессе передачи.
Рекомендации по отладке
1. Логирование
Добавьте дополнительные логгирования на всех этапах обработки запроса и ответа. Это поможет увидеть:
- Какая информация передается в запросе и получаемом ответе
- Корректно ли декодируется
CMSSignedData
- Есть ли другие сообщения об ошибках в логах, которые могли бы объяснить проблему
2. Проверка содержимого responseBytes
Прежде чем вызывать scepClient.enrol
, убедитесь, что responseBytes
, полученные от SCEP-сервера, действительно содержат корректное PKI-сообщение. Для этого:
- Распечатывайте размер массива байтов
- Проверьте, что содержимое соответствует стандарту PKCS#7/CMS
3. Валидация PKI-сообщения
В методе decode()
добавьте дополнительную валидацию, чтобы убедиться, что переданный CMSSignedData
объект не просто заполнен, но и корректно сформирован:
if (pkiMessage.getSignerInfos().getSigners().isEmpty()) {
throw new MessageDecodingException("No signer information present in the PKI message.");
}
4. Сравнение с работающим кодом
Так как указано, что при прямом обращении к SCEP-серверу все работает корректно, сравните что именно отличается в запросах и ответах:
- Используйте инструменты типа Wireshark или Postman, чтобы захватить и проанализировать HTTP-трафик.
- Сравните заголовки и тела запросов.
Заключение
Ошибка, с которой вы столкнулись, указывает на потенциальные проблемы в процессе передачи или обработке данных в рамках вашего SCEP-прокси. Применяя описанные шаги для отладки и улучшая логирование, вы сможете pinpoint проблему и устранить ее.
Если все вышеперечисленные шаги не приведут к успеху, возможно, потребуется более глубокое изучение используемого вами API jscep и его взаимодействия с SCEP-сервером.