aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Fitzek <andreas.fitzek@iaik.tugraz.at>2013-12-12 12:17:05 +0100
committerAndreas Fitzek <andreas.fitzek@iaik.tugraz.at>2013-12-12 12:17:05 +0100
commit9bc71794a49d89e1ff6adab76f5f473b94b3d348 (patch)
tree40415f1157045b794569710a68293d1f437909eb
parent1761001e82a4abcfc90d6ee93c4e867c66bedd34 (diff)
downloadpdf-as-4-9bc71794a49d89e1ff6adab76f5f473b94b3d348.tar.gz
pdf-as-4-9bc71794a49d89e1ff6adab76f5f473b94b3d348.tar.bz2
pdf-as-4-9bc71794a49d89e1ff6adab76f5f473b94b3d348.zip
Creation of PAdES signatures with local keystore
-rw-r--r--pdf-as-cli/src/main/java/at/gv/egiz/pdfas/cli/Main.java3
-rw-r--r--pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/util/CertificateUtils.java53
-rw-r--r--pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/util/package-info.java8
-rw-r--r--signature-standards/sigs-pades/src/main/java/at/gv/egiz/pdfas/sigs/pades/PAdESSignerKeystore.java154
4 files changed, 217 insertions, 1 deletions
diff --git a/pdf-as-cli/src/main/java/at/gv/egiz/pdfas/cli/Main.java b/pdf-as-cli/src/main/java/at/gv/egiz/pdfas/cli/Main.java
index eeff47c7..578175a8 100644
--- a/pdf-as-cli/src/main/java/at/gv/egiz/pdfas/cli/Main.java
+++ b/pdf-as-cli/src/main/java/at/gv/egiz/pdfas/cli/Main.java
@@ -27,6 +27,7 @@ import at.gv.egiz.pdfas.lib.api.sign.SignResult;
import at.gv.egiz.pdfas.lib.api.verify.VerifyParameter;
import at.gv.egiz.pdfas.lib.api.verify.VerifyResult;
import at.gv.egiz.pdfas.sigs.pades.PAdESSigner;
+import at.gv.egiz.pdfas.sigs.pades.PAdESSignerKeystore;
import at.gv.egiz.pdfas.sigs.pkcs7detached.PKCS7DetachedSigner;
import at.gv.egiz.sl.util.BKUSLConnector;
import at.gv.egiz.sl.util.MOAConnector;
@@ -341,7 +342,7 @@ public class Main {
keystoreKeypass = "";
}
- slConnector = new PKCS7DetachedSigner(keystoreFilename,
+ slConnector = new PAdESSignerKeystore(keystoreFilename,
keystoreAlias, keystoreStorepass, keystoreKeypass, keystoreType);
}
}
diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/util/CertificateUtils.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/util/CertificateUtils.java
new file mode 100644
index 00000000..2f4fbe10
--- /dev/null
+++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/util/CertificateUtils.java
@@ -0,0 +1,53 @@
+package at.gv.egiz.pdfas.lib.util;
+
+import iaik.asn1.structures.AlgorithmID;
+import iaik.x509.X509Certificate;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+
+public class CertificateUtils {
+ public static AlgorithmID[] getAlgorithmIDs(X509Certificate signingCertificate)
+ throws NoSuchAlgorithmException {
+ PublicKey publicKey = signingCertificate.getPublicKey();
+ String algorithm = publicKey.getAlgorithm();
+ AlgorithmID[] algorithms = new AlgorithmID[2];
+ AlgorithmID signatureAlgorithm;
+ AlgorithmID digestAlgorithm;
+
+ if ("DSA".equals(algorithm)) {
+ signatureAlgorithm = AlgorithmID.dsaWithSHA256;
+ digestAlgorithm = AlgorithmID.sha256;
+ } else if ("RSA".equals(algorithm)) {
+ signatureAlgorithm = AlgorithmID.sha256WithRSAEncryption;
+ digestAlgorithm = AlgorithmID.sha256;
+ } else if (("EC".equals(algorithm)) || ("ECDSA".equals(algorithm))) {
+
+ int fieldSize = 0;
+ if (publicKey instanceof ECPublicKey) {
+ ECParameterSpec params = ((ECPublicKey) publicKey).getParams();
+ fieldSize = params.getCurve().getField().getFieldSize();
+ }
+
+ if (fieldSize >= 512) {
+ signatureAlgorithm = AlgorithmID.ecdsa_With_SHA512;
+ digestAlgorithm = AlgorithmID.sha512;
+ } else if (fieldSize >= 256) {
+ signatureAlgorithm = AlgorithmID.ecdsa_With_SHA256;
+ digestAlgorithm = AlgorithmID.sha256;
+ } else {
+ signatureAlgorithm = AlgorithmID.ecdsa_With_SHA1;
+ digestAlgorithm = AlgorithmID.sha1;
+ }
+ } else {
+ throw new NoSuchAlgorithmException("Public key algorithm '"
+ + algorithm + "' not supported.");
+ }
+
+ algorithms[0] = signatureAlgorithm;
+ algorithms[1] = digestAlgorithm;
+
+ return algorithms;
+ }
+}
diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/util/package-info.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/util/package-info.java
new file mode 100644
index 00000000..e635fb93
--- /dev/null
+++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/util/package-info.java
@@ -0,0 +1,8 @@
+/**
+ *
+ */
+/**
+ * @author afitzek
+ *
+ */
+package at.gv.egiz.pdfas.lib.util; \ No newline at end of file
diff --git a/signature-standards/sigs-pades/src/main/java/at/gv/egiz/pdfas/sigs/pades/PAdESSignerKeystore.java b/signature-standards/sigs-pades/src/main/java/at/gv/egiz/pdfas/sigs/pades/PAdESSignerKeystore.java
new file mode 100644
index 00000000..5ae0ed76
--- /dev/null
+++ b/signature-standards/sigs-pades/src/main/java/at/gv/egiz/pdfas/sigs/pades/PAdESSignerKeystore.java
@@ -0,0 +1,154 @@
+package at.gv.egiz.pdfas.sigs.pades;
+
+import iaik.asn1.ASN1Object;
+import iaik.asn1.CodingException;
+import iaik.asn1.ObjectID;
+import iaik.asn1.SEQUENCE;
+import iaik.asn1.UTF8String;
+import iaik.asn1.structures.AlgorithmID;
+import iaik.asn1.structures.Attribute;
+import iaik.asn1.structures.ChoiceOfTime;
+import iaik.cms.ContentInfo;
+import iaik.cms.IssuerAndSerialNumber;
+import iaik.cms.SignedData;
+import iaik.cms.SignerInfo;
+import iaik.smime.ess.ESSCertID;
+import iaik.smime.ess.ESSCertIDv2;
+import iaik.x509.X509Certificate;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.pdfas.common.exceptions.PdfAsException;
+import at.gv.egiz.pdfas.common.exceptions.PdfAsSignatureException;
+import at.gv.egiz.pdfas.lib.api.sign.IPlainSigner;
+import at.gv.egiz.pdfas.lib.util.CertificateUtils;
+
+public class PAdESSignerKeystore implements IPlainSigner {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(PAdESSignerKeystore.class);
+
+ PrivateKey privKey;
+ X509Certificate cert;
+
+ public PAdESSignerKeystore(String file, String alias, String kspassword,
+ String keypassword, String type) throws PdfAsException {
+ try {
+ KeyStore ks = KeyStore.getInstance(type);
+ ks.load(new FileInputStream(file), kspassword.toCharArray());
+ privKey = (PrivateKey) ks.getKey(alias, keypassword.toCharArray());
+ cert = new X509Certificate(ks.getCertificate(alias).getEncoded());
+ } catch (Throwable e) {
+ throw new PdfAsException("Failed to get KeyStore", e);
+ }
+ }
+
+ public X509Certificate getCertificate() {
+ return cert;
+ }
+
+ private void setMimeTypeAttrib(List<Attribute> attributes, String mimeType) {
+ String oidStr = "0.4.0.1733.2.1";
+ String name = "mime-type";
+ ObjectID mimeTypeOID = new ObjectID(oidStr, name);
+
+ Attribute mimeTypeAtt = new Attribute(mimeTypeOID, new ASN1Object[] {new UTF8String(mimeType)});
+ attributes.add(mimeTypeAtt);
+ }
+
+ private void setContentTypeAttrib(List<Attribute> attributes) {
+ Attribute contentType = new Attribute(ObjectID.contentType, new ASN1Object[] {ObjectID.cms_data});
+ attributes.add(contentType);
+ }
+
+ private void setSigningCertificateAttrib(List<Attribute> attributes, X509Certificate signingCertificate) throws CertificateException, NoSuchAlgorithmException, CodingException {
+ ObjectID id;
+ ASN1Object value = new SEQUENCE();
+ AlgorithmID[] algorithms = CertificateUtils.getAlgorithmIDs(signingCertificate);
+ if (algorithms[1].equals(AlgorithmID.sha1)) {
+ id = ObjectID.signingCertificate;
+ value.addComponent(new ESSCertID(signingCertificate, true).toASN1Object());
+ }
+ else {
+ id = ObjectID.signingCertificateV2;
+ value.addComponent(new ESSCertIDv2(algorithms[1], signingCertificate, true).toASN1Object());
+ }
+ ASN1Object signingCert = new SEQUENCE();
+ signingCert.addComponent(value);
+ Attribute signingCertificateAttrib = new Attribute(id, new ASN1Object[] {signingCert});
+ attributes.add(signingCertificateAttrib);
+ }
+
+ private void setSigningTimeAttrib(List<Attribute> attributes, Date date) {
+ Attribute signingTime = new Attribute(ObjectID.signingTime, new ASN1Object[] {new ChoiceOfTime(date).toASN1Object()});
+ attributes.add(signingTime);
+ }
+
+ private void setAttributes(String mimeType, X509Certificate signingCertificate, Date signingTime,
+ SignerInfo signerInfo) throws CertificateException, NoSuchAlgorithmException, CodingException {
+ List<Attribute> attributes = new ArrayList<Attribute>();
+ setMimeTypeAttrib(attributes, mimeType);
+ setContentTypeAttrib(attributes);
+ setSigningCertificateAttrib(attributes, signingCertificate);
+ setSigningTimeAttrib(attributes, signingTime);
+ Attribute[] attributeArray = attributes.toArray(new Attribute[attributes.size()]);
+ signerInfo.setSignedAttributes(attributeArray);
+ }
+
+ public byte[] sign(byte[] input, int[] byteRange) throws PdfAsException {
+ try {
+ IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(cert);
+
+ AlgorithmID[] algorithms = CertificateUtils.getAlgorithmIDs(cert);
+
+ SignerInfo signer1 = new SignerInfo(issuer, algorithms[1],
+ algorithms[0], privKey);
+
+ SignedData si = new SignedData(input, SignedData.EXPLICIT);
+ si.addCertificates(new Certificate[] { cert });
+ setAttributes("application/pdf", cert, new Date(), signer1);
+ si.addSignerInfo(signer1);
+ InputStream dataIs = si.getInputStream();
+ byte[] buf = new byte[1024];
+ int r;
+ while ((r = dataIs.read(buf)) > 0)
+ ; // skip data
+ ContentInfo ci = new ContentInfo(si);
+
+ return ci.getEncoded();
+ } catch (NoSuchAlgorithmException e) {
+ throw new PdfAsSignatureException("Failed to generate Signature", e);
+ } catch (iaik.cms.CMSException e) {
+ throw new PdfAsSignatureException("Failed to generate Signature", e);
+ } catch (IOException e) {
+ throw new PdfAsSignatureException("Failed to generate Signature", e);
+ } catch (CertificateException e) {
+ throw new PdfAsSignatureException("Failed to generate Signature", e);
+ } catch (CodingException e) {
+ throw new PdfAsSignatureException("Failed to generate Signature", e);
+ }
+ }
+
+ public String getPDFSubFilter() {
+ return PDSignature.SUBFILTER_ETSI_CADES_DETACHED.getName();
+ }
+
+ public String getPDFFilter() {
+ return PDSignature.FILTER_ADOBE_PPKLITE.getName();
+ }
+
+} \ No newline at end of file