Signature cryptographic validation not successful opensaml - java

I am trying to do signature validation on SAML2 Response which is obtained from an identity provider using OpenSAML. I am trying to read the response from the localfile system.
Here is my code:
DefaultBootstrap.bootstrap();
BasicParserPool ppMgr = new BasicParserPool();
ppMgr.setNamespaceAware(true);
//Read file from the filesystem
File file1=new File("F:/Softwares/Assertion.xml");
InputStream inCommonSaml=new FileInputStream(file1);
// Parse file
Document inCommonSamlDoc = ppMgr.parse(inCommonSaml);
Element metadataRoot = inCommonSamlDoc.getDocumentElement();
UnmarshallerFactory unmarshallerFactory=configuration.getUnmarshallerFactory();
Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(metadataRoot);
Response inCommonSamlRes = (Response) unmarshaller.unmarshall(metadataRoot);
//Get certificate
SignatureValidator signatureValidator = new SignatureValidator(cert);
Signature signature=inCommonSamlRes.getSignature();
signatureValidator.validate(signature);
try {
BasicX509Credential credential = new BasicX509Credential();
File file2=new File("F:/Softwares/publicKey.crt");
InputStream samlCertificate=new FileInputStream(file2);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
//
#SuppressWarnings("deprecation")
java.security.cert.X509Certificate certificate = (java.security.cert.X509Certificate) certificateFactory.generateCertificate(samlCertificate);
//
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec((certificate).getPublicKey().getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey key = keyFactory.generatePublic(publicKeySpec);
credential.setPublicKey(key);
Object obj = (credential).getPublicKey();
if (obj instanceof RSAPublicKey) {
BigInteger modulus = ((RSAPublicKey) obj).getModulus();
BigInteger exponent = ((RSAPublicKey) obj).getPublicExponent();
System.out.println("modulus");
System.out.println (org.apache.commons.codec.binary.Base64.encodeBase64String(modulus.toByteArray()));
System.out.println("public exponent:");
System.out.println (org.apache.commons.codec.binary.Base64.encodeBase64String(exponent.toByteArray()));
}
// System.out.println ("public key is: //n//r"+ credential.getPublicKey());
return credential;
} catch (Exception e) {
throw e; //Throws a 'Signature did not validate against the credential's key' exception
}
Note: I use the same certificate(publicKey.crt) to sign the assertion also.
I am getting the following error:
signature cryptographic validation not successful.
Please let me know where am I wrong? What does the error mean? Does it say that public and private keys are the same?
Thanks,
aswini J

I think you need to get .jks file from IdP (Identity Provider) server. Also when you're getting SAMLResponse from for your POST from IDP, this SAMLResponse should be containing Signature (FYI - will be an encoded string, you can decode and read using Open SAML library, available on Maven Central Repository).
Once you get signature from , you can validate that using OpenSAML
sigValidator.validate(response.getSignature());
This method will give you meesage if everything is OK. The message for reference "Signature validated with key from supplied credentia"
You can follow this link: http://sureshatt.blogspot.in/2012/11/how-to-read-saml-20-response-with.html to get Signature and
(IMP): Your IDP (Identity Provider) should be send (may be via HTTP POST), so that you can get from which can have NameID i.e, ClinetId

This answer is for incoming people getting this error and searching on Google.
In my case, I am facing the same error :"error: signature cryptographic validation not successful", with a slightly different case. I am validating with SimpleSamlPHP as SP and CAS as IDP.
The problem was that my SP uses one (self-signed) cert for SP validation to IDP, and another cert for SP in Apache to make allow SSL (so that I can have https)
Using two separate cert might works fine for a lot of process like login and metadata validation, but with prcess like logout the above error will happen.
The solution is to use only one cert for both process, and my error is gone.

Related

How to find the PrivateKey for decrypt smime.p7m message with RecipientInformation?

I try to use the follow Java code to decrypt a S/MIME message from the JavaMail API:
String mimeType = mail.getContentType();
if( mimeType == null ) {
return mail;
}
ContentType contentType = new ContentType( mimeType );
if( "application/pkcs7-mime".equals( contentType.getBaseType() ) //
&& "smime.p7m".equals( contentType.getParameter( "name" ) ) ) {
Object content = mail.getContent();
if( content instanceof InputStream ) {
CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser( (InputStream)content );
RecipientInformationStore recipients = ep.getRecipientInfos();
Iterator<RecipientInformation> it = recipients.getRecipients().iterator();
RecipientInformation recipient = (RecipientInformation) it.next();
recipient.getContent(new JceKeyTransEnvelopedRecipient(privateKey).setProvider( provider) );
}
}
I have a list of PrivateKeys. How can I find the right PrivateKey to pass in the JceKeyTransEnvelopedRecipient constructor? I think that this should be possible with the RecipientInformation object.
S/MIME messages are usually encrypted using publickey from a certificate specifically an X.509 or PKIX certificate (PKIX is the Internet 'version' or technically profile of X.509) and KeyTransRI -- if that is indeed what you have, your code doesn't check -- or KeyAgreeRI contains a 'recipient id' which actually identifies the certificate; you are expected to map that certificate to the corresponding privatekey, which is how Java crypto normally works (the KeyStore API stores a privatekey with its corresponding certificate or chain).
RecipientInformation.getRID() returns a RecipientId, normally KeyTransRecipientId or KeyAgreeRecipientId corresponding to the RecipientInfo, either of which allows you to get the issuer and serial of the cert, or the 'subject key identifier' an extension in most certs that normally contains a hash of its subject key bit-string value.
Similarly signing is done with the privatekey, and SignerInfo includes the id of the corresponding certificate, which is distributed to and used by reliers to verify the signature.

how to : iTextSharp 5.5 sign hash that was generated by Java iText 5.5

I am going to sign a PDF from the client site.
I will create a web service to generate the PDF hash using itext5.5 (Java), and then send to the client agent to sign that hash (using iTextSharp-5.5), and send back the signed hash to the web service for closing the signature state.
But the signed PDF got the following error when validate the signature:
Error during signature verification.
Error encountered while BER decoding:
in the server side (Java):
ExternalDigest externalDigest = new BouncyCastleDigest();
PdfPKCS7 sign = new PdfPKCS7(null, chain, "SHA1", null, externalDigest, false);
InputStream data = appearance.getRangeStream();
byte[] digestHash = DigestAlgorithms.digest(data, externalDigest.getMessageDigest(hashAlgorithm));
ocsp = null;
if (chain.length >= 2 && ocspClient != null) {
ocsp = ocspClient.getEncoded((X509Certificate)chain[0], (X509Certificate)chain[1], null);
}
byte[] sh = sign.getAuthenticatedAttributeBytes(digestHash, signCal, ocsp, crlBytes, SIGN_TYPE);
this.hash = digestHash;
this.hashForSign = sh;
in C#, I using the following code to sign:
IExternalSignature es = new X509Certificate2Signature(cert, "SHA1");
byte[] signedHash = es.Sign(hashForSign);
Where this.hashForSign is the hash generate from Java, and the signedHash is signed in C#.
Please help!
Best regards,
Eric
I had a similar problem. This wasn't a Java language issue. One way to solve it is to do the following:
Go to the Windows Certificate Manager (certmgr.msc)
Try deleting all certificates under Personal
Recreate an ID in Adobe using Security settings.

Use certificate to make API requests in Java

Below I have included code that takes a Thumbprint of a certificate as an argument and then loads the appropriate cert from the Windows certificate store.
This was done because now I would like to use the found cert to make API calls to an API that requires this certificate- if the certificate is not included in the request the API will reject me as unauthorized.
I have previously done this in C# and it was quite simple as I was able to just create a clientHandler that identified the protocol, callback, and certificate that allowed for creation of a usable HttpClient. Java is significantly more complicated and is giving me issues since it appears I must work with the keymanager(and possibly trustStore and SSLContext). In other words I am having a hard time understanding how to use these objects to send my certificate to the API with my request.
I realize I may not be able to simply build the client with the cert to get the successful connection. But how can I use the x509certificate that I have in memory to successfully send requests to the API.
I am not looking for a solution that will 100% work for my case, I would just like to see a clean example of how to send an API request with the certificate(in whichever way the libraries require) in Java.
public static X509Certificate LoadCert(String inThumbprint) {
X509Certificate ReturnCert = null;
try{
KeyStore keyStore = KeyStore.getInstance("Windows-MY");
keyStore.load(null, null); // Load keystore
String currentAlias;
X509Certificate foundCert;
String calculatedThumbprint;
for (Enumeration<String> oEnum = keyStore.aliases(); oEnum.hasMoreElements();) {
currentAlias = oEnum.nextElement(); System.out.println(currentAlias);
foundCert = (X509Certificate) keyStore.getCertificate(currentAlias);
calculatedThumbprint = getThumbprint(foundCert); System.out.println(calculatedThumbprint);
if (calculatedThumbprint.equals(inThumbprint)) {
ReturnCert = foundCert;
}
}
} catch (Exception ex){
ex.printStackTrace();
}
return ReturnCert;
}
private static String getThumbprint(X509Certificate cert)
throws NoSuchAlgorithmException, CertificateEncodingException {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] der = cert.getEncoded();
md.update(der);
byte[] digest = md.digest();
String digestHex = DatatypeConverter.printHexBinary(digest);
return digestHex.toLowerCase();
}

