Closed saranpol closed 3 years ago
@saranpol The problem might occurred from eToken does not have certificate chain or application can't connect CDP to get CRL? Could you confirm that eToken have certificate chain and attach test file?
I debug the certificateChain
and the output are ...
certificateChain length 1 certificateChain [Ljava.security.cert.Certificate;@490d6c15
here is and output pdf tsa_signed.pdf
this dialog show when open pdf and take 10-20 seconds and disappear
why you have this line of code in for loop ? if(i==certificateChain.length-1) {break;}
@sala-daeng
from the debug log and output pdf, there is only 1 certificate (signer certificate) in chain.
Could you confirm how many certificate in the eToken? This code require full certificate chain provided to get complete CRL list. It does not automatically retrieve chain from its certificate information.
The dialog shown because Adobe try to check certificate revocation information due to pdf file does not have any revocation information (CRL).
if(i==certificateChain.length-1) {break;} This line of code is for skipping Root CA revocation information retrieve, Root CA revocation information is not required to check certificate validity. I aware that there is a better way to check this. However due to developer shortage, it might a long time to improve this code.
My eToken have only 1 certificate, requested from https://www.thaidigitalid.com
so the certificateChain length should have more than one right?
I try this pull request https://github.com/ETDA/PDFSigningAndTimestamp/pull/13
found that it can get about 1700 Certificate Revocation List (CRLs)
and I need to increase signature size *10
but I still can't make LTV enable.
@saranpol Default eToken from CA might have only 1 certificate because there are other ways to get CRL, not from eToken only.
However this code uses certificates from eToken to get CRL. You can add other certificates into it via Safenet client tool.
Yes, the chain length from eToken to be more than 1 in this case.
New PDF file might not have CRL for complete certificate chain.
Could you provide the new sample PDF file?
Here is pdf from https://github.com/ETDA/PDFSigningAndTimestamp/pull/13 tsa_signed.pdf
What can I do to enable LTV ? I have only one eToken and one certificate from thaidigitalid. How can I add other CRL to make LTV enable ?
@sala-daeng This file has the revocation information for signer certificate, however it is not LTV because there is not revocation information for complete certificate chain. There are 2 options to use this code to sign LTV on Adobe
@nathamETDA Thank you very much in advance. We really need your help.
"This file has the revocation information for signer certificate" << Do you mean only second tsa_signed.pdf from https://github.com/ETDA/PDFSigningAndTimestamp/pull/13 code has revocation information or both tsa_signed.pdf has revocation information ?
For option 1 : 1.1 Where is certificate chain how can I get it from, is it a file ? 1.2 Which Menu of Safenet Authentication Client to import certificate chain ?
For option 2 : 2.1 Which code to modify do you mean from pull request 13 https://github.com/ETDA/PDFSigningAndTimestamp/pull/13 ? 2.2 If you mean from pull request 13, this is important part of code I modify It already get certificateChain in public static void signWithTSA function before it get crlList in public byte[] sign so what is the cause of no revocation information for complete certificate chain ?
(here is source code of modify from pull request 13) PDFSigningAndTimestamp_LTV_1.zip
boolean signPdf(File pdfFile, File signedPdfFile) throws IOException {
PDDocument doc = null;
try {
doc = PDDocument.load(pdfFile);
OutputStream fos = new FileOutputStream(signedPdfFile);
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setSignDate(Calendar.getInstance());
COSDictionary catalogDict = doc.getDocumentCatalog().getCOSObject();
catalogDict.setNeedToBeUpdated(true);
// For big certificate chain
SignatureOptions signatureOptions = new SignatureOptions();
// signatureOptions.setPreferredSignatureSize(SignatureOptions.DEFAULT_SIGNATURE_SIZE * 2);
signatureOptions.setPreferredSignatureSize(SignatureOptions.DEFAULT_SIGNATURE_SIZE * 10);
doc.addSignature(signature, this, signatureOptions);
doc.saveIncremental(fos);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
if(doc != null){
doc.close();
}
}
}
@Override
public byte[] sign(InputStream is) throws IOException {
try {
List<Certificate> certList = new ArrayList<>();
certList.addAll(Arrays.asList(certificateChain));
@SuppressWarnings("rawtypes")
Store certStore = new JcaCertStore(certList);
ContentSigner sha512Signer = new JcaContentSignerBuilder("SHA256WithRSA").build(privateKey);
org.bouncycastle.asn1.x509.Certificate cert = org.bouncycastle.asn1.x509.Certificate
.getInstance(ASN1Primitive.fromByteArray(certificate.getEncoded()));
ASN1EncodableVector signedAttributes = new ASN1EncodableVector();
signedAttributes.add(new Attribute(CMSAttributes.contentType, new DERSet(CMSObjectIdentifiers.data)));
// =========================== For LTV Enable ===========================
List<CRL> crlList = new DssHelper().readCRLsFromCert((X509Certificate) certificate);
CertificateList[] certRevList = new CertificateList[crlList.size()];
System.out.println("crlList ###############################");
System.out.println(crlList.toString());
for(int i=0; i<crlList.size(); i++) {
X509CRL crl = (X509CRL) crlList.get(0);
X509CRLHolder crlHolder = new X509CRLHolder(crl.getEncoded());
certRevList[i] = crlHolder.toASN1Structure();
}
List<OCSPResponse> ocspList = new ArrayList<OCSPResponse>();
for (int i=0; i<certificateChain.length; i++) {
X509Certificate certTemp = (X509Certificate) certificateChain[i];
if (!certTemp.getIssuerDN().equals(certTemp.getSubjectDN())) {
X509Certificate issuerCert = null;
if (i+1 < certificateChain.length) {
issuerCert = (X509Certificate) certificateChain[i + 1];
}
if(issuerCert == null) {
issuerCert = new GetOcspResp().getIssuerCert(certTemp);
}
OCSPResp ocspResp = new GetOcspResp().getOcspResp(certTemp, issuerCert);
if (ocspResp != null) {
ocspList.add(OCSPResponse.getInstance(ocspResp.getEncoded()));
}
}
}
OCSPResponse[] ocsps = new OCSPResponse[ocspList.size()];
for(int i=0; i<ocspList.size(); i++) {
ocsps[i] = ocspList.get(i);
}
RevocationValues revValues = new RevocationValues(certRevList, ocsps, null);
signedAttributes.add(new Attribute(new ASN1ObjectIdentifier("1.2.840.113583.1.1.8"), new DERSet(revValues)));
// =========================== For LTV Enable ===========================
AttributeTable signedAttributesTable = new AttributeTable(signedAttributes);
signedAttributesTable.toASN1EncodableVector();
DefaultSignedAttributeTableGenerator signedAttributeGenerator = new DefaultSignedAttributeTableGenerator(
signedAttributesTable);
SignerInfoGeneratorBuilder signerInfoBuilder = new SignerInfoGeneratorBuilder(
new JcaDigestCalculatorProviderBuilder().build());
signerInfoBuilder.setSignedAttributeGenerator(signedAttributeGenerator);
SignerInfoGenerator signerInfoGen = signerInfoBuilder.build(sha512Signer, new X509CertificateHolder(cert));
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addSignerInfoGenerator(signerInfoGen);
gen.addCertificates(certStore);
CMSProcessableInputStream msg = new CMSProcessableInputStream(is);
CMSSignedData signedData = gen.generate(msg,false);
if(tsaClient!= null)
signedData = signTimeStamps(signedData);
return signedData.getEncoded();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void signWithTSA(String passwordP12, String inputFileP12, String inputFileName, String outputFile,
String filePath, String tsaUrl, String keystorePath, String keystorePassword, String keystoreType, String selectedAlias)
throws IOException, GeneralSecurityException, SignatureException {
KeyStore keystore = null;
char[] password = passwordP12.toCharArray();
if(keystoreType.equals("PKCS12")) {
keystore = KeyStore.getInstance(keystoreType);
keystore.load(new FileInputStream(filePath + inputFileP12), password);
}
else if(keystoreType.equals("PKCS11")) {
String configString = "";
configString = new String(Files.readAllBytes(Paths.get(filePath + inputFileP12)));
ByteArrayInputStream confStream = new ByteArrayInputStream(configString.getBytes());
Provider p = new sun.security.pkcs11.SunPKCS11(confStream);
Security.addProvider(p);
keystore = KeyStore.getInstance(keystoreType,p);
keystore.load(null,password);
}
if(selectedAlias != "") {
privateKey = (PrivateKey) keystore.getKey(selectedAlias, password);
certificate = keystore.getCertificate(selectedAlias);
certificateChain = keystore.getCertificateChain(selectedAlias);
}else{
Enumeration<String> aliases = keystore.aliases();
while(aliases.hasMoreElements()) {
String alias = (String)aliases.nextElement();
System.out.println(alias);
privateKey = (PrivateKey) keystore.getKey(alias, password);
certificate = keystore.getCertificate(alias);
certificateChain = keystore.getCertificateChain(alias);
}
}
System.out.println("certificateChain ###############################");
System.out.println(certificateChain.toString());
if(!tsaUrl.isEmpty() && tsaUrl != null){
MessageDigest digest = MessageDigest.getInstance("SHA-256");
// tsaClient = new TSAClient(new URL(tsaUrl), filePath+keystorePath,
// keystorePassword,"PKCS12", digest);
tsaClient = new TSAClient(new URL(tsaUrl), "",
"", digest);
}
File inFile = new File(filePath + inputFileName);
File outFile = new File(filePath + outputFile);
new SignAndTimeStamp().signPdf(inFile, outFile);
}
Thank you very very much again.
1st pdf file does not have any revocation info, 2nd file has revocation info for signer cert. However LTV signature requires revocation info for complete chain so 2nd file still not show LTV.
For option 1 1.1 Certificate chain is a list of certificate files (Root CA cert, intermidiate issuer cert, signer cert), it is the source of trust for signer certificate. This code use it to get complete revocation info. You can get certificate chain from signature properties in Adobe Reader when open pdf file or you can download them from link in signer and issuer certificates or from CA website. 1.2 This manual has how to import cert into eToken. SafeNet Authentication Client_9.0_Users_Guide.pdf
For option 2 Certificate chain was retrieved in signWithTSA(), however the chain is not complete (length = 1) because it get chain from token which does not have complete chain. You have to put intermediate issuer CA certificate into chain at least after chain was retrieved and before revocation check process in sign().
You finally saved my life.
I export 2 .cer file from pdf (Root CA cert, intermidiate issuer cert) and import into eToken This work with original source code of PDFSigningAndTimestamp (no need https://github.com/ETDA/PDFSigningAndTimestamp/pull/13)
I'm glad to hear that.
Hi owner,
I see your code has "For LTV Enable" section but when is sign pdf the signature is not LTV enabled. I use PKCS11 with eToken.
What is possible reason ?![image](https://user-images.githubusercontent.com/61673/98319688-e5fd9200-2013-11eb-834c-e5bc6185a5fc.png)