feat: udpates
This commit is contained in:
@@ -1,10 +1,15 @@
|
|||||||
package me.hatter.tool.signpdf.main;
|
package me.hatter.tool.signpdf.main;
|
||||||
|
|
||||||
import me.hatter.tool.signpdf.CreateSignature;
|
|
||||||
import me.hatter.tool.signpdf.options.SignOptions;
|
import me.hatter.tool.signpdf.options.SignOptions;
|
||||||
|
import me.hatter.tool.signpdf.sign.CreateSignature;
|
||||||
|
import me.hatter.tool.signpdf.sign.SigUtils;
|
||||||
|
import me.hatter.tool.signpdf.time.TSAClient;
|
||||||
import me.hatter.tools.commons.io.RFile;
|
import me.hatter.tools.commons.io.RFile;
|
||||||
import me.hatter.tools.commons.security.cert.X509CertUtil;
|
import me.hatter.tools.commons.security.cert.X509CertUtil;
|
||||||
import me.hatter.tools.commons.security.key.KeyUtil;
|
import me.hatter.tools.commons.security.key.KeyUtil;
|
||||||
|
import me.hatter.tools.commons.string.StringUtil;
|
||||||
|
import org.bouncycastle.operator.ContentSigner;
|
||||||
|
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
@@ -18,7 +23,11 @@ public class SignPdfMain {
|
|||||||
signOptions.setName("Example User");
|
signOptions.setName("Example User");
|
||||||
signOptions.setLocation("Hangzhou, ZJ");
|
signOptions.setLocation("Hangzhou, ZJ");
|
||||||
signOptions.setReason("Testing");
|
signOptions.setReason("Testing");
|
||||||
final String tsaUrl = "https://hatter.ink/ca/sign_timestamp.action";
|
|
||||||
|
final File inFile = new File("Resume.pdf");
|
||||||
|
final String name = inFile.getName();
|
||||||
|
final String substring = name.substring(0, name.lastIndexOf('.'));
|
||||||
|
final File outFile = new File(inFile.getParent(), substring + "_signed.pdf");
|
||||||
|
|
||||||
final List<X509Certificate> certs = X509CertUtil.parseX509CertificateList(
|
final List<X509Certificate> certs = X509CertUtil.parseX509CertificateList(
|
||||||
RFile.from("__certs.pem").string()
|
RFile.from("__certs.pem").string()
|
||||||
@@ -28,15 +37,12 @@ public class SignPdfMain {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final X509Certificate[] chain = certs.toArray(new X509Certificate[0]);
|
final X509Certificate[] chain = certs.toArray(new X509Certificate[0]);
|
||||||
|
final String signatureAlgorithm = SigUtils.getSignatureAlgorithm(chain[0]);
|
||||||
final CreateSignature signing = new CreateSignature(signOptions, chain, privateKey);
|
final ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).build(privateKey);
|
||||||
|
final CreateSignature signing = new CreateSignature(signOptions, chain, contentSigner);
|
||||||
// signing.setExternalSigning(true);
|
// signing.setExternalSigning(true);
|
||||||
|
|
||||||
final File inFile = new File("Resume.pdf");
|
final String tsaUrl = StringUtil.def(signOptions.getTsaUrl(), TSAClient.DEFAULT_TSA_URL);
|
||||||
final String name = inFile.getName();
|
|
||||||
final String substring = name.substring(0, name.lastIndexOf('.'));
|
|
||||||
|
|
||||||
final File outFile = new File(inFile.getParent(), substring + "_signed.pdf");
|
|
||||||
signing.signDetached(inFile, outFile, tsaUrl);
|
signing.signDetached(inFile, outFile, tsaUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ public class SignOptions {
|
|||||||
private String name;
|
private String name;
|
||||||
private String location;
|
private String location;
|
||||||
private String reason;
|
private String reason;
|
||||||
|
private String tsaUrl;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
@@ -28,4 +29,12 @@ public class SignOptions {
|
|||||||
public void setReason(String reason) {
|
public void setReason(String reason) {
|
||||||
this.reason = reason;
|
this.reason = reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTsaUrl() {
|
||||||
|
return tsaUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTsaUrl(String tsaUrl) {
|
||||||
|
this.tsaUrl = tsaUrl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.hatter.tool.signpdf;
|
package me.hatter.tool.signpdf.sign;
|
||||||
|
|
||||||
import org.apache.pdfbox.io.IOUtils;
|
import org.apache.pdfbox.io.IOUtils;
|
||||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
package me.hatter.tool.signpdf;
|
package me.hatter.tool.signpdf.sign;
|
||||||
|
|
||||||
import me.hatter.tool.signpdf.options.SignOptions;
|
import me.hatter.tool.signpdf.options.SignOptions;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.ExternalSigningSupport;
|
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.ExternalSigningSupport;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
|
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
|
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
|
||||||
|
import org.bouncycastle.operator.ContentSigner;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.UnrecoverableKeyException;
|
import java.security.UnrecoverableKeyException;
|
||||||
import java.security.cert.Certificate;
|
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
@@ -33,9 +32,9 @@ import java.util.Calendar;
|
|||||||
public class CreateSignature extends CreateSignatureBase {
|
public class CreateSignature extends CreateSignatureBase {
|
||||||
private final SignOptions signOptions;
|
private final SignOptions signOptions;
|
||||||
|
|
||||||
public CreateSignature(SignOptions signOptions, X509Certificate[] certificateChain, PrivateKey privateKey)
|
public CreateSignature(SignOptions signOptions, X509Certificate[] certificateChain, ContentSigner contentSigner)
|
||||||
throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, CertificateException, IOException {
|
throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, CertificateException, IOException {
|
||||||
super(certificateChain, privateKey);
|
super(certificateChain, contentSigner);
|
||||||
this.signOptions = signOptions;
|
this.signOptions = signOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package me.hatter.tool.signpdf;
|
package me.hatter.tool.signpdf.sign;
|
||||||
|
|
||||||
|
import me.hatter.tool.signpdf.time.ValidationTimeStamp;
|
||||||
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
|
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
|
||||||
import org.bouncycastle.cert.jcajce.JcaCertStore;
|
import org.bouncycastle.cert.jcajce.JcaCertStore;
|
||||||
import org.bouncycastle.cms.CMSException;
|
import org.bouncycastle.cms.CMSException;
|
||||||
@@ -8,49 +9,30 @@ import org.bouncycastle.cms.CMSSignedDataGenerator;
|
|||||||
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
|
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
|
||||||
import org.bouncycastle.operator.ContentSigner;
|
import org.bouncycastle.operator.ContentSigner;
|
||||||
import org.bouncycastle.operator.OperatorCreationException;
|
import org.bouncycastle.operator.OperatorCreationException;
|
||||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
|
||||||
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
|
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.security.*;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.interfaces.ECPublicKey;
|
|
||||||
import java.security.interfaces.RSAPublicKey;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
// https://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/
|
// https://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/
|
||||||
// org/apache/pdfbox/examples/signature/CreateSignatureBase.java?view=co
|
// org/apache/pdfbox/examples/signature/CreateSignatureBase.java?view=co
|
||||||
public abstract class CreateSignatureBase implements SignatureInterface {
|
public abstract class CreateSignatureBase implements SignatureInterface {
|
||||||
private PrivateKey privateKey;
|
private final ContentSigner contentSigner;
|
||||||
private X509Certificate[] certificateChain;
|
private final X509Certificate[] certificateChain;
|
||||||
private String tsaUrl;
|
private String tsaUrl;
|
||||||
private boolean externalSigning;
|
private boolean externalSigning;
|
||||||
|
|
||||||
public CreateSignatureBase(X509Certificate[] certificateChain, PrivateKey privateKey)
|
public CreateSignatureBase(X509Certificate[] certificateChain, ContentSigner contentSigner)
|
||||||
throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, IOException, CertificateException {
|
throws CertificateException {
|
||||||
// grabs the first alias from the keystore and get the private key. An
|
this.contentSigner = contentSigner;
|
||||||
// alternative method or constructor could be used for setting a specific
|
|
||||||
// alias that should be used.
|
|
||||||
this.privateKey = privateKey;
|
|
||||||
this.certificateChain = certificateChain;
|
this.certificateChain = certificateChain;
|
||||||
|
final X509Certificate firstCertificate = certificateChain[0];
|
||||||
final X509Certificate cert = certificateChain[0];
|
firstCertificate.checkValidity();
|
||||||
cert.checkValidity();
|
SigUtils.checkCertificateUsage(firstCertificate);
|
||||||
SigUtils.checkCertificateUsage(cert);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void setPrivateKey(PrivateKey privateKey) {
|
|
||||||
this.privateKey = privateKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void setCertificateChain(final X509Certificate[] certificateChain) {
|
|
||||||
this.certificateChain = certificateChain;
|
|
||||||
}
|
|
||||||
|
|
||||||
public X509Certificate[] getCertificateChain() {
|
|
||||||
return certificateChain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTsaUrl(String tsaUrl) {
|
public void setTsaUrl(String tsaUrl) {
|
||||||
@@ -62,20 +44,7 @@ public abstract class CreateSignatureBase implements SignatureInterface {
|
|||||||
try {
|
try {
|
||||||
final CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
|
final CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
|
||||||
final X509Certificate cert = certificateChain[0];
|
final X509Certificate cert = certificateChain[0];
|
||||||
// TODO use customer signer
|
|
||||||
final boolean isEcPublicKey = cert.getPublicKey() instanceof ECPublicKey;
|
|
||||||
final boolean isRsaPublicKey = cert.getPublicKey() instanceof RSAPublicKey;
|
|
||||||
|
|
||||||
final String signatureAlgorithm;
|
|
||||||
if (isEcPublicKey) {
|
|
||||||
signatureAlgorithm = "SHA256WithECDSA";
|
|
||||||
} else if (isRsaPublicKey) {
|
|
||||||
signatureAlgorithm = "SHA256WithRSA";
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("Supported algorithm: " + cert.getPublicKey().getClass());
|
|
||||||
}
|
|
||||||
final ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm)
|
|
||||||
.build(privateKey);
|
|
||||||
gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
|
gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
|
||||||
new JcaDigestCalculatorProviderBuilder().build()).build(contentSigner, cert));
|
new JcaDigestCalculatorProviderBuilder().build()).build(contentSigner, cert));
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.hatter.tool.signpdf;
|
package me.hatter.tool.signpdf.sign;
|
||||||
|
|
||||||
import me.hatter.tools.commons.log.LogTool;
|
import me.hatter.tools.commons.log.LogTool;
|
||||||
import me.hatter.tools.commons.log.LogTools;
|
import me.hatter.tools.commons.log.LogTools;
|
||||||
@@ -13,6 +13,8 @@ import org.bouncycastle.asn1.x509.KeyPurposeId;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.cert.CertificateParsingException;
|
import java.security.cert.CertificateParsingException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.security.interfaces.ECPublicKey;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.SortedMap;
|
import java.util.SortedMap;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
@@ -28,9 +30,25 @@ import java.util.TreeMap;
|
|||||||
public class SigUtils {
|
public class SigUtils {
|
||||||
private static final LogTool LOG = LogTools.getLogTool(SigUtils.class);
|
private static final LogTool LOG = LogTools.getLogTool(SigUtils.class);
|
||||||
|
|
||||||
|
public static final String SIGNATURE_ALGORITHM_SHA256_WITH_ECDSA = "SHA256WithECDSA";
|
||||||
|
public static final String SIGNATURE_ALGORITHM_SHA256_WITH_RSA = "SHA256WithRSA";
|
||||||
|
|
||||||
private SigUtils() {
|
private SigUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getSignatureAlgorithm(X509Certificate cert) {
|
||||||
|
final boolean isEcPublicKey = cert.getPublicKey() instanceof ECPublicKey;
|
||||||
|
final boolean isRsaPublicKey = cert.getPublicKey() instanceof RSAPublicKey;
|
||||||
|
|
||||||
|
if (isEcPublicKey) {
|
||||||
|
return SIGNATURE_ALGORITHM_SHA256_WITH_ECDSA;
|
||||||
|
} else if (isRsaPublicKey) {
|
||||||
|
return SIGNATURE_ALGORITHM_SHA256_WITH_RSA;
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Supported algorithm: " + cert.getPublicKey().getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the access permissions granted for this document in the DocMDP transform parameters
|
* Get the access permissions granted for this document in the DocMDP transform parameters
|
||||||
* dictionary. Details are described in the table "Entries in the DocMDP transform parameters
|
* dictionary. Details are described in the table "Entries in the DocMDP transform parameters
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.hatter.tool.signpdf;
|
package me.hatter.tool.signpdf.time;
|
||||||
|
|
||||||
import me.hatter.tools.commons.io.RStream;
|
import me.hatter.tools.commons.io.RStream;
|
||||||
import me.hatter.tools.commons.log.LogTool;
|
import me.hatter.tools.commons.log.LogTool;
|
||||||
@@ -29,6 +29,8 @@ import java.security.SecureRandom;
|
|||||||
public class TSAClient {
|
public class TSAClient {
|
||||||
private static final LogTool LOG = LogTools.getLogTool(TSAClient.class);
|
private static final LogTool LOG = LogTools.getLogTool(TSAClient.class);
|
||||||
|
|
||||||
|
public static final String DEFAULT_TSA_URL = "https://hatter.ink/ca/sign_timestamp.action";
|
||||||
|
|
||||||
private final URL url;
|
private final URL url;
|
||||||
private final String username;
|
private final String username;
|
||||||
private final String password;
|
private final String password;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.hatter.tool.signpdf;
|
package me.hatter.tool.signpdf.time;
|
||||||
|
|
||||||
import org.apache.pdfbox.io.IOUtils;
|
import org.apache.pdfbox.io.IOUtils;
|
||||||
import org.bouncycastle.asn1.*;
|
import org.bouncycastle.asn1.*;
|
||||||
Reference in New Issue
Block a user