You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
333 lines
13 KiB
333 lines
13 KiB
import java.io.BufferedReader;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileNotFoundException;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStreamReader;
|
|
import java.net.URL;
|
|
import java.net.URLDecoder;
|
|
import java.security.CodeSource;
|
|
import java.security.KeyStore;
|
|
import java.security.KeyStoreException;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.security.PrivateKey;
|
|
import java.security.Provider;
|
|
import java.security.ProviderException;
|
|
import java.security.Security;
|
|
import java.security.UnrecoverableKeyException;
|
|
import java.security.cert.Certificate;
|
|
import java.security.cert.CertificateException;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.ResourceBundle;
|
|
|
|
import sun.security.pkcs11.SunPKCS11;
|
|
|
|
import com.lowagie.text.pdf.PdfReader;
|
|
import com.lowagie.text.pdf.PdfSignatureAppearance;
|
|
import com.lowagie.text.pdf.PdfStamper;
|
|
|
|
/*
|
|
import com.itextpdf.text.pdf.PdfReader;
|
|
import com.itextpdf.text.pdf.PdfSignatureAppearance;
|
|
import com.itextpdf.text.pdf.PdfStamper;
|
|
*/
|
|
|
|
/**
|
|
*
|
|
* @author Jan Peter Stotz
|
|
*
|
|
*/
|
|
public class JPdfSign {
|
|
|
|
private static PrivateKey privateKey;
|
|
|
|
private static Certificate[] certificateChain;
|
|
|
|
private static ResourceBundle bundle = ResourceBundle.getBundle("strings");
|
|
|
|
private static String PRODUCTNAME = bundle.getString("productname");
|
|
|
|
private static String VERSION = bundle.getString("version");
|
|
|
|
private static String JAR_FILENAME = bundle.getString("jar-filename");
|
|
|
|
public static void main(String[] args) {
|
|
// for (int i = 0; i < args.length; i++) {
|
|
// System.out.println("arg[" + i + "] :" + args[i]);
|
|
// }
|
|
if (args.length < 2)
|
|
showUsage();
|
|
|
|
try {
|
|
|
|
String pkcs12FileName = args[0].trim();
|
|
String pdfInputFileName = args[1];
|
|
String pdfOutputFileName = args[2];
|
|
boolean usePKCS12 = !(pkcs12FileName.equals("-PKCS11"));
|
|
|
|
String passwdfile = "";
|
|
if (args.length == 4) {
|
|
passwdfile = args[3];
|
|
}
|
|
// System.out.println("");
|
|
// System.out.println("pdfInputFileName : " + pdfInputFileName);
|
|
// System.out.println("pdfOutputFileName: " + pdfOutputFileName);
|
|
|
|
if (usePKCS12)
|
|
readPrivateKeyFromPKCS12(pkcs12FileName, passwdfile);
|
|
else
|
|
readPrivateKeyFromPKCS11();
|
|
|
|
PdfReader reader = null;
|
|
try {
|
|
reader = new PdfReader(pdfInputFileName);
|
|
} catch (IOException e) {
|
|
System.err
|
|
.println("An unknown error accoured while opening the input PDF file: \""
|
|
+ pdfInputFileName + "\"");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
}
|
|
FileOutputStream fout = null;
|
|
try {
|
|
fout = new FileOutputStream(pdfOutputFileName);
|
|
} catch (FileNotFoundException e) {
|
|
System.err
|
|
.println("An unknown error accoured while opening the output PDF file: \""
|
|
+ pdfOutputFileName + "\"");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
}
|
|
PdfStamper stp = null;
|
|
try {
|
|
stp = PdfStamper.createSignature(reader, fout, '\0', null, true);
|
|
PdfSignatureAppearance sap = stp.getSignatureAppearance();
|
|
sap.setCrypto(privateKey, certificateChain, null, PdfSignatureAppearance.WINCER_SIGNED);
|
|
// sap.setCrypto(privateKey, certificateChain, null, null);
|
|
// sap.setReason("I'm the author");
|
|
// sap.setLocation("Lisbon");
|
|
// sap.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1,
|
|
// null);
|
|
sap.setCertified(true);
|
|
stp.close();
|
|
} catch (Exception e) {
|
|
System.err
|
|
.println("An unknown error accoured while signing the PDF file:");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
}
|
|
} catch (KeyStoreException kse) {
|
|
System.err
|
|
.println("An unknown error accoured while initializing the KeyStore instance:");
|
|
kse.printStackTrace();
|
|
System.exit(-1);
|
|
}
|
|
}
|
|
|
|
private static void readPrivateKeyFromPKCS11() throws KeyStoreException {
|
|
// Initialize PKCS#11 provider from config file
|
|
String configFileName = getConfigFilePath("pkcs11.cfg");
|
|
|
|
Provider p = null;
|
|
try {
|
|
p = new SunPKCS11(configFileName);
|
|
Security.addProvider(p);
|
|
} catch (ProviderException e) {
|
|
System.err
|
|
.println("Unable to load PKCS#11 provider with config file: "
|
|
+ configFileName);
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
}
|
|
String pkcs11PIN = "000000";
|
|
System.out.print("Please enter the smartcard pin: ");
|
|
try {
|
|
BufferedReader in = new BufferedReader(new InputStreamReader(
|
|
System.in));
|
|
pkcs11PIN = in.readLine();
|
|
// System.out.println(pkcs11PIN);
|
|
// System.out.println(pkcs11PIN.length());
|
|
} catch (Exception e) {
|
|
System.err
|
|
.println("An unknown error accoured while reading the PIN:");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
}
|
|
KeyStore ks = null;
|
|
try {
|
|
ks = KeyStore.getInstance("pkcs11", p);
|
|
ks.load(null, pkcs11PIN.toCharArray());
|
|
} catch (NoSuchAlgorithmException e) {
|
|
System.err
|
|
.println("An unknown error accoured while reading the PKCS#11 smartcard:");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
} catch (CertificateException e) {
|
|
System.err
|
|
.println("An unknown error accoured while reading the PKCS#11 smartcard:");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
} catch (IOException e) {
|
|
System.err
|
|
.println("An unknown error accoured while reading the PKCS#11 smartcard:");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
}
|
|
|
|
String alias = "";
|
|
try {
|
|
alias = (String) ks.aliases().nextElement();
|
|
privateKey = (PrivateKey) ks.getKey(alias, pkcs11PIN.toCharArray());
|
|
} catch (NoSuchElementException e) {
|
|
System.err
|
|
.println("An unknown error accoured while retrieving the private key:");
|
|
System.err
|
|
.println("The selected PKCS#12 file does not contain any private keys.");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
} catch (NoSuchAlgorithmException e) {
|
|
System.err
|
|
.println("An unknown error accoured while retrieving the private key:");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
} catch (UnrecoverableKeyException e) {
|
|
System.err
|
|
.println("An unknown error accoured while retrieving the private key:");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
}
|
|
certificateChain = ks.getCertificateChain(alias);
|
|
}
|
|
|
|
protected static void readPrivateKeyFromPKCS12(String pkcs12FileName, String pwdFile)
|
|
throws KeyStoreException {
|
|
String pkcs12Password = "";
|
|
KeyStore ks = null;
|
|
if (!pwdFile.equals("")) {
|
|
try {
|
|
FileInputStream pwdfis = new FileInputStream(pwdFile);
|
|
byte[] pwd = new byte[1024];
|
|
try {
|
|
do {
|
|
int r = pwdfis.read(pwd);
|
|
if (r < 0) {
|
|
break;
|
|
}
|
|
pkcs12Password += new String(pwd);
|
|
pkcs12Password = pkcs12Password.trim();
|
|
} while (pwdfis.available() > 0);
|
|
pwdfis.close();
|
|
} catch (IOException ex) {
|
|
System.err
|
|
.println("Can't read password file: " + pwdFile);
|
|
}
|
|
} catch (FileNotFoundException fnfex) {
|
|
System.err
|
|
.println("Password file not found: " + pwdFile);
|
|
}
|
|
} else {
|
|
System.out.print("Please enter the password for \"" + pkcs12FileName
|
|
+ "\": ");
|
|
try {
|
|
BufferedReader in = new BufferedReader(new InputStreamReader(
|
|
System.in));
|
|
pkcs12Password = in.readLine();
|
|
} catch (Exception e) {
|
|
System.err
|
|
.println("An unknown error accoured while reading the password:");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
}
|
|
}
|
|
|
|
try {
|
|
ks = KeyStore.getInstance("pkcs12");
|
|
ks.load(new FileInputStream(pkcs12FileName), pkcs12Password
|
|
.toCharArray());
|
|
} catch (NoSuchAlgorithmException e) {
|
|
System.err
|
|
.println("An unknown error accoured while reading the PKCS#12 file:");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
} catch (CertificateException e) {
|
|
System.err
|
|
.println("An unknown error accoured while reading the PKCS#12 file:");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
} catch (FileNotFoundException e) {
|
|
System.err.println("Unable to open the PKCS#12 keystore file \""
|
|
+ pkcs12FileName + "\":");
|
|
System.err
|
|
.println("The file does not exists or missing read permission.");
|
|
System.exit(-1);
|
|
} catch (IOException e) {
|
|
System.err
|
|
.println("An unknown error accoured while reading the PKCS#12 file:");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
}
|
|
String alias = "";
|
|
try {
|
|
alias = (String) ks.aliases().nextElement();
|
|
privateKey = (PrivateKey) ks.getKey(alias, pkcs12Password
|
|
.toCharArray());
|
|
} catch (NoSuchElementException e) {
|
|
System.err
|
|
.println("An unknown error accoured while retrieving the private key:");
|
|
System.err
|
|
.println("The selected PKCS#12 file does not contain any private keys.");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
} catch (NoSuchAlgorithmException e) {
|
|
System.err
|
|
.println("An unknown error accoured while retrieving the private key:");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
} catch (UnrecoverableKeyException e) {
|
|
System.err
|
|
.println("An unknown error accoured while retrieving the private key:");
|
|
e.printStackTrace();
|
|
System.exit(-1);
|
|
}
|
|
certificateChain = ks.getCertificateChain(alias);
|
|
}
|
|
|
|
protected static String getConfigFilePath(String configFilename) {
|
|
CodeSource source = JPdfSign.class.getProtectionDomain()
|
|
.getCodeSource();
|
|
URL url = source.getLocation();
|
|
|
|
String jarPath = URLDecoder.decode(url.getFile());
|
|
File f = new File(jarPath);
|
|
try {
|
|
jarPath = f.getCanonicalPath();
|
|
} catch (IOException e) {
|
|
}
|
|
if (!f.isDirectory()) {
|
|
f = new File(jarPath);
|
|
jarPath = f.getParent();
|
|
}
|
|
System.out.println(jarPath);
|
|
if (jarPath.length() > 0) {
|
|
return jarPath + File.separator + configFilename;
|
|
} else
|
|
return configFilename;
|
|
}
|
|
|
|
public static void showUsage() {
|
|
System.out.println("jPdfSign v" + VERSION
|
|
+ " by Jan Peter Stotz - jpstotz@gmx.de\n");
|
|
System.out.println(PRODUCTNAME + " usage:");
|
|
System.out
|
|
.println("\nFor using a PKCS#12 (.p12) file as signature certificate and private key source:");
|
|
System.out.print("\tjava -jar " + JAR_FILENAME);
|
|
System.out
|
|
.println(" pkcs12FileName pdfInputFileName pdfOutputFileName");
|
|
System.out
|
|
.println("\nFor using a PKCS#11 smartcard as signature certificate and private key source:");
|
|
System.out.print("\tjava -jar" + JAR_FILENAME);
|
|
System.out.println(" -PKCS11 pdfInputFileName pdfOutputFileName");
|
|
System.exit(0);
|
|
}
|
|
}
|