Encrypting a string using private key in php

I need to integrate with some service provider API, where each request needs to be signed with private key of our certificate and service provider will decrypt it using our public key and similarly for response service provider will encrypt it using their private key and we will decrypt it using their public key (Means we will share our Public Key between each other)
Service Provider did not have sample code in php
Instructions which they provided are:
Get contents in Bytes to Sign (Using UTF-8 Encoding)
Get the X509 Certificate (Private Key Certificate)
Compute the Message Digest
Sign the Message and generate attached Signature
(use Detached/attached property of Signing Library)
Encode your Signed Message into Base64 Encoding
Send the Encoded Message on HTTP
Sample Code in Java provided by service provider:
string data = "SAMPLE REQUEST XML";
priv = (PrivateKey)keystore.getKey(name, passw);
CMSSignedDataGenerator sgen = new CMSSignedDataGenerator();
sgen.addSigner(priv, (X509Certificate)cert, CMSSignedDataGenerator.DIGEST_SHA1);
sgen.addCertificatesAndCRLs(certs);
byte[] utf8 = data.getBytes("UTF8");
// The 2nd parameter need to be true (dettached form) we need to attach original message to signed message
CMSSignedData csd = sgen.generate(new CMSProcessableByteArray(utf8), true, "BC");
byte[] signedData = csd.getEncoded();
char[] signedDataB64 = Base64Coder.encode(signedData);
String str = new String(signedDataB64);
I have written following code in php:
$utf8_data = utf8_encode($xmlString);
$byte_array = unpack('C*', $utf8_data);
$bytesStr = implode("", $byte_array);
$data = file_get_contents('/path/to/abc.pfx');
$certPassword = 'certpassword';
openssl_pkcs12_read($data, $certs, $certPassword);
$private_key = $certs['pkey'];
$binary_signature = "";
openssl_sign($bytesStr, $binary_signature, $private_key, OPENSSL_ALGO_SHA1);
Now my question is my above code correct ? Also how openssl_sign give me signature + sample request data,
As i am not able to generate same encoded string which service provider has provided into their sample,

