Two types of P7 signatures1. Java JCEPackage encrypt;
Import Java.io.ByteArrayInputStream;
Import Java.io.ByteArrayOutputStream;
Import Java.io.FileInputStream;
Import java.io.IOException;
Import Java.io.InputStream;
Import Java.lang.reflect.Array;
Import Java.lang.reflect.Constructor;
Import Java.lang.reflect.Field;
Import Java.lang.reflect.Method;
Import Java.math.BigInteger;
Import java.security.GeneralSecurityException;
Import java.security.InvalidKeyException;
Import Java.security.KeyStore;
Import java.security.NoSuchAlgorithmException;
Import java.security.NoSuchProviderException;
Import Java.security.PrivateKey;
Import Java.security.Signature;
Import java.security.SignatureException;
Import Java.security.cert.Certificate;
Import java.security.cert.CertificateException;
Import Java.security.cert.CertificateFactory;
Import Java.security.cert.X509Certificate;
Import java.util.Enumeration;
Import Javax.security.auth.x500.X500Principal;
Import Sun.misc.BASE64Decoder;
Import Sun.misc.BASE64Encoder;
Import Sun.security.pkcs.ContentInfo;
Import sun.security.pkcs.PKCS7;
Import sun.security.pkcs.PKCS9Attributes;
Import Sun.security.pkcs.SignerInfo;
/**
* Pkcs7tool.java PKCS7 Format Signature Tool
*
* @version 1.0
* @author SUNY written date:2008-9-23 Modified Date 2010-6-12 Update for IBM
* JDK
*/
public class Pkcs7tool {
/** Signature */
private static final int signer = 1;
/** Verification */
private static final int VERIFIER = 2;
/** Use */
private int mode = 0;
/** Digest Algorithm */
Private String Digestalgorithm = "SHA1";
/** Signature Algorithm */
Private String Signingalgorithm = "Sha1withrsa";
/** Signing certificate Chain */
Private x509certificate[] certificates = null;
/** Signing Private Key */
Private Privatekey privatekey = null;
/** Root Certificate */
Private Certificate rootcertificate = null;
/** JVM Provider */
private static char, JVM = 0;
private static Class algorithmid = null;
private static Class dervalue = null;
private static Class objectidentifier = null;
private static Class x500name = null;
private static Boolean debug = FALSE;
/**
* Private Construction method
*/
Private Pkcs7tool (int mode) {
This.mode = mode;
}
/**
* Get signature tool to load Certificate library, get signing certificate chain and private key
*
* @param Keystorepath
* Certificate Library Path
* @param Keystorepassword
* Certificate Store password
* @throws generalsecurityexception
* @throws IOException
*/
public static Pkcs7tool Getsigner (String Keystorepath,
String Keystorepassword, String Keypassword)
Throws Generalsecurityexception, IOException {
Init ();
Load Certificate Library
KeyStore KeyStore = null;
if (Keystorepath.tolowercase (). EndsWith (". pfx"))
KeyStore = Keystore.getinstance ("PKCS12");
Else
KeyStore = Keystore.getinstance ("JKS");
FileInputStream FIS = null;
try {
FIS = new FileInputStream (Keystorepath);
Keystore.load (FIS, Keystorepassword.tochararray ());
} finally {
if (FIS! = null)
Fis.close ();
}
Locate the signature private key in the certificate store
Enumeration aliases = Keystore.aliases ();
String keyalias = null;
if (aliases! = null) {
while (Aliases.hasmoreelements ()) {
Keyalias = (String) aliases.nextelement ();
certificate[] certs = Keystore.getcertificatechain (Keyalias);
if (certs = = NULL | | certs.length = = 0)
Continue
X509Certificate cert = (x509certificate) certs[0];
if (Matchusage (Cert.getkeyusage (), 1)) {
try {
Cert.checkvalidity ();
} catch (Certificateexception e) {
Continue
}
Break
}
}
}
No available signature private key found
if (Keyalias = = null)
throw New Generalsecurityexception (
"None certificate for sign on this keystore");
if (Debug)
System.out.println (Keyalias);
x509certificate[] certificates = null;
if (Keystore.iskeyentry (Keyalias)) {
Check the certificate chain
certificate[] certs = Keystore.getcertificatechain (Keyalias);
for (int i = 0; i < certs.length; i++) {
if (! ( Certs[i] instanceof X509Certificate))
throw new Generalsecurityexception ("certificate[" + I
+ "] in chain '" + Keyalias
+ "is not a x509certificate.");
}
Convert certificate Chain
Certificates = new X509certificate[certs.length];
for (int i = 0; i < certs.length; i++)
Certificates[i] = (x509certificate) certs[i];
} else if (Keystore.iscertificateentry (Keyalias)) {
Only a single certificate
Certificate cert = keystore.getcertificate (Keyalias);
if (cert instanceof X509Certificate) {
Certificates = new x509certificate[] {(x509certificate) cert};
}
} else {
throw New Generalsecurityexception (Keyalias
+ "is unknown to this keystore");
}
Privatekey Privatekey = (privatekey) keystore.getkey (Keyalias,
Keypassword.tochararray ());
No private key Throw exception
if (Privatekey = = null) {
throw New Generalsecurityexception (Keyalias
+ "could not being accessed");
}
Pkcs7tool tool = new Pkcs7tool (signer);
Tool.certificates = certificates;
Tool.privatekey = Privatekey;
return tool;
}
/**
* Obtain a signature tool to load the trust root certificate
*
* @param Rootcertificatepath
* Root Certificate path
* @throws generalsecurityexception
* @throws IOException
*/
public static Pkcs7tool Getverifier (String rootcertificatepath)
Throws Generalsecurityexception, IOException {
Init ();
Load Root Certificate
FileInputStream FIS = null;
Certificate rootcertificate = null;
try {
FIS = new FileInputStream (Rootcertificatepath);
Certificatefactory certificatefactory = certificatefactory
. getinstance ("the");
try {
Rootcertificate = Certificatefactory.generatecertificate (FIS);
} catch (Exception Exception) {
InputStream is = new Bytearrayinputstream (
New Base64decoder (). Decodebuffer (FIS));
Rootcertificate = Certificatefactory.generatecertificate (IS);
}
} finally {
if (FIS! = null)
Fis.close ();
}
Pkcs7tool tool = new Pkcs7tool (VERIFIER);
Tool.rootcertificate = rootcertificate;
return tool;
}
/**
* Signature
*
* @param data
* Data
* @return Signature Signature Results
* @throws generalsecurityexception
* @throws IOException
* @throws IllegalArgumentException
*/
Public String sign (byte[] data) throws Exception {
if (mode! = signer)
throw New IllegalStateException (
"Call a Pkcs7tool instance isn't for signature.");
Signature signer = signature.getinstance (signingalgorithm);
Signer.initsign (Privatekey);
Signer.update (data, 0, data.length);
byte[] signedattributes = Signer.sign ();
ContentInfo contentinfo = null;
Field Data_oidfield = ContentInfo.class.getField ("data_oid");
Object data_oid = Data_oidfield.get (null);
Constructor Contentinfoconstructor = Contentinfo.class
. GetConstructor (New class[] {data_oid.getclass (), dervalue});
ContentInfo = (contentinfo) contentinfoconstructor
. newinstance (New object[] {data_oid, null});
Root certificate
X509Certificate x509 = certificates[certificates.length-1];
Java.math.BigInteger serial = X509.getserialnumber ();
X500name
Constructor X500nameconstructor = X500name
. GetConstructor (New class[] {string.class});
Object X500nameobject = X500nameconstructor
. newinstance (New object[] {X509.getissuerdn (). GetName ()});
Algorithmid
Method algorithmidget = Algorithmid.getmethod ("Get",
New class[] {string.class});
Object digestalgorithmid = Algorithmidget.invoke (null,
New object[] {digestalgorithm});
Field Algorithmidfield = Algorithmid.getfield ("rsaencryption_oid");
Object rsaoid = Algorithmidfield.get (null);
Constructor Algorithmconstructor = Algorithmid
. GetConstructor (New class[] {objectidentifier});
Object algorithmrsaoid = Algorithmconstructor
. newinstance (New object[] {rsaoid});
SignerInfo
Constructor Signerinfoconstructor = Signerinfo.class
. GetConstructor (New class[] {x500name, Biginteger.class,
Algorithmid, Pkcs9attributes.class, Algorithmid,
Byte[].class, pkcs9attributes.class});
Signature information
SignerInfo si = (signerinfo) signerinfoconstructor
. newinstance (New object[] {x500nameobject,//x500name,
Issuername,
Serial,//X509.getserialnumber (), BigInteger serial,
Digestalgorithmid,//Algorithmid, Digestalgorithmid,
NULL,//Pkcs9attributes, Authenticatedattributes,
Algorithmrsaoid,//Algorithmid,
Digestencryptionalgorithmid,
Signedattributes,//byte[] encrypteddigest,
Null//Pkcs9attributes unauthenticatedattributes)
});
Signerinfo[] Signerinfos = {SI};
Constructing PKCS7 Data
Object digestalgorithmids = Array.newinstance (Algorithmid, 1);
Array.set (digestalgorithmids, 0, Digestalgorithmid);
PKCS7
Constructor pkcs7constructor = PKCS7.class.getConstructor (new class[] {
Digestalgorithmids.getclass (), Contentinfo.class,
X509certificate[].class, Signerinfos.getclass ()});
PKCS7 P7 = (PKCS7) pkcs7constructor.newinstance (new object[] {
Digestalgorithmids, ContentInfo, certificates, Signerinfos});
PKCS7 P7 = new PKCS7 (Digestalgorithmids, ContentInfo, certificates,
Signerinfos);
Public PKCS7 (com.ibm.security.x509.algorithmid[] arg0,
Sun.security.pkcs.ContentInfo Arg1,
Java.security.cert.x509certificate[] Arg2,
Sun.security.pkcs.signerinfo[] arg3);
Public PKCS7 (sun.security.x509.algorithmid[] arg0,
Sun.security.pkcs.ContentInfo Arg1,
Java.security.cert.x509certificate[] Arg2,
Sun.security.pkcs.signerinfo[] arg3);
Bytearrayoutputstream baout = new Bytearrayoutputstream ();
P7.encodesigneddata (baout);
BASE64 encoding
Return (new Base64encoder ()). Encode (Baout.tobytearray ());
}
/**
* Verify signature (no CRL)
*
* @param signature
* Signature Signature Results
* @param data
* Signed Data
* @param DN
* Signature Certificate DN, if empty, does not match authentication
* @throws IOException
* @throws nosuchalgorithmexception
* @throws signatureexception
* @throws InvalidKeyException
* @throws certificateexception
* @throws nosuchproviderexception
*/
public void Verify (string signature, byte[] data, string dn)
Throws IOException, NoSuchAlgorithmException, Signatureexception,
InvalidKeyException, Certificateexception, nosuchproviderexception {
if (mode! = VERIFIER)
throw New IllegalStateException (
"Call a Pkcs7tool instance isn't for verify.");
byte[] Sign = new Base64decoder (). Decodebuffer (signature);
PKCS7 P7 = new PKCS7 (sign);
x509certificate[] certs = P7.getcertificates ();
if (Debug)
for (int i = 0; i < certs.length; i++) {
X509Certificate cert = certs[i];
System.out.println ("signer" + i + "=\n" + cert);
System.out.println ("signer" + i + "=\n"
+ New Base64encoder (). Encode (cert.getencoded ()));
}
Verifying the signature itself, certificate usage, certificate extensions
Signerinfo[] sis = p7.verify (data);
Check the results of the verification
if (sis = = null)
throw New Signatureexception (
"Signature failed verification, data has been tampered");
for (int i = 0; i < sis.length; i++) {
SignerInfo si = sis[i];
X509Certificate cert = si.getcertificate (P7);
Whether the certificate expires validation if no system date is available cert.checkvalidity (date);
Cert.checkvalidity ();
if (!cert.equals (rootcertificate)) {
Verifying certificate Signing
Cert.verify (Rootcertificate.getpublickey ());
}
Verify DN
if (i = = 0 && DN = null) {
X500principal name = Cert.getsubjectx500principal ();
if (!dn.equals (Name.getname (x500principal.rfc1779))
&&!new X500principal (DN). Equals (name))
throw new Signatureexception ("Signer dn")
+ Name.getname (x500principal.rfc1779)
+ "' does not matchs '" + DN + "'");
}
}
}
/**
* Match private key usage
*
* @param keyusage
* @param usage
* @return
*/
private static Boolean Matchusage (boolean[] keyusage, int usage) {
if (Usage = = 0 | | keyusage = = NULL)
return true;
for (int i = 0; i < math.min (keyusage.length); i++) {
if (Usage & (1 << i) = = 0 &&!keyusage[i])
return false;
}
return true;
}
private static void Init () {
if (JVM! = 0)
Return
String vendor = System.getproperty ("Java.vm.vendor");
if (vendor = = NULL)
Vendor = "";
String Vendoruc = Vendor.touppercase ();
try {
if (Vendoruc.indexof ("SUN") >= 0) {
JVM = ' S ';
Algorithmid = Class.forName ("Sun.security.x509.AlgorithmId");
Dervalue = Class.forName ("Sun.security.util.DerValue");
Objectidentifier = Class
. forname ("Sun.security.util.ObjectIdentifier");
X500name = Class.forName ("Sun.security.x509.X500Name");
} else if (Vendoruc.indexof ("IBM") >= 0) {
JVM = ' I ';
Algorithmid = Class
. forname ("Com.ibm.security.x509.AlgorithmId");
Dervalue = Class.forName ("Com.ibm.security.util.DerValue");
Objectidentifier = Class
. forname ("Com.ibm.security.util.ObjectIdentifier");
X500name = Class.forName ("Com.ibm.security.x509.X500Name");
} else {
System.out.println ("Not the support JRE:" + vendor);
System.exit (-1);
}
} catch (ClassNotFoundException e) {
E.printstacktrace ();
System.exit (-1);
}
}
/**
* @return return to Digestalgorithm.
*/
Public final String Getdigestalgorithm () {
return digestalgorithm;
}
/**
* @param digestalgorithm
* The Digestalgorithm to be set.
*/
Public final void Setdigestalgorithm (String digestalgorithm) {
This.digestalgorithm = Digestalgorithm;
}
/**