http://what-when-how.com/itext-5/digital-signatures-ocsp-and-timestamping-part-2-itext-5/
http://www.verypdf.com/document/pdf-format-reference/pg_0740.htm
http://www.adobe.com/devnet-docs/acrobatetk/tools/DigSig/oids.html
http://permalink.gmane.org/gmane.comp.windows.dotnet.itextsharp.general/2662
https://sourceforge.net/projects/podofo/?source=typ_redirect
加入pdf ocsp 签名属性
package net.netca.pki.keyx.utils;
import net.netca.pki.crypto.android.constant.NetcaPKIConst;
import net.netca.pki.crypto.android.interfaces.NetcaCryptoInterface;
import net.netca.pki.crypto.android.interfaces.SignatureInterface;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Enumerated;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
import org.bouncycastle.asn1.cms.SignedData;
import org.bouncycastle.asn1.cms.SignerIdentifier;
import org.bouncycastle.asn1.cms.SignerInfo;
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import java.io.ByteArrayInputStream;
import java.security.MessageDigest;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.List;
public class CmsHelper
{
public static final String ID_PKCS7_DATA = "1.2.840.113549.1.7.1";
public static final String ID_PKCS7_SIGNED_DATA = "1.2.840.113549.1.7.2";
public static final String ID_RSA = "1.2.840.113549.1.1.1";
public static final String ID_SHA1WITHRSA = "1.2.840.113549.1.1.5";
public static final String ID_DSA = "1.2.840.10040.4.1";
public static final String ID_ECDSA = "1.2.840.10045.2.1";
public static final String ID_CONTENT_TYPE = "1.2.840.113549.1.9.3";
public static final String ID_MESSAGE_DIGEST = "1.2.840.113549.1.9.4";
public static final String ID_SIGNING_TIME = "1.2.840.113549.1.9.5";
public static final String ID_ADBE_REVOCATION = "1.2.840.113583.1.1.8";
public static final String ID_TSA = "1.2.840.113583.1.1.9.1";
public static final String ID_OCSP = "1.3.6.1.5.5.7.48.1";
public static final String ID_AA_SIGNING_CERTIFICATE_V1 = "1.2.840.113549.1.9.16.2.12";
public static final String ID_AA_SIGNING_CERTIFICATE_V2 = "1.2.840.113549.1.9.16.2.47";
static int version = 1;
static int signerversion = 1;
static String digestAlgorithmOid = ID_SHA1WITHRSA;
static String digestEncryptionAlgorithmOid = ID_SHA1WITHRSA;
public static byte[] SignedData(byte[] data, X509Certificate[] cers, NetcaCryptoInterface netcaCryptoInterface, List<byte[]> ocsps, List<byte[]> crls) throws Exception {
net.netca.pki.Certificate cert = new net.netca.pki.Certificate(cers[0].getEncoded());
try {
byte[] hashData = MessageDigest.getInstance("SHA1").digest(data);
SignatureInterface signatureInterface = netcaCryptoInterface.getSignatureInterface();
if ((ocsps == null || ocsps.isEmpty()) && (crls == null || crls.isEmpty())) {
signatureInterface.init(NetcaPKIConst.Signature.SHA1WITHRSA, cert, null);
signatureInterface.signUpdate(hashData, 0, hashData.length);
byte[] signeddata = signatureInterface.sign();
return ToSignedDataDer(hashData, null, cers, signeddata, true);
} else {
DERSet ds = getAuthenticatedAttributeSet(hashData, ocsps, crls);
byte[] buf = ds.getEncoded(ASN1Encoding.DER);
signatureInterface.init(NetcaPKIConst.Signature.SHA1WITHRSA, cert, null);
signatureInterface.signUpdate(buf, 0, buf.length);
byte[] signeddata = signatureInterface.sign();
return ToSignedDataDer(hashData, ASN1Set.getInstance(new DERTaggedObject(false, 0, ds), true), cers, signeddata, true);
}
}finally {
cert.free();
}
}
//SHA1withRSA
private static byte[] ToSignedDataDer(byte[] content, ASN1Set signedAttr, X509Certificate[] cers, byte[] signature, boolean isAttached) throws Exception
{
//digestAlgorithms
DERSet digestAlgorithms= new DERSet(
new AlgorithmIdentifier[]{new AlgorithmIdentifier(X509ObjectIdentifiers.id_SHA1)});
//contentInfo
ContentInfo contentInfo= null;
if(isAttached)
contentInfo= new ContentInfo(CMSObjectIdentifiers.data,new DEROctetString(content));
else
contentInfo= new ContentInfo(CMSObjectIdentifiers.data,null);
//certificates
Certificate[] bcCert = new Certificate[cers.length];
for(int i = 0;i <cers.length;i++){
X509Certificate cer = cers[i];
ASN1Sequence seq= ASN1Sequence.getInstance(cer.getEncoded());
bcCert[i] = Certificate.getInstance(seq);
}
DERSet certificates= new DERSet(
bcCert);
IssuerAndSerialNumber sid = new IssuerAndSerialNumber(bcCert[bcCert.length-1]);
SignerInfo sinfo= new SignerInfo(
new SignerIdentifier(sid),
new AlgorithmIdentifier(X509ObjectIdentifiers.id_SHA1),
signedAttr,
new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption,DERNull.INSTANCE),
new DEROctetString(signature),
null);
DERSet signerInfos= new DERSet(new SignerInfo[]{sinfo});
//SignedData
SignedData signeddata= new SignedData(
digestAlgorithms,
contentInfo,
certificates,
null,
signerInfos);
//cms
ContentInfo data= new ContentInfo(
CMSObjectIdentifiers.signedData,
signeddata);
return data.getEncoded(ASN1Encoding.DER);
}
private static DERSet getAuthenticatedAttributeSet(byte[] secondDigest, Collection<byte[]> ocspBytes, Collection<byte[]> crlBytes) throws Exception {
ASN1EncodableVector attribute = new ASN1EncodableVector();
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(new ASN1ObjectIdentifier(ID_CONTENT_TYPE));
v.add(new DERSet(new ASN1ObjectIdentifier(ID_PKCS7_DATA)));
attribute.add(new DERSequence(v));
v = new ASN1EncodableVector();
v.add(new ASN1ObjectIdentifier(ID_MESSAGE_DIGEST));
v.add(new DERSet(new DEROctetString(secondDigest)));
attribute.add(new DERSequence(v));
boolean haveCrl = false;
if (crlBytes != null) {
for (byte[] bCrl : crlBytes) {
if (bCrl != null) {
haveCrl = true;
break;
}
}
}
if (ocspBytes != null || haveCrl) {
v = new ASN1EncodableVector();
v.add(new ASN1ObjectIdentifier(ID_ADBE_REVOCATION));
ASN1EncodableVector revocationV = new ASN1EncodableVector();
if (haveCrl) {
ASN1EncodableVector v2 = new ASN1EncodableVector();
for (byte[] bCrl : crlBytes) {
if (bCrl == null){
continue;
}
ASN1InputStream t = new ASN1InputStream(new ByteArrayInputStream(bCrl));
v2.add(t.readObject());
}
revocationV.add(new DERTaggedObject(true, 0, new DERSequence(v2)));
}
if (ocspBytes != null&&!ocspBytes.isEmpty()) {
ASN1EncodableVector vo1 = new ASN1EncodableVector();
for(byte[] o:ocspBytes){
if(o==null){
continue;
}
DEROctetString doctet = new DEROctetString(o);
ASN1EncodableVector v2 = new ASN1EncodableVector();
v2.add(OCSPObjectIdentifiers.id_pkix_ocsp_basic);
v2.add(doctet);
ASN1Enumerated den = new ASN1Enumerated(0);
ASN1EncodableVector v3 = new ASN1EncodableVector();
v3.add(den);
v3.add(new DERTaggedObject(true, 0, new DERSequence(v2)));
vo1.add(new DERSequence(v3));
}
revocationV.add(new DERTaggedObject(true, 1, new DERSequence(vo1)));
}
v.add(new DERSet(new DERSequence(revocationV)));
attribute.add(new DERSequence(v));
}
return new DERSet(attribute);
}
}
Attributes signedAttr = null;
byte[] signedAttrData = null;
if((ocspList!=null&&!ocspList.isEmpty())||(crlList!=null&&!crlList.isEmpty())){
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(data);
byte[] secondDigest = md.digest();
signedAttr = Attributes.getInstance(CmsHelper.getAuthenticatedAttributeSet(secondDigest, ocspList, crlList));
signedAttrData = signedAttr.getEncoded(ASN1Encoding.DER);
}else{
signedAttrData = data;
}
signResult = sign(certInfo, "SHA1WithRSA", signedAttrData )
byte[] retData = CmsHelper.ToSignedDataDer(data, signedAttr, certs, signResult, true);
获取ocsp 和crl地址
public static String getOCSPURL(X509Certificate certificate) {
try {
ASN1Primitive obj = getExtensionValue(certificate,
Extension.authorityInfoAccess.getId());
if (obj == null) {
return null;
}
ASN1Sequence AccessDescriptions = (ASN1Sequence) obj;
for (int i = 0; i < AccessDescriptions.size(); i++) {
ASN1Sequence AccessDescription = (ASN1Sequence) AccessDescriptions
.getObjectAt(i);
if (AccessDescription.size() == 2) {
if ((AccessDescription.getObjectAt(0) instanceof ASN1ObjectIdentifier)) {
ASN1ObjectIdentifier id = (ASN1ObjectIdentifier) AccessDescription
.getObjectAt(0);
if ("1.3.6.1.5.5.7.48.1".equals(id.getId())) {
ASN1Primitive description = (ASN1Primitive) AccessDescription
.getObjectAt(1);
String AccessLocation = getStringFromGeneralName(description);
if (AccessLocation == null) {
return "";
}
return AccessLocation;
}
}
}
}
} catch (IOException e) {
return null;
}
return null;
}
public static String getCRLURL(X509Certificate certificate)
throws CertificateParsingException {
ASN1Primitive obj;
try {
obj = getExtensionValue(certificate,
Extension.cRLDistributionPoints.getId());
} catch (IOException e) {
obj = null;
}
if (obj == null) {
return null;
}
CRLDistPoint dist = CRLDistPoint.getInstance(obj);
DistributionPoint[] dists = dist.getDistributionPoints();
for (DistributionPoint p : dists) {
DistributionPointName distributionPointName = p
.getDistributionPoint();
if (0 == distributionPointName.getType()) {
GeneralNames generalNames = (GeneralNames) distributionPointName
.getName();
GeneralName[] names = generalNames.getNames();
for (GeneralName name : names) {
if (name.getTagNo() == 6) {
DERIA5String derStr = DERIA5String.getInstance(
(ASN1TaggedObject) name.toASN1Primitive(),
false);
return derStr.getString();
}
}
}
}
return null;
}
private static String getStringFromGeneralName(ASN1Primitive names)
throws IOException {
ASN1TaggedObject taggedObject = (ASN1TaggedObject) names;
return new String(ASN1OctetString.getInstance(taggedObject, false)
.getOctets(), "ISO-8859-1");
}
private static ASN1Primitive getExtensionValue(X509Certificate certificate,
String oid) throws IOException {
byte[] bytes = certificate.getExtensionValue(oid);
if (bytes == null) {
return null;
}
ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(
bytes));
ASN1OctetString octs = (ASN1OctetString) aIn.readObject();
aIn = new ASN1InputStream(new ByteArrayInputStream(octs.getOctets()));
return aIn.readObject();
}
itext
public static void signPdfByiText(ExternalSignature externalSignature, String pdfFile,String bitmapFilePath, String savePath,int pageIndex, RectF rect,X509Certificate[] chain,List<byte[]>crlBytes,List<byte[]>ocsp, int estimatedSize) throws Exception{
PdfReader reader = new PdfReader(pdfFile);
File file = new File(savePath);
file.delete();
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
PdfStamper pdfStamper = PdfStamper.createSignature(reader, fos, '\0', null, true);
PdfSignatureAppearance sap = pdfStamper.getSignatureAppearance();
sap.setVisibleSignature(new Rectangle(rect.left, rect.top, rect.right, rect.bottom), pageIndex+1, UUID.randomUUID().toString());
if(!TextUtils.isEmpty(bitmapFilePath)){
sap.setSignatureGraphic(com.itextpdf.text.Image.getInstance(bitmapFilePath));
sap.setRenderingMode(RenderingMode.GRAPHIC);
}else{
sap.setRenderingMode(RenderingMode.DESCRIPTION);
}
BouncyCastleDigest externalDigest = new BouncyCastleDigest();
byte[] ocspData = null;
if (estimatedSize == 0) {
estimatedSize = 8192;
if (crlBytes != null) {
for (byte[] element : crlBytes) {
if(element == null){
continue;
}
estimatedSize += element.length + 10;
}
}
if (ocsp != null) {
for (byte[] element : ocsp) {
if(element == null){
continue;
}
estimatedSize += 4192;
ocspData = element;
}
}
}
String displayData = chain[0].getSubjectDN().toString();
sap.setCertificate(chain[0]);
Font font = new Font(BaseFont.createFont(Constant.FONT,BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED));
sap.setLayer2Font(font);
sap.setSignatureCreator(StringUtil.getCertDN(displayData, "CN="));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String layer2Text = String.format("%s 签名日期:%s", StringUtil.getCertDN(displayData, "CN="), sdf.format(new Date()));
sap.setLayer2Text(layer2Text);
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE,PdfName.ADBE_PKCS7_SHA1);
dic.setSignatureCreator(sap.getSignatureCreator());
dic.setDate(new PdfDate(sap.getSignDate()));
sap.setCryptoDictionary(dic);
HashMap<PdfName, Integer> exc = new HashMap();
exc.put(PdfName.CONTENTS, new Integer(estimatedSize * 2 + 2));
sap.preClose(exc);
String hashAlgorithm = DigestAlgorithms.SHA1;
PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, null,
externalDigest, true);
InputStream data = sap.getRangeStream();
byte[] hash = DigestAlgorithms.digest(data,
externalDigest.getMessageDigest(hashAlgorithm));
byte[]secondDigest = DigestAlgorithms.digest(new ByteArrayInputStream(hash),
externalDigest.getMessageDigest(hashAlgorithm));
byte[] sh = sgn.getAuthenticatedAttributeBytes(secondDigest, ocspData, crlBytes,
CryptoStandard.CMS);
byte[] extSignature = externalSignature.sign(sh);
sgn.setExternalDigest(extSignature, hash,
externalSignature.getEncryptionAlgorithm());
byte[] encodedSig = sgn.getEncodedPKCS7(secondDigest, null, ocspData,
crlBytes, CryptoStandard.CMS);
if (estimatedSize < encodedSig.length) {
throw new IOException("Not enough space");
}
byte[] paddedSig = new byte[estimatedSize];
System.arraycopy(encodedSig, 0, paddedSig, 0, encodedSig.length);
PdfDictionary dic2 = new PdfDictionary();
dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
sap.close(dic2);
}