Generate valid CMS Signature file adding external PKCS#1 with Java

I'm generating CMS signature files with external PKCS#1 based on this thread.
The first step is obtain the signed attributes from the original file to be signed in external application which is returning PKCS#1 byte array.
Then build standard org.bouncycastle.cms.SignerInfoGenerator with original file hash, signed data (PKCS#1) and certificate to add to CMS, and finally create the attached signature.
But when i'd tried to validate it using this code:
String originalFile = "aG9sYQ0KYXNkYXMNCg0KYWZzDQo=";
String cmsSignedFile = "MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBg...j2Dwytp6kzQNwtXGO8QbWty1lOo8oYm+6LR8EWba3ikO/m9ol/G808vit9gAAAAAAAA==";
byte[] signedByte = DatatypeConverter.parseBase64Binary(cmsSignedFile);
Security.addProvider(new BouncyCastleProvider());
CMSSignedData s = new CMSSignedData(new CMSProcessableByteArray(DatatypeConverter.parseBase64Binary(originalFile)), signedByte);
SignerInformationStore signers = s.getSignerInfos();
SignerInformation signerInfo = (SignerInformation)signers.getSigners().iterator().next();
FileInputStream fis = new FileInputStream("C:/myCertificate.cer");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificates(fis).iterator().next();
boolean result = signerInfo.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert.getPublicKey()));
System.out.println("Verified: "+result);
I get Verified: false
I'm adding Content Type, Signing time, Message digest and OCSP as signed attributes and TSP Token as unsigned attribute (I'm not sure if this is right).
I'm also trying to recover data from CMS signature, using the code below:
//load cms signed file with attached data
CMSSignedData cms = new CMSSignedData(FileUtils.readFileToByteArray(new File("C:/tmp/tempFile1864328163858309463.cms")));
System.out.println(cms.getSignerInfos().getSigners().iterator().next().getDigestAlgorithmID().getAlgorithm().getId());
System.out.println(Hex.encodeHexString(cms.getSignerInfos().getSigners().iterator().next().getSignature()));
//recover signer certificate info
Store certs = cms.getCertificates();
Collection<X509CertificateHolder> col = certs.getMatches(null);
X509CertificateHolder []h1 = col.toArray(new X509CertificateHolder[col.size()]);
X509CertificateHolder firmante = h1[0];
System.out.println(firmante.getSubject());
System.out.println(h1[1].getSubject());
SignerInformation sinfo = cms.getSignerInfos().getSigners().iterator().next();
//recover OCSP information
//THIS FAILS :(
// Store infocspbasic = cms.getOtherRevocationInfo(OCSPObjectIdentifiers.id_pkix_ocsp_basic);
// Object basic = infocspbasic.getMatches(null).iterator().next();
//recover signing time
if (sinfo.getSignedAttributes() != null) {
Attribute timeStampAttr = sinfo.getSignedAttributes().get(PKCSObjectIdentifiers.pkcs_9_at_signingTime);
ASN1Encodable attrValue = timeStampAttr.getAttrValues().getObjectAt(0);
final Date signingDate;
if (attrValue instanceof ASN1UTCTime) {
ASN1UTCTime time = ASN1UTCTime.getInstance(attrValue);
Date d = time.getDate();
System.out.println("ASN1UTCTime:" + d);
} else if (attrValue instanceof Time) {
signingDate = ((Time) attrValue).getDate();
} else if (attrValue instanceof ASN1GeneralizedTime) {
System.out.println("ASN1GeneralizedTimeASN1GeneralizedTime");
} else {
signingDate = null;
}
}
//recover timestamp TOken
//unsigned attributes are null :(
if (sinfo.getUnsignedAttributes() != null) {
Attribute timeStampAttr = sinfo.getUnsignedAttributes().get(PKCSObjectIdentifiers.id_aa_signatureTimeStampToken);
for (ASN1Encodable value : timeStampAttr.getAttrValues().toArray()) {
TimeStampToken token = new TimeStampToken(new CMSSignedData(value.toASN1Primitive().getEncoded()));
System.out.println(token.getTimeStampInfo().getGenTime());
}
}
But I can't retrieve OCSP response nor TSP Token information. Additionally I've downloaded this viewer software to help verify it:
Any help would be very appreciated.
I found a project named j4sign which implements CMS signature with external PKCS#1. The link goes to the project's forum where I posted the code sample using their classes and the final correction to make the validation works.

Categories