I need to send a digital signature as one the parameters to an external webservice.
The steps to create as per documentation is :
Create a DOM representation of the XML data
Create a canonicalised representation of the DOM data. The canonicalised representation should follow the form described in http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments;
Create the signature RSA encryption of the SHA1 digest of the canonicalised representation. The signature is encrypted using the Participant‟s private key;
Encode the binary signature into a base64-encoded string
Place the Signature string in the SOAP message ReqDigSig element;
Store the XML data as it may be needed later to support Non-Repudiation of the submitted XML data.
I have used the following code:
private string SignXML(X509Certificate2 Cert, string data)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = false;
xmlDoc.LoadXml(data);
XmlDsigC14NWithCommentsTransform t = new XmlDsigC14NWithCommentsTransform();
t.LoadInput(xmlDoc);
Stream s = (Stream)t.GetOutput(typeof(Stream));
SHA1 sha1 = SHA1.Create();
byte[] hash = sha1.ComputeHash(s);
RSACryptoServiceProvider rsaKey =
(RSACryptoServiceProvider)Cert.PrivateKey;
RSAParameters rsaPrivateParams = rsaKey.ExportParameters(true);
rsaKey.ImportParameters(rsaPrivateParams);
byte[] signature = rsaKey.Encrypt(hash, false);
return Convert.ToBase64String(signature);
}
But the response from the webservice says digital signature verification error.
is the code above as per the description in the documentation?
How would i verify if the digital signaature is valid? is there any online tool?
[Post edited as follows]
I have tried using the following. I have verified the signature and it returns true. But fails from the webservice end. What is the difference among signData, signHash and the rsaPKCsignatureformatter classes' createsignature method?
var document = Encoding.UTF8.GetBytes(Reqdata);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = false;
xmlDoc.LoadXml(Reqdata);
//trial with XmlDsigC14NWithCommentsTransform class
XmlDsigC14NWithCommentsTransform t = new XmlDsigC14NWithCommentsTransform();
t.LoadInput(xmlDoc);
Stream s = (Stream)t.GetOutput(typeof(Stream));
//trial with SignedXML class
SignedXml signedXml = new SignedXml(xmlDoc);
signedXml.SignedInfo.CanonicalizationMethod =
SignedXml.XmlDsigC14NWithCommentsTransformUrl;
document = Encoding.UTF8.GetBytes(signedXml.ToString());
byte[] hashedDocument;
using (var sha1 = SHA1.Create())
{
//hashedDocument = sha1.ComputeHash(document);
hashedDocument = sha1.ComputeHash(s);
}
var digitalSignature = new DigitalSignature();
digitalSignature.AssignNewKey();
byte[] signature = digitalSignature.SignData(hashedDocument);
string finalsignature = Convert.ToBase64String(signature) ;
byte[] finalSignveri = Convert.FromBase64String(finalsignature);
bool verified = digitalSignature.VerifySignature(hashedDocument, finalSignveri);
and the digital signature class is as follows:
public class DigitalSignature
{
private RSAParameters publicKey;
private RSAParameters privateKey;
public void AssignNewKey()
{
using (var rsa = new RSACryptoServiceProvider())
{
rsa.PersistKeyInCsp = false;
publicKey = rsa.ExportParameters(false);
privateKey = rsa.ExportParameters(true);
}
}
public byte[] SignData(byte[] hashOfDataToSign)
{
using (var rsa = new RSACryptoServiceProvider())
{
rsa.PersistKeyInCsp = false;
rsa.ImportParameters(privateKey);
var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
rsaFormatter.SetHashAlgorithm("SHA1");
return rsaFormatter.CreateSignature(hashOfDataToSign);
}
}
public bool VerifySignature(byte[] hashOfDataToSign, byte[] signature)
{
using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(publicKey);
var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
rsaDeformatter.SetHashAlgorithm("SHA1");
return rsaDeformatter.VerifySignature(hashOfDataToSign, signature);
}
}
}
Could you please let me know what data are you specifically looking for in wsdl? Sorry i am unable to provide the complete wsdl information here.
The error returned is i believe user handled and states "Digital signature verification error"
[Redited]
Please find below a snippet of the code that generates digital signature in java. This was sent by the third party for reference. I am not a java developer. Could someone let me know if the C#code that i have written corresponds to the Java code? if not, please let me know where i am going wrong.
private static String createDigitalSignature(Key key, byte[] data) {
byte[] signature = null;
try {
// Initialize xml-security library
org.apache.xml.security.Init.init();
// Build DOM document from XML data
DocumentBuilderFactory dfactory = DocumentBuilderFactory
.newInstance();
dfactory.setNamespaceAware(true);
dfactory.setValidating(true);
DocumentBuilder documentBuilder = dfactory.newDocumentBuilder();
// This is to throw away all validation errors
documentBuilder
.setErrorHandler(new org.apache.xml.security.utils.IgnoreAllErrorHandler());
Document doc = documentBuilder
.parse(new ByteArrayInputStream(data));
// Build canonicalized XML from document
Canonicalizer c14n = Canonicalizer
.getInstance("http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments");
byte[] canonBytes = c14n.canonicalizeSubtree(doc);
// Initialize signing object with SHA1 digest and RSA encryption
Signature rsa = Signature.getInstance("SHA1withRSA");
// Set private key into signing object
rsa.initSign((PrivateKey) key);
// Generate signature
rsa.update(canonBytes);
signature = rsa.sign();
} catch (Exception ex) {
System.out.println("Exception occurred in createDigitalSignature: "
+ ex.toString());
System.exit(-1);
}
// Base64 encode signature
BASE64Encoder b64e = new BASE64Encoder();
String signatureString = b64e.encode(signature);
return signatureString;
}
At step 3, a digital signature is not exactly the same as encrypt a digest. A rsa digital signature with pkcs#1 format concatenates the digestAlgorithm OID(the identifier) with the digest value. So you are generating and invalid signature.
All programming languages have a method to perform digital signature without dealing with digests and ciphers. I am not a C# programmer but I guess you have to use RSACryptoServiceProvider.SignData
Use also VerifyData to verify the signature
Related
We have a java program that signs a xml file with a private key like this:
byte[] privateKeyBytes = ...; // read from the .der file
PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory privateKeyFactory = KeyFactory.getInstance("RSA");
PrivateKey = privateKeyFactory.generatePrivate(privateSpec);
Signature rsaSignature = Signature.getInstance("SHA1withRSA");
rsaSignature.initSign(privateKey);
rsaSignature.update(data);
byte[] signature = rsaSignature.sign();
Now i have to validate this signature in C++ using cryptocpp. What i tried:
void Load(const std::string& filename, BufferedTransformation& bt)
{
FileSource file(filename.c_str(), true /*pumpAll*/);
file.TransferTo(bt);
bt.MessageEnd();
}
void LoadKeyFile(const std::string& filename, PublicKey & key)
{
ByteQueue queue;
Load(filename, queue);
key.Load(queue);
}
void verifySignature(std::string xmlString, std::string signature)
{
RSA::PublicKey publicKey;
LoadKeyFile(..., publicKey);
RSASS<PSS, SHA1>::Verifier verifier(publicKey);
// also tried RSASS<PSSR, SHA1>::Verifier verifier(publicKey);
if (!verifier.VerifyMessage((byte*)xmlString.c_str(), xmlString.size(),
(byte*)signature.c_str(), signature.size()) )
{
// always returns false
}
}
I validated that the data passed as xmlString is binary identical with the one used for creating the signature in java. The signature is base64 encoded and i also tried using it decoded.
I always failed so far.
If i create a signature with the private key using cryptopp - then validating the created signature works without problems.
What may be the problem here? I am sure this has already been done?
The solution is
RSASS<PKCS1v15, SHA1>::Verifier verifier(publicKey);
Instead of
RSASS<PSS, SHA1>::Verifier verifier(publicKey);
Thanks a lot to #Topaco!
please help me to solve the following:
I have a code on Java
java code bellow:
StringBuilder fullText;
KeyStore p12 = KeyStore.getInstance("PKCS12");
p12.load(new FileInputStream("FileName.p12"), "1234".toCharArray());
Key key = (Key) p12.getKey("1", "1234".toCharArray());
//signing
Signature signer = Signature.getInstance("SHA1withRSA");
signer.initSign((PrivateKey) key);
signer.update(fullText.toString().getBytes());
b`yte[] digitalSignature = signer.sign();
String base64sign = new String(Base64.getEncoder().encode(digitalSignature));
I tried to reproduce it on .Net platform.
I create a code on .NET 3.5 platform. The code on X++ below:
public static boolean Encrypt(str sXmlDoc)
{
boolean bSuccess = false;
System.Security.Cryptography.X509Certificates.X509Certificate2 p12;
System.Security.Cryptography.AsymmetricAlgorithm key;
str sBase64Cert;
str sBase64Xml;
str sBase64Sign;
str sTmp;
System.Byte[] byteArray;
System.Security.Cryptography.Xml.Signature signer;
System.Exception ex;
str sKeyPublic;
System.Byte[] keyPublic;
System.Int32 myInt32;
int myInt;
System.Byte[] byteTmp, byteTmp2;
System.Text.ASCIIEncoding txtEncoder;
System.Security.Cryptography.Xml.KeyInfo keyInfo;
System.Security.Cryptography.Xml.SignedXml signedXml;
System.Xml.XmlDocument xmlDocument;
System.Xml.XmlElement xmlElement;
System.Security.Cryptography.Xml.SignedInfo signedInfo;
System.Security.Cryptography.Xml.Reference reference;
System.Security.Cryptography.Xml.XmlDsigEnvelopedSignatureTransform env;
System.Security.Cryptography.Xml.RSAKeyValue rsaKeyValue;
System.Security.Cryptography.RSA rsaKey;
try
{
p12 = new System.Security.Cryptography.X509Certificates.X509Certificate2("fileName.p12", "pass");
if (p12)
{
//Signature
//TEST
if (p12.get_HasPrivateKey())
{
key = p12.get_PrivateKey();
rsaKey = p12.get_PrivateKey();
xmlDocument = new System.Xml.XmlDocument();
xmlDocument.set_PreserveWhitespace(true); //Allow white spaces
xmlDocument.LoadXml(sXmlDoc);
signedXml = new System.Security.Cryptography.Xml.SignedXml(xmlDocument);
signedXml.set_SigningKey(key);
keyInfo = new System.Security.Cryptography.Xml.KeyInfo();
rsaKeyValue = new System.Security.Cryptography.Xml.RSAKeyValue(rsaKey);
keyInfo.AddClause(rsaKeyValue);
signedXml.set_KeyInfo(keyInfo);
// Create a reference to be signed.
//System.Security.Cryptography.Xml.Reference reference;
reference = new System.Security.Cryptography.Xml.Reference();
reference.set_Uri("");
// Add an enveloped transformation to the reference.
env = new System.Security.Cryptography.Xml.XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
signedXml.set_KeyInfo(keyInfo);
signedXml.ComputeSignature();
xmlElement = signedXml.GetXml();
signer = new System.Security.Cryptography.Xml.Signature();
signer = signedXml.get_Signature();
signedInfo = new System.Security.Cryptography.Xml.SignedInfo();
signedInfo = signer.get_SignedInfo();
byteTmp = signer.get_SignatureValue();
sTmp = System.Convert::ToBase64String(byteTmp);
sBase64Sign = "<signature>"+sTmp+"</signature>";
info(sBase64Sign);
}
}
}
catch (Exception::CLRError)
{
ex = ClrInterop::getLastException();
if (ex != null)
{
ex = ex.get_InnerException();
if (ex != null)
{
error(ex.ToString());
}
}
}
return bSuccess;
}
But the result differs than I got on java. I opened a p12 key. I signed an XML sting and got the signature for this XML, but got the wrong string. What did I do wrong?
The Java code doesn't say anything about XML, so I don't know if you learned anything about porting code, but if you do use XML in C# then it's going to fail.
In short, you need to use the RSA functions directly. Starting with RSA.Create() might make a lot of sense in most languages. However, .NET is rather certificate / key based (you perform operations on the key rather than using the key, for better or worse, and private keys are considered part of the certificate that they belong to). So using a constructor to read PKCS#12 is probably a better starting point.
That's all for this little tutorial. I don't believe for a second that you thought that your code would be a correct port, so start over. Happy programming.
EDIT: Oh, one last hint: SHA1withRSA is RSA using PKCS#1 v1.5 padding for signature generation, using SHA-1 as underlying hash function (which of course means it is SHATTERED and more).
The best way to sign an XML on .NET is by using a Bouncy Castle library. I hope anybody in one day will solve it on .NET framework, without using an external library, but the solution has found via using BounsyCastle.
This code on C# used BouncyCastle.
string item = string.Empty;
Pkcs12Store p12 = new Pkcs12Store();
p12.Load(_p12, _p12_psw.ToCharArray());
string alias = "";
foreach (string al in p12.Aliases)
{
if (p12.IsKeyEntry(al) && p12.GetKey(al).Key.IsPrivate)
{
alias = al;
break;
}
}
//signature
var data = Encoding.UTF8.GetBytes(xmlDoc);
ISigner signer = SignerUtilities.GetSigner("SHA1withRSA");
signer.Init(true,p12.GetKey(alias).Key);
signer.BlockUpdate(data, 0, data.Length);
var sign = signer.GenerateSignature();
string base64Sign = Convert.ToBase64String(sign);
item = "<signature>"+base64Sign+"</signature>", base64Sign);
I need to sign some data with one private key using Algorithm SHA1RSA ,Rsa Key length 2048 with 64 base encoding.My code is like this
string sPayload = "";
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create("URI");
httpWebRequest.ContentType = "application/json; charset=utf-8";
httpWebRequest.Method = WebRequestMethods.Http.Post;
using (StreamWriter streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
sPayload = "{\"id\":\"14123213213\"," +
"\"uid\":\"teller\"," +
"\"pwd\":\"abc123\"," +
"\"apiKey\":\"2343243\"," +
"\"agentRefNo\":\"234324324\"}";
httpWebRequest.Headers.Add("SIGNATURE", Convert.ToBase64String(new System.Security.Cryptography.SHA1CryptoServiceProvider().ComputeHash(Encoding.ASCII.GetBytes(sPayload))));
streamWriter.Write(sPayload);
streamWriter.Flush();
streamWriter.Close();
}
System.Net.ServicePointManager.Expect100Continue = false;
HttpWebResponse httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
string result = streamReader.ReadToEnd();
}
In the Header name Signature i need to pass the signed data(sPayload) using the private key.But using above code an error is getting as "invalid signature" from third party and i'am not sure whether the Encryption part is correct or not.
httpWebRequest.Headers.Add("SIGNATURE", Convert.ToBase64String(new System.Security.Cryptography.SHA1CryptoServiceProvider().ComputeHash(Encoding.ASCII.GetBytes(sPayload))));
Third party had provide one certificate(cert,sha1) and key.should i refer that to the code?
You have computed the SHA-1 hash of sPayload, not the RSA-SHA1 signature.
If you have an X509Certificate2:
using (RSA rsa = cert.GetRSAPrivateKey())
{
return rsa.SignData(sPayload, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
}
If you already have a raw RSA key then just leave off the using statement.
If you have to compute the hash of sPayload for some other reason you can do it like
byte[] hash;
byte[] signature;
using (HashAlgorithm hasher = SHA1.Create())
using (RSA rsa = cert.GetRSAPrivateKey())
{
hash = hasher.ComputeHash(sPayload);
signature = rsa.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
}
SignHash still requires the HashAlgorithmName value because the algorithm identifier is embedded within the signature.
I am trying to digitally sign xml document and verify the signature with the original xml file with public key and signed document. I have a java code for reference. I need to convert java code to C# where I have java code like this:
certList = new ArrayList<X509Certificate>();
certList.add(signerCert);
certStore = new JcaCertStore(certList);
signedDataGenerator = new CMSSignedDataGenerator();
ContentSigner sha2Signer = new JcaContentSignerBuilder("SHA512with" + privateKey.getAlgorithm()).build(privateKey);
ignedDataGenerator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).setDirectSignature(true).build(sha2Signer, signerCert));
signedDataGenerator.addCertificates(certStore);
CMSSignedData sigData = signedDataGenerator.generate(new CMSProcessableFile(inputXmlFile), false);
signedBytes = sigData.getEncoded();
I have converted java code to C# like this:
X509Store my = new X509Store(StoreName.My, StoreLocation.LocalMachine);
my.Open(OpenFlags.ReadOnly);
// Find the certificate we’ll use to sign
RSACryptoServiceProvider csp = null;
foreach (X509Certificate2 cert in my.Certificates)
{
if (cert.Subject.Contains(certSubject))
{
// We found it.
// Get its associated CSP and private key
csp = (RSACryptoServiceProvider)cert.PrivateKey;
}
}
if (csp == null)
{
throw new Exception("oppose no valid application was found");
}
// Hash the data
SHA512Managed sha1 = new SHA512Managed();
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(text);
byte[] hash = sha1.ComputeHash(data);
// Sign the hash
return csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
I am trying to convert it since two days, It is generating sign byte array but not been able to verify. While verifying it is throwing bad hash\r\n error I shall be highly grateful for any assistance. I know I am somewhere wrong in converting the java code to C#. I am able to verify the code but not been able to sign the document
I have generated Signature using System.Security.Cryptography.Pkcs library like this
public static byte[] Sign(byte[] data, X509Certificate2 certificate)
{
if (data == null)
throw new ArgumentNullException("data");
if (certificate == null)
throw new ArgumentNullException("certificate");
// setup the data to sign
ContentInfo content = new ContentInfo(data);
SignedCms signedCms = new SignedCms(content, false);
CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, certificate);
// create the signature
signedCms.ComputeSignature(signer);
return signedCms.Encode();
}
and verify the signature like this
private static bool VerifySignatures(FileInfo contentFile, Stream signedDataStream)
{
CmsProcessable signedContent = null;
CmsSignedData cmsSignedData = null;
Org.BouncyCastle.X509.Store.IX509Store store = null;
ICollection signers = null;
bool verifiedStatus = false;
try
{
//Org.BouncyCastle.Security.addProvider(new BouncyCastleProvider());
signedContent = new CmsProcessableFile(contentFile);
cmsSignedData = new CmsSignedData(signedContent, signedDataStream);
store = cmsSignedData.GetCertificates("Collection");//.getCertificates();
IX509Store certStore = cmsSignedData.GetCertificates("Collection");
signers = cmsSignedData.GetSignerInfos().GetSigners();
foreach (var item in signers)
{
SignerInformation signer = (SignerInformation)item;
var certCollection = certStore.GetMatches(signer.SignerID);
IEnumerator iter = certCollection.GetEnumerator();
iter.MoveNext();
var cert = (Org.BouncyCastle.X509.X509Certificate)iter.Current;
verifiedStatus = signer.Verify(cert.GetPublicKey());
}
}
catch (Exception e)
{
throw e;
}
return verifiedStatus;
}
It is working for me
I have a valid PKCS7 file loaded into a CMSSignedData object.
This PKCS7 file includes a plain text message and a valid attached digital signature (all in the same file).
Now I want to timestamp this file. This is the code I'm using (source):
private static CMSSignedData addTimestamp(CMSSignedData signedData)
throws Exception {
Collection ss = signedData.getSignerInfos().getSigners();
SignerInformation si = (SignerInformation) ss.iterator().next();
TimeStampToken tok = getTimeStampToken();
ASN1InputStream asn1InputStream = new ASN1InputStream
(tok.getEncoded());
DERObject tstDER = asn1InputStream.readObject();
DERSet ds = new DERSet(tstDER);
Attribute a = new Attribute(new
DERObjectIdentifier("1.2.840.113549.1.9.16.2.14"), ds);
DEREncodableVector dv = new DEREncodableVector();
dv.add(a);
AttributeTable at = new AttributeTable(dv);
si = SignerInformation.replaceUnsignedAttributes(si, at);
ss.clear();
ss.add(si);
SignerInformationStore sis = new SignerInformationStore(ss);
signedData = CMSSignedData.replaceSigners(signedData, sis);
return signedData;
}
private static TimeStampToken getTimeStampToken() throws
Exception {
Security.addProvider (new
org.bouncycastle.jce.provider.BouncyCastleProvider());
PostMethod post = new PostMethod("http://My-TrustedTimeStampProvier.com");
// I'm omitting the part where I pass the user and password
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
//request TSA to return certificate
reqGen.setCertReq (true); // In my case this works
//make a TSP request this is a dummy sha1 hash (20 zero bytes)
TimeStampRequest request =
reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
byte[] enc_req = request.getEncoded();
ByteArrayInputStream bais = new ByteArrayInputStream(enc_req);
post.setRequestBody(bais);
post.setRequestContentLength (enc_req.length);
post.setRequestHeader("Content-type","application/timestamp-query");
HttpClient http_client = new HttpClient();
http_client.executeMethod(post);
InputStream in = post.getResponseBodyAsStream();
//read TSP response
TimeStampResponse resp = new TimeStampResponse (in);
resp.validate(request);
TimeStampToken tsToken = resp.getTimeStampToken();
return tsToken;
}
I can get a valid TimeStamp, and I could put it into my CMSSignedData object and save it to a file writting the bytes from signedData.getEncoded() to the harddisk. But when I validate my new shinny timestamped file with a third party software, this software tells the original signature is ok, but the Timestamp doesn't correspond with the signature. This software also can show me the original plain text message.
I think the problem is in this line:
TimeStampRequest request =
reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));
I think I have to pass a digest instead of a dummy byte array, but I don't know which digest, or what are the right bytes I have to timeStamp.
I successfully could get and verify a SignerInformation object from my signedData. Then I tried to pass to the reqGen.generate() function the bytes from mySignerInformation.getSignature(). The timestamp verification failed. Then I passed a Sha1 digest of mySignerInformation.getSignature(), but my timestamp verification failed again.
The RFC3161 specification says:
2.4.1. Request Format
A time-stamping request is as follows:
TimeStampReq ::= SEQUENCE { version INTEGER
{ v1(1) }, messageImprint MessageImprint,
--a hash algorithm OID and the hash value of the data to be
(...)
The messageImprint field SHOULD contain the hash of the datum to be
time-stamped. The hash is represented as an OCTET STRING. Its
length MUST match the length of the hash value for that algorithm
(e.g., 20 bytes for SHA-1 or 16 bytes for MD5).
MessageImprint ::= SEQUENCE {
hashAlgorithm AlgorithmIdentifier,
hashedMessage OCTET STRING }
But it doesn't tell me where or how I get the MessageImprint data if I want to TimeStamp the bytes inside a CMSSignedData object.
I'm a newbie in this digital signature stuff.
You're right, the problem is that you're timestamping the incorrect data. The rest of the code seems correct to me.
So the thing is that you've to timestamp the hash of the signature. To get the signature from your CMSSignedData and hash it; you can use the follow code (supposing that you've only one signer in your PKCS7 and you're using SHA1 hash algorithm):
CMSSignedData signedData = ...
// get the signers of your CMSSignedData signedData
Collection ss = signedData.getSignerInfos().getSigners();
SignerInformation si = (SignerInformation) ss.iterator().next();
// hash the signature
byte[] signDigest = MessageDigest
.getInstance(TSPAlgorithms.SHA1, new BouncyCastleProvider())
.digest(si.getSignature()); // since you're adding the bc provider with Security.addProvider you can use "BC" instead of passing the new BouncyCastleProvider()
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
// generate the TSRequest
TimeStampRequest request =
reqGen.generate(TSPAlgorithms.SHA1, signDigest, BigInteger.valueOf(100));
...
Hope this helps,