I have a servlet and the content type of my request is of type : application-pkcs-7
And how do i decode the request ?
Any ideas ?
I learnt that i can use openssl to decode , but not much docs on that .
That's probably a signature or an encrypted piece of data. It's old name is PKCS-7 (of RSA labs, publicly available standard) but it is also known as CMS (Cryptographic Message Syntax, publicly available RFC). CMS is a container format for different kinds of encryption. You can parse it in Java using the open source Bouncy Castle libraries - "bcmail" in particular, but you probably need some kind of key if it is encrypted. If it is signed, you could simply parse the plain text data from it and ignore the signature, I guess, depends on the application really.
[UPDATE] Since 1.47 the necessary functionality is in the PKIX library of Bouncy Castle.
Should work in this way
CMSSignedData cmsSignedData = new CMSSignedData(byte[] signedData);
CMSProcessable cmsProcessable = cmsSignedData.getSignedContent();
In my case it didn't though, because of unknown tag entry while parsing data
Related
I'm stumped trying to figure out Esig DSS java suite just from docs and source.
(eu.europa.esig.dss.* tree)
We connect to Swedish BankID to sign PDF's and simple plain texts.
Response is a SOAP XML with fields for the signature and an OCSP response.
The end goal is to combine these two parts into a single object "a valid signature" that can be embedded in a PDF (using DSS and PDFbox).
The contents of the BankID Soap fields seems to have the right format for DSS tools:
The signature can be loaded with
DSSDocument sigDoc = new InMemoryDocument(xmlSignature)
SignedDocumentValidator documentValidator = SignedDocumentValidator.fromDocument(sigDoc);
// ...
AdvancedSignature advancedSignature = documentValidator.getSignatures().get(0);
and the OCSP response can be read with
ExternalResourcesOCSPSource source = new ExternalResourcesOCSPSource(ocspBytes);
BasicOCSPResp basicOCSPResp = source.getContainedOCSPResponses().get(0);
I can print out various info from the objects, find embedded certificates etc, so the format seems legit.
Question:
How do I get a valid OCSPToken from the ExternalResourcesOCSPSource?
I keep running in circles trying to combining the two into a single AdvancedSignature (if that's what I can use to embed into a PDF).
An advanced digital signature provided by a third system can not be used to create a valid signed PDF
A PAdES signature is always enveloped into a PDF document, so it is not possible for the signature service to be returning a detached PAdES signature that is considered valid by DSS.
It probably provides a detached CAdES or XAdES signature into the SOAP message that can be processed by DSS( DSS provides a high level API to sign documents using XAdES, CAdES, PAdES and aSiCS formats).
Both formats support embedding the OCSP responses, but it requires to add a TimeStamp too, which make more difficult to build the final format. It could be the reason to use a custom field into the SOAP message to return the OCSP response
XAdES and PAdES are conceptually similar but structurally different. A XAdES signature is XML and PAdES is binary. A XML signature can not be converted to PAdES
PAdES and CAdES use CMS, both are binary and they use ASN.1 syntax. But the signed message is different, CAdES signature is calculated on the entire document (and some othe attributes) and PAdes use certain data of the PDF document. Therefore a cades signature could not be converted to PAdes either.
Is not so clear to me how to check and parse value passed by this partial response envelope in SAML 2.0:
<dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
<dsig:SignedInfo><dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/><dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<dsig:Reference URI="#ID_ce8c62aa-08e4-4a21-a89a-af4fbd7a9f50">
<dsig:Transforms><dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<dsig:DigestValue>ImUVGjTf7WTCmboAbAtjx7WKQhI=</dsig:DigestValue>
</dsig:Reference>
</dsig:SignedInfo>
<dsig:SignatureValue>CDk+O/3PPh57l84pjFW0xwiPYJ+yinYJciBowT3nkPaAXeMYCH1AopZl7ZP+swPiK+oYuW9STPSlJVuEuDao5VbSU2WlQR7Ed9nZMt9PNY19/eKtkAqbMk01ZY8YH6OyTQm17w6IzNRbY4sJcHSRz9eDUsTzAYVhV9PEBgT1ouZsghklMCe0iYBjK5LmRS88jGmCN5sZ5+L8+KimTCakWSJ8CLntEAFx1SBL50Or4e8j6nHiW7g==</dsig:SignatureValue>
<dsig:KeyInfo>
<dsig:KeyValue>
<dsig:RSAKeyValue>
<dsig:Modulus>4Gvzu2dCYGhdWr9Er/WtgbWRqAR798IPCfAubx8NeBKG/X6P7sM91zbD2LEH4tJS2vkMCnQFidoLdeh1SHp7+GLHnVsgTcj6NPOit0EOHz10tdRmFMwoRCh5hcMFEisFUgSdaS8bO2wSXBmLENfLDUOSYKKLP0JGtTqnAZ0A99UNrVWKemx/EnHopH+Q7M+zmbj8VWFVlCK6rDfXJLUBr+kGSlw==</dsig:Modulus>
<dsig:Exponent>AQAB</dsig:Exponent>
</dsig:RSAKeyValue>
</dsig:KeyValue>
</dsig:KeyInfo>
</dsig:Signature>
So basically the RSAKeyValue should contain the "public key" to read the DigestedValue?
So what's the purpose of the Signature value?
I would like to implement a Java class to decrypt (I have the proper keystore and pass to do that...). Please point me in the right direction.
As written in the comment, it's an XML signature. The signature allows you to validate the XML has been signed by a trusted party and the element hasn't been modified. So you can trust the SAML response is really from the IdP you can trust. It is not encryption.
I would like to implement a Java class to decrypt
As I stated there's nothing to decrypt, you can only validate integrity of the signed XML element.
For that I suggest you use an out of box library to process the XML (it will be boring to implement all canonization options, etc..). I suggest you use an out of box library ( OpenSAML, spring-security-saml2) to validate the signature.
if you want to do it yourself, just read search/about the XML signatures.
What you have there:
<dsig:Reference URI="#ID_ce8c62aa-08e4-4a21-a89a-af4fbd7a9f50">
There must be an element in your XML with id attribute of "#ID_ce8c62aa-08e4-4a21-a89a-af4fbd7a9f50" and the signature ensures integrity of the refered XML element. Make sure the signature is refered to the whole SAML message or an assertion element. If not, you're code would be prone to signature injection attacks. That's why I suggest you use a mature library for that.
<dsig:DigestValue>ImUVGjTf7WTCmboAbAtjx7WKQhI=</dsig:DigestValue>
RSA doesn't work with messages of arbitrary (any) length, so a message digest (sha-1 hash) is created and that is signed. The DigestValue is value of the hash created from the signed XML element and its content. (how to create a whole content to be hashed is depending on the parameters stated in the CanonicalizationMethod, Transforms, DigestMethod, you can read about it in the first link)
<dsig:SignatureValue>
This is the RSA/PKCS1.5 signature of the DigestValue
I hope that clarifies your question.
I am using BouncyCastle to generate a DSA signature but using the native JCE to verify the it.
NOTE: I am working with a j2me client that does not natively support signing hence the need for BouncyCastle)
So, on the client the signature is generated as follows:
DSASigner sig = new DSASigner();
sig.init(true, privateKey);
String plaintext = "This is the message being signed";
BigInteger[] sigArray = sig.generateSignature(plaintext.getBytes());
...
sigArray contains 2 BigIntegers r and s.
This signature then has to be transmitted to a server which uses native JCE to verify the sig. On the server side, using the native Java JCE, it should be possible to verify a signature as follows:
...
Signature sig = Signature.getInstance("SHA1withDSA");
byte[] sigbytes = Base64.decode(signature);
sig.initVerify(publicKey);
sig.update(plaintext.getBytes());
sig.verify(sigbytes)
The problem am having is: how do i encode sigArray into a format that can be sent to the pc/server as a single Base64 string (instead of separately as r and s) that can then be verified on the server using the native JCE method show in the second snippet of code?
So far i have tried to create DERObjects from the r,s arrays (separately, together as one array, encoded) but still no luck. Anybody faced this before? How did you tackle it?
According to Cryptographic Message Syntax Algorithms (RFC 3370) the DSA signature encoding is an ASN.1 sequence containing both integers r and s:
Dss-Sig-Value ::= SEQUENCE {
r INTEGER,
s INTEGER }
I have a java application that signs a string using a certificate. It works encrypting the string it with SHA1. I am trying to translate the code to Delphi 2010, but I have no idea how to get it working the same way the java app does (using sha1). So far, I have found this:
Delphi 7 access Windows X509 Certificate Store
It does work, but it does not use sha1 and I get different results when I run the java app.
Java code
char[] pass = (char[]) null;
PrivateKey key = (PrivateKey) getKeyStore().getKey(alias, pass);
Certificate[] chain = getKeyStore().getCertificateChain(alias);
CertStore certsAndCRLs = CertStore.getInstance("Collection", new CollectionCertStoreParameters(Arrays.asList(chain)), "BC");
X509Certificate cert = (X509Certificate) chain[0];
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addSigner(key, cert, CMSSignedDataGenerator.DIGEST_SHA1);
gen.addCertificatesAndCRLs(certsAndCRLs);
CMSProcessable data = new CMSProcessableByteArray(conteudoParaAssinar);
CMSSignedData signed = gen.generate(data, true, "SunMSCAPI");
byte[] envHex = signed.getEncoded();
CertInfo certInfo = new CertInfo();
certInfo.Hash = new BigInteger(envHex).toString(16);
return certInfo;
Delphi Code
var
lSigner: TSigner;
lSignedData: TSignedData;
fs: TFileStream;
qt: integer;
ch: PChar;
msg : WideString;
content : string;
cert: TCertificate;
begin
cert := Self.GetCert;
content := 'test';
lSigner := TSigner.Create(self);
lSigner.Certificate := cert.DefaultInterface;
lSignedData := TSignedData.Create(self);
lSignedData.content := content;
msg := lSignedData.Sign(lSigner.DefaultInterface, false, CAPICOM_ENCODE_BASE64);
lSignedData.Free;
lSigner.Free;
EDIT
Based on the java code, should I get the cert info in binary format, apply sha1 on it and them convert it to hex? Is this the right order and the same thing the java code does? I can see some SHA1 constants in the capicom tlb as well as a hash class, maybe I should use those classes, but I dont know how.
We use DCPCrypt in some delphi apps that interface with our Java Tomcat App and are able to get SHA-256 compatible hashes. I suspect SHA1 is also easy.
Here's an example
function Sha256FileStreamHash(fs : TFileStream): String;
var
Hash: TDCP_sha256;
Digest: array[0..31] of byte; // RipeMD-160 produces a 160bit digest (20bytes)
i: integer;
s: string;
begin
if fs <> nil then
begin
fs.Seek(0, soFromBeginning);
Hash:= TDCP_sha256.Create(nil); // create the hash
try
Hash.Init; // initialize it
Hash.UpdateStream(fs,fs.Size); // hash the stream contents
Hash.Final(Digest); // produce the digest
s:= '';
for i:= 0 to 31 do
s:= s + IntToHex(Digest[i],2);
Result:= s; // display the digest
finally
Hash.Free;
end;
end;
end;
First, what makes you think you're not using SHA-1 ? I'm asking because CAPICOM's sign function only works with SHA-1 signature.
Second, how do you know that you're getting a different result ? Have you tried to validate the answer ? If yes, using what ?
Third, there is something that you MUST know about CAPICOM: the "content" property is a widestring. This has various implication, including the fact that all content will be padded to 16-bits. If your input data is of different size, you'll get a different result.
Based on the java code, should I get the cert info in binary format, apply sha1 on it and them convert it to hex?
No. You get an interface to an instance of a ICertificate object (or, more likely, ICertificate2) and you just use that directly. If you have the B64 encoded version of the certificate, you can create a new ICertificate instance and then call the ICertificate.Import method. The hash of the certificate itself is only used by the signing authority to sign that specific cert.
The hash algorythm is actually used during the data signature process: the library reads the data, creates a hash of that data (using SHA-1 in case of CAPICOM) and then digitally sign that hash value. This reduction is necessary because signing the whole data block would be far too slow and because, that way, you only have to carry the hash if you're using a hardware crypto system.
Is this the right order and the same thing the java code does?
Yes and no. The Java code does all the necessary steps in explicit details, something you don't have (and actually cannot) do with CAPICOM. It should result in compatible result, though.
It also has an additional step not related to the signature itself: I'm not sure what it does because it seems to create a dummy certificate information data and store the SHA-1 hash value of the signed CMS message and return the resulting instance. I suppose that it's a way the Java dev has found to pass the hash value back to the caller.
I can see some SHA1 constants in the capicom tlb as well as a hash class, maybe I should use those classes, but I dont know how.
The HashedData class is used to (surprise) hash data. It has the same limitation as Signeddata i.e. it only works on widestrings so compatibility with other frameworks is dodgy at best.
Final note: Windows offers access to much more comprehensive cryptographic functions through the CAPI group of functions. CAPICOM is only an interface to that library that is used (mostly) in script language (JavaScript on web pages, VB, etc). You should do yourself a favor and try using it instead of CAPICOM because there is a good chance you'll encounter something that you simply cannot do properly using CAPICOM. At that stage, you will have to rewrite part for all of your application using CAPI (or another library). So save time now and skip CAPICOM if you don't have a requirement to use it.
I have a signedCMS, and would like to know how to use Bouncy Castle API to remove the signature so I can have clear access to the plain text file underneath?
Thanks
Something like this might work:
CMSSignedData signedData = new CMSSignedData(signedFileBytes);
// Now get the content contained in the CMS EncapsulatedContentInfo
CMSProcessable processable = signedData.getSignedContent();
You should then be able to get a stream on processable from which the data can be read.