Цифровая подпись с отметкой времени в Java
У меня проблема с созданием действительной подписи CMS в Bouncy Castle с использованием надежной временной метки. Создание подписи работает хорошо (я хочу включить подпись в файл PDF), подпись действительна. Но после того, как я включил доверенную временную метку в таблицу атрибутов без знака подписи, подпись все еще остается действительной, но Reader сообщает, что подпись включает встроенную временную метку, но она недействительна. Это заставляет меня поверить, что временная метка хэша I не является правильной, но я не могу понять, в чем ее проблема.
Код подписи:
Store store = new JcaCertStore(Arrays.asList(certContainer.getChain()));
CMSSignedDataGenerator signedDataGenerator = new CMSSignedDataGenerator();
JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build());
JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA1withRSA");
signedDataGenerator.addSignerInfoGenerator(
infoGeneratorBuilder.build(contentSignerBuilder.build(certContainer.getPrivateKey()), (X509Certificate)certContainer.getSignatureCertificate()));
signedDataGenerator.addCertificates(store);
CMSTypedData cmsData = new CMSProcessableByteArray(data);
signedData = signedDataGenerator.generate(cmsData, false);
Collection<SignerInformation> ss = signedData.getSignerInfos().getSigners();
SignerInformation si = ss.iterator().next(); // get first signer (should be only one)
ASN1EncodableVector timestampVector = new ASN1EncodableVector();
Attribute token = createTSToken(si.getSignature());
timestampVector.add(token);
AttributeTable at = new AttributeTable(timestampVector);
si = SignerInformation.replaceUnsignedAttributes(si, at);
ss.clear();
ss.add(si);
SignerInformationStore newSignerStore = new SignerInformationStore(ss);
CMSSignedData newSignedData = CMSSignedData.replaceSigners(signedData, newSignerStore);
createTSToken
код:
public Attribute createTSToken(byte[] data) throws NoSuchProviderException, NoSuchAlgorithmException, IOException {
// Generate timestamp
MessageDigest digest = MessageDigest.getInstance("SHA1", "BC");
TimeStampResponse response = timestampData(digest.digest(data));
TimeStampToken timestampToken = response.getTimeStampToken();
// Create timestamp attribute
Attribute a = new Attribute(PKCSObjectIdentifiers.id_aa_signatureTimeStampToken, new DERSet(ASN1Primitive.fromByteArray(timestampToken.getEncoded())));
return a;
}
timestampData
:
TimeStampRequestGenerator reqgen = new TimeStampRequestGenerator();
TimeStampRequest req = reqgen.generate(TSPAlgorithms.SHA1, data);
byte request[] = req.getEncoded();
URL url = new URL("http://time.certum.pl");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Content-type", "application/timestamp-query");
con.setRequestProperty("Content-length", String.valueOf(request.length));
OutputStream out = con.getOutputStream();
out.write(request);
out.flush();
if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new IOException("Received HTTP error: " + con.getResponseCode() + " - " + con.getResponseMessage());
}
InputStream in = con.getInputStream();
TimeStampResp resp = TimeStampResp.getInstance(new ASN1InputStream(in).readObject());
response = new TimeStampResponse(resp);
response.validate(req);
if(response.getStatus() != 0) {
System.out.println(response.getStatusString());
return null;
}
return response;
Спасибо за вашу помощь!
Файлы примеров:
Подписанный PDF с LTV - отредактированный
1 ответ
signature_lipsum.pdf, первая версия
Метка времени ссылается как подписавшая какая-то
CN=e-Szigno Test TSA2,OU=e-Szigno CA,O=Microsec Ltd.,L= Будапешт,C=HU
который был выпущен
CN=Microsec e-Szigno Test Root CA 2008,OU=e-Szigno CA,O=Microsec Ltd.,L= Будапешт,C=HU
с серийным номером 7.
Однако он не предоставляет сам этот сертификат и не предоставляется ни контейнером CMS с инкапсулирующей подписью, ни в некотором разделе PDF-документа с информацией, связанной с проверкой.
Таким образом, по крайней мере, на моем компьютере нет никакой возможности проверить маркер метки времени, и Adobe Reader совершенно прав, чтобы не принимать метку времени.
Предоставили ли вы соответствующий сертификат на вашем компьютере способом, подходящим для вашего Adobe Reader? Если у вас есть, и он все еще не работает, пожалуйста, предоставьте его для дальнейших испытаний. Если нет, попробуйте найти и предоставить их.
Возможно, вы захотите усилить сам маркер метки времени, чтобы включить этот сертификат, прежде чем включать его в подпись.
signature_lipsum.pdf, вторая версия
В обновленном файле signature_lipsum.pdf отметка времени подписи содержит сертификат TSA, но это неверный сертификат!
Как и в первой версии, отметка времени ссылается на сертификат подписывающего
- Испытуемый CN=e-Szigno Test TSA2,OU=e-Szigno CA,O=Microsec Ltd.,L= Будапешт,C=HU
- CN эмитента = Microsec e-Szigno Test Root CA 2008, OU = e-Szigno CA, O = Microsec Ltd., L = Будапешт,C=HU
- Серийный номер 7.
Содержащийся сертификат, с другой стороны, имеет
- Испытуемый CN=e-Szigno Test TSA2,OU=e-Szigno CA,O=Microsec Ltd.,L= Будапешт,C=HU
- CN эмитента = Microsec e-Szigno Test Root CA 2008, OU = e-Szigno CA, O = Microsec Ltd., L = Будапешт,C=HU
- Серийный номер 5.
Я предполагаю, что тестовый TSA использует несколько подписывающих устройств / программных токенов с индивидуальными сертификатами, а OP содержит неправильный сертификат.
Поэтому вы можете вместо этого включить правильный сертификат.
Кстати, метка времени в PDF, подписанная iText, содержит сертификат, соответствующий ссылкам в марке...
В запросах метки времени RFC 3161 TSA может автоматически включить сертификат подписавшего. Надувной замок позволяет установить этот флаг следующим образом:
TimeStampRequestGenerator reqgen = new TimeStampRequestGenerator();
reqgen.setCertReq(true); // <<<<<<<<<<<<<<<<<<<<<<<<<<
TimeStampRequest req = reqgen.generate(TSPAlgorithms.SHA1, data);
Вместо того, чтобы включать сертификат самостоятельно, вы можете попробовать это.
LTV включен
Из комментариев:
Просто из любопытства, что еще нужно добавить, чтобы включить PDF LTV?
Цитируя Леонарда Розентхола (PDF-гуру в Adobe):
LTV включен означает, что вся информация, необходимая для проверки файла (за исключением корневых сертификатов), содержится внутри. Так что это утверждение [...] было бы правдой.
PDF подписан правильно и содержит все необходимые сертификаты, действительный ответ CRL или OSCP для каждого сертификата
( 10 января 2013 г.; 7:07 вечера; Леонард Розентол на главном форуме)