Digital signatures - chapter 4
These examples were written in the context of the white paper Digital Signatures for PDF documents.
c4_03_signwithpkcs11sc
JAVA
JAVA
/*
* This class is part of the white paper entitled
* "Digital Signatures for PDF documents"
* written by Bruno Lowagie
*
* For more info, go to: http://itextpdf.com/learn
*/
package signatures.chapter4;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.security.pkcs11.SunPKCS11;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.log.LoggerFactory;
import com.itextpdf.text.log.SysoLogger;
import com.itextpdf.text.pdf.security.CrlClient;
import com.itextpdf.text.pdf.security.CrlClientOnline;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.OcspClient;
import com.itextpdf.text.pdf.security.OcspClientBouncyCastle;
public class C4_03_SignWithPKCS11SC extends C4_02_SignWithPKCS11USB {
public static final String SRC = "src/main/resources/hello.pdf";
public static final String DEST = "results/chapter4/hello_smartcard_%s.pdf";
public static final String DLL = "c:/windows/system32/beidpkcs11.dll";
public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
LoggerFactory.getInstance().setLogger(new SysoLogger());
String config = "name=beid\n" +
"library=" + DLL + "\n" +
"slotListIndex = " + getSlotsWithTokens(DLL)[0];
ByteArrayInputStream bais = new ByteArrayInputStream(config.getBytes());
Provider providerPKCS11 = new SunPKCS11(bais);
Security.addProvider(providerPKCS11);
BouncyCastleProvider providerBC = new BouncyCastleProvider();
Security.addProvider(providerBC);
KeyStore ks = KeyStore.getInstance("PKCS11");
ks.load(null, null);
Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) {
System.out.println(aliases.nextElement());
}
smartcardsign(providerPKCS11.getName(), ks, "Authentication");
smartcardsign(providerPKCS11.getName(), ks, "Signature");
}
public static void smartcardsign(String provider, KeyStore ks, String alias) throws GeneralSecurityException, IOException, DocumentException {
PrivateKey pk = (PrivateKey)ks.getKey(alias, null);
Certificate[] chain = ks.getCertificateChain(alias);
OcspClient ocspClient = new OcspClientBouncyCastle();
List<CrlClient> crlList = new ArrayList<CrlClient>();
crlList.add(new CrlClientOnline(chain));
C4_03_SignWithPKCS11SC app = new C4_03_SignWithPKCS11SC();
app.sign(SRC, String.format(DEST, alias), chain, pk, DigestAlgorithms.SHA256, provider, CryptoStandard.CMS,
"Test", "Ghent", crlList, ocspClient, null, 0);
}
}
C#
C#
/*
* This class is part of the white paper entitled
* "Digital Signatures for PDF documents"
* written by Bruno Lowagie
*
* For more info, go to: http://itextpdf.com/learn
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using Cryptware.NCryptoki;
using Org.BouncyCastle.Security;
using iTextSharp.text;
using iTextSharp.text.log;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
using X509Certificate = Org.BouncyCastle.X509.X509Certificate;
namespace signatures.chapter4 {
class CryptokiPrivateKeySignature : IExternalSignature
{
private readonly Session session;
RSAPrivateKey privateKey;
public CryptokiPrivateKeySignature(Session session, String alias) {
this.session = session;
CryptokiCollection template = new CryptokiCollection();
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PRIVATE_KEY));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_KEY_TYPE, Key.CKK_RSA));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, alias));
privateKey = (RSAPrivateKey)session.Objects.Find(template);
}
public String GetHashAlgorithm() {
return "SHA1";
}
public String GetEncryptionAlgorithm() {
return "RSA";
}
public byte[] Sign(byte[] message) {
session.SignInit(Mechanism.SHA1_RSA_PKCS, privateKey);
return session.Sign(message);
}
}
class C4_03_SignWithPKCS11SC {
public const String SRC = "../../../../resources/hello.pdf";
public const String DEST = "../../../../results/chapter4/hello_smartcard_{0}.pdf";
public const String DLL = "c:/windows/system32/beidpkcs11.dll";
public void Sign(String src, String dest, ICollection<X509Certificate> chain, Session session, String alias,
String digestAlgorithm, CryptoStandard subfilter, String reason, String location,
ICollection<ICrlClient> crlList, IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize) {
// Creating the reader and the stamper
PdfReader reader = null;
PdfStamper stamper = null;
FileStream os = null;
try {
reader = new PdfReader(src);
os = new FileStream(dest, FileMode.Create);
stamper = PdfStamper.CreateSignature(reader, os, '\0');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.Reason = reason;
appearance.Location = location;
appearance.SetVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
// Creating the signature
IExternalSignature pks = new CryptokiPrivateKeySignature(session, alias);
MakeSignature.SignDetached(appearance, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
} finally {
if (reader != null)
reader.Close();
if (stamper != null)
stamper.Close();
if (os != null)
os.Close();
}
}
static void Main(String[] args) {
LoggerFactory.GetInstance().SetLogger(new SysoLogger());
// Creates a Cryptoki object related to the specific PKCS#11 native library
Cryptoki cryptoki = new Cryptoki("beidpkcs11.dll");
cryptoki.Initialize();
// Reads the set of slots containing a token
SlotList slots = cryptoki.Slots;
if(slots.Count == 0) {
Console.WriteLine("No slot available");
return;
}
// Gets the first slot available
Slot slot = slots[0];
if(!slot.IsTokenPresent) {
Console.WriteLine("No token inserted in the slot: " + slots[0].Info.Description);
return;
}
// Gets the first token available
Token token = slot.Token;
// Opens a read/write serial session
Session session =
token.OpenSession(Session.CKF_SERIAL_SESSION | Session.CKF_RW_SESSION, null, null);
// Executes the login passing the user PIN
//int nRes = session.Login(Session.CKU_USER, "0000");
/*if (nRes != 0) {
Console.WriteLine("Wrong PIN");
return;
}*/
Smartcardsign(session, "Authentication");
Smartcardsign(session, "Signature");
// Logouts and closes the session
session.Logout();
session.Close();
cryptoki.Finalize(IntPtr.Zero);
}
public static void Smartcardsign(Session session, String alias) {
// Searchs for an RSA certificate object
// Sets the template with its attributes
CryptokiCollection template = new CryptokiCollection();
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_CERTIFICATE));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CERTIFICATE_TYPE, Certificate.CKC_X_509));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, alias));
Cryptware.NCryptoki.X509Certificate nCert = (Cryptware.NCryptoki.X509Certificate)session.Objects.Find(template);
X509Certificate2 cert = Utils.ConvertCertificate(nCert);
ICollection<X509Certificate> chain = new List<X509Certificate>();
X509Chain x509chain = new X509Chain();
x509chain.Build(cert);
foreach (X509ChainElement x509ChainElement in x509chain.ChainElements) {
chain.Add(DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate));
}
IOcspClient ocspClient = new OcspClientBouncyCastle();
List<ICrlClient> crlList = new List<ICrlClient>();
crlList.Add(new CrlClientOnline(chain));
C4_03_SignWithPKCS11SC app = new C4_03_SignWithPKCS11SC();
app.Sign(SRC, String.Format(DEST, alias), chain, session, alias, DigestAlgorithms.SHA256, CryptoStandard.CMS,
"Test", "Ghent", crlList, ocspClient, null, 0);
}
}
}
c4_07_clientserversigning
JAVA
JAVA
package signatures.chapter4;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.ExceptionConverter;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
public class C4_07_ClientServerSigning {
public static final String SRC = "src/main/resources/hello.pdf";
public static final String DEST = "results/chapter4/hello_server.pdf";
public static final String CERT = "http://demo.itextsupport.com/SigningApp/itextpdf.cer";
public class ServerSignature implements ExternalSignature {
public static final String SIGN = "http://demo.itextsupport.com/SigningApp/signbytes";
public String getHashAlgorithm() {
return DigestAlgorithms.SHA256;
}
public String getEncryptionAlgorithm() {
return "RSA";
}
public byte[] sign(byte[] message) throws GeneralSecurityException {
try {
URL url = new URL(SIGN);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.connect();
OutputStream os = conn.getOutputStream();
os.write(message);
os.flush();
os.close();
InputStream is = conn.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[1];
int read;
while ((read = is.read(b)) != -1) {
baos.write(b, 0, read);
}
is.close();
return baos.toByteArray();
} catch (IOException e) {
throw new ExceptionConverter(e);
}
}
}
public void sign(String src, String dest,
Certificate[] chain,
CryptoStandard subfilter,
String reason, String location)
throws GeneralSecurityException, IOException, DocumentException {
// Creating the reader and the stamper
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
// Creating the signature
ExternalDigest digest = new BouncyCastleDigest();
ExternalSignature signature = new ServerSignature();
MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, subfilter);
}
public static void main(String[] args) throws GeneralSecurityException, IOException, DocumentException {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
URL certUrl = new URL(CERT);
Certificate[] chain = new Certificate[1];
chain[0] = factory.generateCertificate(certUrl.openStream());
C4_07_ClientServerSigning app = new C4_07_ClientServerSigning();
app.sign(SRC, DEST, chain, CryptoStandard.CMS, "Test", "Ghent");
}
}
C#
C#
/*
* This class is part of the white paper entitled
* "Digital Signatures for PDF documents"
* written by Bruno Lowagie
*
* For more info, go to: http://itextpdf.com/learn
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using Org.BouncyCastle.X509;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
namespace signatures.chapter4 {
class C4_07_ClientServerSigning {
public const String SRC = "../../../../resources/hello.pdf";
public const String DEST = "../../../../results/chapter4/hello_server.pdf";
public const String CERT = "http://demo.itextsupport.com/SigningApp/itextpdf.cer";
public class ServerSignature : IExternalSignature {
public const String SIGN = "http://demo.itextsupport.com/SigningApp/signbytes";
public String GetHashAlgorithm() {
return DigestAlgorithms.SHA256;
}
public String GetEncryptionAlgorithm() {
return "RSA";
}
public byte[] Sign(byte[] message) {
MemoryStream baos = new MemoryStream();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(SIGN);
request.Method = "POST";
Stream ostream = request.GetRequestStream();
ostream.Write(message, 0, message.Length);
ostream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream istream = response.GetResponseStream();
byte[] b = new byte[0x1000];
int read;
while ((read = istream.Read(b, 0, b.Length)) != 0)
baos.Write(b, 0, read);
istream.Close();
return baos.ToArray();
}
}
public void Sign(String src, String dest, ICollection<X509Certificate> chain,
CryptoStandard subfilter, String reason, String location) {
// Creating the reader and the stamper
PdfReader reader = new PdfReader(src);
FileStream os = new FileStream(dest, FileMode.Create);
PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.Reason = reason;
appearance.Location = location;
appearance.SetVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
// Creating the signature
IExternalSignature signature = new ServerSignature();
MakeSignature.SignDetached(appearance, signature, chain, null, null, null, 0, subfilter);
}
public static void Main(String[] args) {
X509CertificateParser parser = new X509CertificateParser();
Stream url = WebRequest.Create(CERT).GetResponse().GetResponseStream();
ICollection<X509Certificate> chain = new List<X509Certificate>();
chain.Add(parser.ReadCertificate(url));
C4_07_ClientServerSigning app = new C4_07_ClientServerSigning();
app.Sign(SRC, DEST, chain, CryptoStandard.CMS, "Test", "Ghent");
}
}
}
c4_08_serverclientsigning
JAVA
JAVA
package signatures.chapter4;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.List;
public class C4_08_ServerClientSigning {
public static final String CERT = "src/main/resources/bruno.crt";
public static final String KEYSTORE = "src/main/resources/ks";
public static final char[] PASSWORD = "password".toCharArray();
public static final String DEST = "results/chapter4/hello_server2.pdf";
public static final String PRE = "http://demo.itextsupport.com/SigningApp/presign";
public static final String POST = "http://demo.itextsupport.com/SigningApp/postsign";
public static void main(String[] args) throws IOException, GeneralSecurityException {
// we make a connection to a PreSign servlet
URL url = new URL(PRE);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.connect();
// we upload our self-signed certificate
OutputStream os = conn.getOutputStream();
FileInputStream fis = new FileInputStream(CERT);
int read;
byte[] data = new byte[256];
while ((read = fis.read(data, 0, data.length)) != -1) {
os.write(data, 0, read);
}
os.flush();
os.close();
// we use cookies to maintain a session
List<String> cookies = conn.getHeaderFields().get("Set-Cookie");
// we receive a hash that needs to be signed
InputStream is = conn.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
data = new byte[256];
while ((read = is.read(data)) != -1) {
baos.write(data, 0, read);
}
is.close();
byte[] hash = baos.toByteArray();
// we load our private key from the key store
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(new FileInputStream(KEYSTORE), PASSWORD);
String alias = (String)ks.aliases().nextElement();
PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
// we sign the hash received from the server
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(pk);
sig.update(hash);
data = sig.sign();
// we make a connection to the PostSign Servlet
url = new URL(POST);
conn = (HttpURLConnection)url.openConnection();
for (String cookie : cookies) {
conn.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
}
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.connect();
// we upload the signed bytes
os = conn.getOutputStream();
os.write(data);
os.flush();
os.close();
// we receive the signed document
is = conn.getInputStream();
FileOutputStream fos = new FileOutputStream(DEST);
data = new byte[256];
while ((read = is.read(data)) != -1) {
fos.write(data, 0, read);
}
is.close();
fos.flush();
fos.close();
}
}
C#
C#
/*
* This class is part of the white paper entitled
* "Digital Signatures for PDF documents"
* written by Bruno Lowagie
*
* For more info, go to: http://itextpdf.com/learn
*/
using System;
using System.IO;
using System.Net;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
namespace signatures.chapter4 {
class C4_08_ServerClientSigning {
public const String CERT = "../../../../resources/bruno.crt";
public const String KEYSTORE = "../../../../resources/pkcs12";
public static char[] PASSWORD = "password".ToCharArray();
public const String DEST = "../../../../results/chapter4/hello_server2.pdf";
public const String PRE = "http://demo.itextsupport.com/SigningApp/presign";
public const String POST = "http://demo.itextsupport.com/SigningApp/postsign";
public static void Main(String[] args) {
// we make a connection to a PreSign servlet
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(PRE);
request.Method = "POST";
// we upload our self-signed certificate
Stream os = request.GetRequestStream();
FileStream fis = new FileStream(CERT, FileMode.Open);
int read;
byte[] data = new byte[0x100];
while ((read = fis.Read(data, 0, data.Length)) != 0)
os.Write(data, 0, read);
os.Flush();
os.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
// we use cookies to maintain a session
String cookies = response.Headers["Set-Cookie"];
// we receive a hash that needs to be signed
Stream istream = response.GetResponseStream();
MemoryStream baos = new MemoryStream();
data = new byte[0x100];
while ((read = istream.Read(data, 0, data.Length)) != 0)
baos.Write(data, 0, read);
istream.Close();
byte[] hash = baos.ToArray();
// we load our private key from the key store
Pkcs12Store store = new Pkcs12Store(new FileStream(KEYSTORE, FileMode.Open), PASSWORD);
String alias = "";
// searching for private key
foreach (string al in store.Aliases)
if (store.IsKeyEntry(al) && store.GetKey(al).Key.IsPrivate) {
alias = al;
break;
}
AsymmetricKeyEntry pk = store.GetKey(alias);
// we sign the hash received from the server
ISigner sig = SignerUtilities.GetSigner("SHA256withRSA");
sig.Init(true, pk.Key);
sig.BlockUpdate(hash, 0, hash.Length);
data = sig.GenerateSignature();
// we make a connection to the PostSign Servlet
request = (HttpWebRequest)WebRequest.Create(POST);
request.Headers.Add(HttpRequestHeader.Cookie,cookies.Split(";".ToCharArray(), 2)[0]);
request.Method = "POST";
// we upload the signed bytes
os = request.GetRequestStream();
os.Write(data, 0, data.Length);
os.Flush();
os.Close();
// we receive the signed document
response = (HttpWebResponse)request.GetResponse();
istream = response.GetResponseStream();
FileStream fos = new FileStream(DEST, FileMode.Create);
data = new byte[0x100];
while ((read = istream.Read(data, 0, data.Length)) != 0)
fos.Write(data, 0, read);
istream.Close();
fos.Flush();
fos.Close();
}
}
}