How to verify the digital signature of downloaded xml file in java - java

I have an XML file, given below
<OfflinePaperlessKyc referenceId="686820201209011401091">
<UidData>
<Poi dob="21-01-1945" e="bd05902a34b7b9e4d92230ac6b0asded072c1c0945190ad357f9ceec387f6fd6" gender="M" m="ed4eeb1376575c1b59096cf5c41243re5f3d4146e0c63eb4cc08a6c22fa9afe5" name="Reepak Sangid"/>
<Poa careof="S/O John Uncle" country="India" dist="Jaipur" house="1134 - B" landmark="80 Feet Road 200 Feet Baypass ke pass" loc="Heerapura Ajmer Road" pc="302024" po="" state="Kerala" street="Heera Nagar" subdist="" vtc="Jaipur"/>
</UidData>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>+ribhQOajFYDHgBTkjU0LSHWxRWpBkkrh4FbUj+RVss=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>qGxO1EURe+FOr0mBocWvBDGuZm3ssVu6dYwSs5IvuA2OhlqH+Cp2WSQ3OKFvLZPfVSXBDNy/zC2F M5NI7RJjl2KaCMX+Qhko7UTpQp/8a/gX3jjcRP5Az8w4GQONIuZhLjUXxqgA4ln0y8vqfEhqdtVk 407QopDyNx6UH9VFCgmGjcDggLUgam1gG4P8Hka3WxT0BFTL7CWO4yVPRwEs8IvhcNvm8Db7p50a qWMwfOmNQQ/G7uj+tQ2wEKzWPcBoeQ6/qGCGfN+1Wt0gmEWIxYaKEDz9kQb8eiYOQSaht+2QzOX7 68gMrDXSms6ljrcklqmVrXwKvJXe5L0tfbNBuA==</SignatureValue>
</Signature>
</OfflinePaperlessKyc>
Here some details about signature:
signature - Signature: – This will a 344 character long digital signature of the data present in the downloaded XML. This can be validated using the public key of UIDAI which will be present in standard signed XML.
Here are the steps provided by the website from which the XML is downloaded:
Steps to validate the signature :
Read the entire XML.
Get signature from XML
Get Certificate from here.
Convert the certificate to base64 string.
Sample code snippets provided here.
Here is the text in the certificate file
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
How can I verify the digital signature provided in the XML file using the certificate file. I have searched many questions but they did not work for me. Thanks in advance.
Here is what I tried:
String certificate = "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";
byte[] decoded = Base64.getDecoder().decode(certificate.getBytes());
String signatureValue = "qGxO1EURe+FOr0mBocWvBDGuZm3ssVu6dYwSs5IvuA2OhlqH+Cp2WSQ3OKFvLZPfVSXBDNy/zC2F M5NI7RJjl2KaCMX+Qhko7UTpQp/8a/gX3jjcRP5Az8w4GQONIuZhLjUXxqgA4ln0y8vqfEhqdtVk 407QopDyNx6UH9VFCgmGjcDggLUgam1gG4P8Hka3WxT0BFTL7CWO4yVPRwEs8IvhcNvm8Db7p50a qWMwfOmNQQ/G7uj+tQ2wEKzWPcBoeQ6/qGCGfN+1Wt0gmEWIxYaKEDz9kQb8eiYOQSaht+2QzOX7 68gMrDXSms6ljrcklqmVrXwKvJXe5L0tfbNBuA==";
byte[] aadharSignature = signatureValue.getBytes();
//Creating KeyPair generator object
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(2048);
KeyPair pair = keyPairGen.generateKeyPair();
PrivateKey privKey = pair.getPrivate();
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(privKey);
signature.update(aadharSignature);
//Initializing the signature
signature.initVerify(pair.getPublic());
signature.update(decoded);
//Verifying the signature
boolean bool = signature.verify(decoded);
if(bool) {
System.out.println("Signature verified");
} else {
System.out.println("Signature failed");
}
But this does not work and generates an error while generating the key.

Related

Signature Verification in Java for RSA SHA-256

EDIT - Updated with full SAML
I'm trying to verify a signature I receive from a SAML Response in Java. The SAML Response is validated by samltool.io, but I am having a difficult time with the Signature class in java. No matter what I try, it's returning false. I have properly canonicalized my XML and I am able to successfully generate the correct MessageDigest with what I have in my content String. Hopefully someone can point out what I'm doing wrong. Here is my code:
public class SigVer {
public static void main(String[] args) throws Exception {
System.out.println("Initialized");
String pubKeyStr = "MIIDqDCCApCgAwIBAgIGAYXQr1PhMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi02MjkxNDMxMjEcMBoGCSqGSIb3DQEJARYNaW5mb0Bva3RhLmNvbTAeFw0yMzAxMjAxOTM2MDlaFw0zMzAxMjAxOTM3MDlaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi02MjkxNDMxMjEcMBoGCSqGSIb3DQEJARYNaW5mb0Bva3RhLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMgSFX7FkFVNzGyL7EjtIRaJRmj7/Z8diMZyAVy0rBqcIB7aL9Hn3gVefJs09XJiQiuhLVihaD4H1c9RZzS8U089wmef8w0Gc0Bca8jLziAqbzDsph9lQUxoUFCDCyGhamQZvnAk7Rk+PT012ICN/K/eB0q/Un0VEeyTyPhBimfpA2TTe3nC4kjDpKOzQPhjHvjusL0e5VMnDR37iv+yO+VKZ8bDI5WbJPeR2jWh+6EJHUIoNH0XK6Fna4ektpD4vvMSNapjKVKvyFnNoVQGpl/Hc7J0Dh7b/B4veUuYvrFEhj6iAISuD5hM70iL+xaKkf9GLObj8Ay6RTx7kR99WECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAMfjuP24tBNbcEURI9hhbMECVHxfXauVQF1H5z7uWyp5+Pqphw1LApG5KmR/RFDXzePuuVZNFZON27r78w0tixgR5Z0xrwB8Lkdt9LJSwUGNv0dxpdDPFvBoGopjcnIs1zi5MgiTwW/mkYOWJhZDo+E4CheVRyp3H32hvfEG8B+vrEH7CZ8csIK2N4hYiCJP+xktHH6yXDP7fVSWu1CdWDddpyhI0B0Gwo6aBBiyDElsNyVHGwJGT7dnsWvc8bIKP2IPFgE7zxKoARqzV/jAcryyySRiDjbS9kAw84svgWxBJefoaPAtJjhr84o7222QoxMaxi/X5V9ns+S76Wo3A4Q==";
byte[] certBytes = pubKeyStr.getBytes(java.nio.charset.StandardCharsets.UTF_8);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(Base64.getDecoder().decode(certBytes));
X509Certificate certificate = (X509Certificate)certFactory.generateCertificate(in);
PublicKey publicKey = certificate.getPublicKey();
String content = "<saml2p:Response xmlns:saml2p=\"urn:oasis:names:tc:SAML:2.0:protocol\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" Destination=\"http://10.100.1.123:8080/identityiq/external/registration.jsf\" ID=\"id130347804157883831058335572\" IssueInstant=\"2023-01-20T19:39:44.049Z\" Version=\"2.0\"><saml2:Issuer xmlns:saml2=\"urn:oasis:names:tc:SAML:2.0:assertion\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:entity\">http://www.okta.com/exk81ebtt38SLQ3I65d7</saml2:Issuer><saml2p:Status><saml2p:StatusCode Value=\"urn:oasis:names:tc:SAML:2.0:status:Success\"></saml2p:StatusCode></saml2p:Status><saml2:Assertion xmlns:saml2=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"id1303478041593882583231621\" IssueInstant=\"2023-01-20T19:39:44.049Z\" Version=\"2.0\"><saml2:Issuer Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:entity\">http://www.okta.com/exk81ebtt38SLQ3I65d7</saml2:Issuer><saml2:Subject><saml2:NameID Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified\">matt#revnatech.com</saml2:NameID><saml2:SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\"><saml2:SubjectConfirmationData NotOnOrAfter=\"2023-01-20T19:44:44.049Z\" Recipient=\"http://10.100.1.123:8080/identityiq/external/registration.jsf\"></saml2:SubjectConfirmationData></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore=\"2023-01-20T19:34:44.049Z\" NotOnOrAfter=\"2023-01-20T19:44:44.049Z\"><saml2:AudienceRestriction><saml2:Audience>http://10.100.1.123:8080/identityiq/</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AuthnStatement AuthnInstant=\"2023-01-20T19:39:44.049Z\" SessionIndex=\"id1674243584047.1963093145\"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement><saml2:AttributeStatement><saml2:Attribute Name=\"email\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified\"><saml2:AttributeValue xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"xs:string\">matt#revnatech.com</saml2:AttributeValue></saml2:Attribute></saml2:AttributeStatement></saml2:Assertion></saml2p:Response>";
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(content.getBytes(java.nio.charset.StandardCharsets.UTF_8));
byte[] digest = md.digest();
System.out.println(new String(Base64.getEncoder().encode(digest)));
String signature = "laE5splYJDi8uoMbbQ1tq8bWHPotfZW/aoJ1psWQkuzgc6wS0XS71MIFM9fcZ7rFQEGUWw0GXR6cy/nyDkCaEOH7o+VvKaainpKSktVrAbBtomWIkFx65AsDbHdcN0CZXIz57yRzzfFWjks+fYEHoEM48/HkB8brFxiiyJ17GEd96O7DErlCxen4W874/uOOneEZYBxXtcZnqQylJjgen3C7VyeQATK1AnGba6TK7cdClJjBDapmo/VnWBP6ovH8ZbATdd6u8au1xBqXBu/a+DLwFIdmd2TdDWmT0mkzz/MqdfCtP8W5nOk3UU9ZwfHzSBaQrWH3/mdIgqh8V57BMw==";
try {
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(publicKey);
sig.update(content.getBytes(java.nio.charset.StandardCharsets.UTF_8));
boolean result = sig.verify(Base64.getDecoder().decode(signature.getBytes(java.nio.charset.StandardCharsets.UTF_8)));
System.out.println("Returning " + result);
} catch (Exception e) {
System.out.println(e);
}
}
}
My SAML Signature block is as follows:
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"></ds:SignatureMethod>
<ds:Reference URI="#id130347804157883831058335572">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"></ec:InclusiveNamespaces>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></ds:DigestMethod>
<ds:DigestValue>
1jaT9pnWmUCL0+atOcxHZ2yxhL5XOIhhHaK3Oz0gDWY=
</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
laE5splYJDi8uoMbbQ1tq8bWHPotfZW/aoJ1psWQkuzgc6wS0XS71MIFM9fcZ7rFQEGUWw0GXR6cy/nyDkCaEOH7o+VvKaainpKSktVrAbBtomWIkFx65AsDbHdcN0CZXIz57yRzzfFWjks+fYEHoEM48/HkB8brFxiiyJ17GEd96O7DErlCxen4W874/uOOneEZYBxXtcZnqQylJjgen3C7VyeQATK1AnGba6TK7cdClJjBDapmo/VnWBP6ovH8ZbATdd6u8au1xBqXBu/a+DLwFIdmd2TdDWmT0mkzz/MqdfCtP8W5nOk3UU9ZwfHzSBaQrWH3/mdIgqh8V57BMw==
</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIIDqDCCApCgAwIBAgIGAYXQr1PhMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi02MjkxNDMxMjEcMBoGCSqGSIb3DQEJARYNaW5mb0Bva3RhLmNvbTAeFw0yMzAxMjAxOTM2MDlaFw0zMzAxMjAxOTM3MDlaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxFTATBgNVBAMMDGRldi02MjkxNDMxMjEcMBoGCSqGSIb3DQEJARYNaW5mb0Bva3RhLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMgSFX7FkFVNzGyL7EjtIRaJRmj7/Z8diMZyAVy0rBqcIB7aL9Hn3gVefJs09XJiQiuhLVihaD4H1c9RZzS8U089wmef8w0Gc0Bca8jLziAqbzDsph9lQUxoUFCDCyGhamQZvnAk7Rk+PT012ICN/K/eB0q/Un0VEeyTyPhBimfpA2TTe3nC4kjDpKOzQPhjHvjusL0e5VMnDR37iv+yO+VKZ8bDI5WbJPeR2jWh+6EJHUIoNH0XK6Fna4ektpD4vvMSNapjKVKvyFnNoVQGpl/Hc7J0Dh7b/B4veUuYvrFEhj6iAISuD5hM70iL+xaKkf9GLObj8Ay6RTx7kR99WECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAMfjuP24tBNbcEURI9hhbMECVHxfXauVQF1H5z7uWyp5+Pqphw1LApG5KmR/RFDXzePuuVZNFZON27r78w0tixgR5Z0xrwB8Lkdt9LJSwUGNv0dxpdDPFvBoGopjcnIs1zi5MgiTwW/mkYOWJhZDo+E4CheVRyp3H32hvfEG8B+vrEH7CZ8csIK2N4hYiCJP+xktHH6yXDP7fVSWu1CdWDddpyhI0B0Gwo6aBBiyDElsNyVHGwJGT7dnsWvc8bIKP2IPFgE7zxKoARqzV/jAcryyySRiDjbS9kAw84svgWxBJefoaPAtJjhr84o7222QoxMaxi/X5V9ns+S76Wo3A4Q==
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
I have tried decrypting the SignatureValue with the PublicKey to retrieve what's in the DigestValue, but the value I retrieved when doing that didn't match up. This is what I tried when attempting that:
Cipher c = Cipher.getInstance("RSA");
c.init(Cipher.DECRYPT_MODE, publicKey);
System.out.println(new String(Base64.getEncoder().encode(c.doFinal(Base64.getDecoder().decode(signature.getBytes(java.nio.charset.StandardCharsets.UTF_8))))));
Your approach is wrong in two ways.
First, in XMLdsig, which SAML uses, the 'real' signature (here the RSA signature) is not over the data or even the data hash as such. Rather, the hash of the data is placed in Reference.DigestValue, and the publickey signature is computed over the SignedInfo element, which includes that DigestValue, canonicalized. Conversely validation checks both that the signature matches the SignedInfo and that the DigestValue in the (or each) Reference matches the (related) data. See https://www.w3.org/TR/xmldsig-core2/#sec-Processing .
Second, the 'backwards RSA' Cipher in Java -- "encrypting with the privatekey and decrypting with the publickey" -- is not correct RSA signature; this is a mistake made back in the 1990s that has never been corrected, apparently for compatibility. Correct PKCS1v1-style signature, now retronymed RSASSA-PKCS1-v1_5 as referenced in that same spec, is four steps:
hash the data
encode the hash (1) in an ASN.1 DigestInfo
pad (2) with 01 FF... 00
take (3) as an integer and modexp with the private exponent
Verification can be done by repeating 1-3 and comparing to the result of modexp-public which reverses 4 OR reversing 4 and 3 (remove 01 ...) AND 2 (split apart the ASN.1) before comparing to 1. Java's backwards Cipher only does 3 and 4 on the 'encrypt' side and 4 and 3 on the 'decrypt' side leaving you to do 2, as well as 1 on the SignedInfo per above.
This part is a very common mistake; see my list over at https://crypto.stackexchange.com/questions/87006/why-is-data-signed-with-sha256-rsa-pkcs-and-digest-signed-with-rsa-pkcs-different plus
java certificate verify failed
How to use x509 public key to verify a signed/hashed Alexa request body?

ADFS saml response have encrypt with two algorithm how to process it?

Here is my SAML response:
<samlp:Response ID="_f81c3493-8dc7-4f3e-a5c7-9a3681d1bd3e" Version="2.0" IssueInstant="2021-09-02T13:13:42.285Z" Destination="https://localhost:4200/auth/login" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">http://saml.mlads.mindlogic.app/adfs/services/trust</Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /></samlp:Status><EncryptedAssertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion"><xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" /><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#"><e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /></e:EncryptionMethod><KeyInfo><ds:X509Data xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509IssuerSerial><ds:X509IssuerName>CN=Sectigo RSA Domain Validation Secure Server CA, O=Sectigo Limited, L=Salford, S=Greater Manchester, C=GB</ds:X509IssuerName><ds:X509SerialNumber>178758501147093338516359025564238573536</ds:X509SerialNumber></ds:X509IssuerSerial></ds:X509Data></KeyInfo><e:CipherData><e:CipherValue>J51XGnrke3CP6Hg9b1WSNFX13nWAdm9twzbY7dX5G4Z5s5kU2N1kShUBxZxH7d8t7nEiUZNPj3UxT21V57DkLZhphv30MvKVAZNj4urjyN+eokaG2caJWololyfObmp0Cwc6GbaCHIVE38vfAx9XvOXnhq5JrlrqCIBjNNkfqKfJSxU+nsUySGvT8Z3eEOCcwWhcLlWLvtpZppz+40X4a8Lv530FDFVZVZMv8abwevi1tPK0Yw7v4drpPIh3epyXl8dgyxt8MPdnNES/DaLFlVaQW2lQbQueP+VO6v2JYVGpoQXoVDOLMzNA0AsYybU1IXbCcy7isim+4S5a4Ljf+w==</e:CipherValue></e:CipherData></e:EncryptedKey></KeyInfo><xenc:CipherData><xenc:CipherValue>ivaby17znjQmrTPIaq97S+CnfoMaXBUcseGLq+iWlYhPoqLOzBCZOX0BFGb68k9QGPPnVN9OFZqgtxBsoFWYxpYKsgSqKTBxIBop9xT8jv5QCBX7WAIPenXqyxnIkNEkQ8haCzGyjHHJ86AKOUibEPWZnoTSDnuaioi10cHLOaTjfF5x0JCqgjmwgOay34VpvQxX2He6bDmxel0j/wGVUBClzbIh0+cAoJMnnzDYOAyiLB5IbUUPBoDLNRgj9KoqFpMugzOoZ1Ixs721NL0R95xP6YSEptl//oK43JwEgxi44FyVqHeTLfEzcjBvl0JDoFnbfxQfQh27yb772d1hqV9W+zhhIqiBKKEI2mKWfDuPs8a2ccCYzEqH8S1e7NhN4l50cwFXouOcs5AnwxUHJAqpdrDBWG2QTz8ms4Lv+cyrIgDwg1tyToHr5pJuDdn6O6GmTCupddnvOt6F0Widmr8awMsVJGe1LA8nIqpakAPH0YAjwOFgx7EVvWjaCxYKjCBV4KhlACoWveGdeAbM48n3yd/u/sTBsjSw3FcakiBd47KLnwUrb+YVnvDKa624e5zQn+dDWgkUhLez2MG6jD+eAVgL1teJAX7MgzM6dSpNp91zbhY8UGfmU1gXgntKEP97PeZhyjlLxW7EzGysZ0EPDpvO/VxocVJ5zO55tNzlu5+zEudnwT5urxhpyTbFXEjxrI13U1eBiTDJcPvFEC2iTtvGyVLUo0omylULZq8PzLzxqbcZPDwFKg3WqoI2JqlW8wB1cmvZ7hr++aObnx5vsuSFcmCDCqWq4Hm31+ZSVU9awfBdvG2p2RPLu0QKw8B4shgNba8mHI85BDBrWnLxTWs7ndplP+SYWlRGCvwJSqKANDB+26LxjC2502RtU4ttj66MlQ8G1VE6IDVTUijCREsZbsqEt23mZMGrJxGVYwq1NKrG5Jfv5yy+PnqxmyHHfiRB55g1GxeiXQfpvFSyB/OZRTou4rumxxRKdaVTpNdwgY+QWpyRkZfcHDjRAeRWMMWPD9e0PdeFZIyzsDQJzZqP7vxMDetfrej94Ic/bBKYLOqnGN+FOoOKy9mcev8KqKcE4Dbd5Au4JtckRECYdBWLMt9QoDqWOJAEzR8/lvyaMkwu2760kNtRMmO+htxkD41u8FH2KwMWEgyG1+3l8PWmOy/4DlmRjzwMGm0eNAxoxLwxbOQ8mWtJHn2DdfYDW6iZrbm+rdGR23bkJ2Hr031xy6PoBXJD8aQrQSXSHR+gW3ieCZyRAzXa76XmFtrGQVQpm6mT2h/ZOprAqT0jSHC42yztcJnVPYuzmiGobrGj77kero463SdYQSI+TuPZFxFyUgmOgVxbWRN2Zy2ilN+/iYgNCWPY01e1TWI62C4QyLpThf9Vk4ezR3f1</xenc:CipherValue></xenc:CipherData></xenc:EncryptedData></EncryptedAssertion></samlp:Response>
In the above response, it has two encrypted algorithm I gave to my identity provider RSA based public key but my response decrypted with two algorithms: AES and RSA.
How can I decrypt in Python?
After a couple of days finally, I did
python snippet
decrypt chiper value using SP private key to get public key to decrypt SAML assertion
chiper_Data = ' P+VO6v2JYVGpoQXoVDOLMzNA0AsYybU1IXbCcy7isim+4S5a4Ljf+w=='
cipher = base64.b64decode(chiper_Data) # base64 decoding
pri_bio = BIO.MemoryBuffer(prikey.encode()) # load the private key
pri_rsa = RSA.load_key_bio(pri_bio)
plain = pri_rsa.private_decrypt(cipher, M2Crypto.RSA.pkcs1_oaep_padding)
print(len(plain)) # lenght of public key
print(base64.b64encode(plain))
decrypting assertion data using above decrypted public key and slicing first 16 block of message to get iv
data = 'xMDetfrej94Ic/bBKYLOqnGN+FOoOKy9mcev8KqKcE4Dbd5Au'
cipher = base64.b64decode(data) # base64 decoding
iv = cipher[:16]
aes = AES.new(plain, AES.MODE_CBC, iv)
decd = aes.decrypt(cipher)
print(decd)

Unsupported Signature Method sha256-rsa-MGF1 for XML digital signature validation

I'm doing XML digital signature validation, but the algorithm SHA256WITHRSAANDMGF1 is not supported.
Here's the related part in XML file:
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="cXMLSignature">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1" />
<ds:Reference URI="#cXMLSignedInfo">
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<ds:DigestValue>dafdfadfdfaddfadfefdafdfdfadfdaf=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
In the 4th line of the above xml, the signature method algorithm is:
<ds:SignatureMethod Algorithm="http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1" />
I tried something like below:
BouncyCastleProvider bc = new BouncyCastleProvider();
Security.addProvider(bc);
//...
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
XMLSignature signature = fac.unmarshalXMLSignature(validateContext);
But got error:
unsupported SignatureMethod algorithm: http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1
So I added a new line like below:
fac.newSignatureMethod("http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1", null);
But it also fails.
It seems that I need to implement the interface SignatureMethodParameterSpec for SHA256WITHRSAANDMGF1 algorithm, but I'm not familiar with this implementation. Do you have any suggestions for this implementation? Or examples for it? Thanks!
This issue is also has the same problem: unsupported SignatureMethod algorithm, but the algorithm is listed as available Service by BC-Provider
Thanks!
Update by myself:
This validation could be done by another library: https://santuario.apache.org/
Here's the sample code:
// Configure for unsupported algorithm
BouncyCastleProvider bc = new BouncyCastleProvider();
Security.addProvider(bc);
org.apache.xml.security.Init.init();
// Load document
File f = new File("C:/Archive/test.xml");
InputStream inputStream = new FileInputStream("C:/Archive/test.xml");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(inputStream);
// Public Key
NodeList x509certNodeList = document.getElementsByTagNameNS(XMLSignature.XMLNS, "X509Certificate");
String x509CertText = x509certNodeList.item(0).getTextContent();
byte[] x509CertBytes = Base64.getDecoder().decode(x509CertText.getBytes());
System.out.println("x509 Cert Text: " + x509CertText);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)certFactory.generateCertificate(new ByteArrayInputStream(x509CertBytes));
PublicKey publicKey = cert.getPublicKey();
System.out.println("x509 Cert Public-Key Algorithm: " + publicKey.getAlgorithm());
System.out.println("x509 Cert Public-Key Format: " + publicKey.getFormat());
// Signature Value
NodeList signValueNodeList = document.getElementsByTagNameNS(XMLSignature.XMLNS, "SignatureValue");
String sigValue = signValueNodeList.item(0).getTextContent();
System.out.println("SignatureValue: " + sigValue);
// Validate
NodeList signatureNodeList = document.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
Node signatureNode = signatureNodeList.item(0);
System.out.println("Signature Node Local Name: " + signatureNode.getLocalName());
System.out.println("f: " + f.toURI().toURL().toString());
org.apache.xml.security.signature.XMLSignature signature1 = new org.apache.xml.security.signature.XMLSignature(
(Element)signatureNode, f.toURI().toURL().toString()
);
boolean result = signature1.checkSignatureValue(publicKey);
System.out.println("result: " + result);

Signature as parameter in the authentication request

I should get a GET authentication request with a certain set of parameters:
"https://domain_name_of_idp_here/idp/profile/SAML2/Redirect/SSO?" +
"SAMLRequest=" + SAMLRequest + "&SigAlg=" + SigAlg + "&Signature=" + Signature
Thus, I'm interested in the parameters:
SAMLRequest
SigAlg
Signature
When I used OIOSAML, all these parts of the request formed automatically, but it was not possible to flexibly manage them and get full control.
So I decided to write my sP- based Web SSO by using OpenSAML 2.4.1
Consider how to create SAMLRequest. My idP requires that sP- AuthnRequest requests come in this format:
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
AssertionConsumerServiceURL=
"https://ip_of_my_sp_here/oiosaml/saml/SAMLAssertionConsumer"
Destination="https://domain_name_of_idp_here/idp/profile/SAML2/Redirect/SSO"
ForceAuthn="false"
ID="_054240e4-...-e0b5e84d3a35"
IsPassive="false"
IssueInstant="2012-02-28T06:43:35.704Z"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
test_issuer
</saml2:Issuer>
Therefore SAMLRequest I form as follows:
private AuthnRequest buildAuthnRequestObject() {
DateTime issueInstant = new DateTime();
IssuerBuilder issuerBuilder = new IssuerBuilder();
Issuer issuer = issuerBuilder.buildObject(
"urn:oasis:names:tc:SAML:2.0:assertion",
"Issuer", "samlp");
issuer.setValue(issuerId);
AuthnRequestBuilder authRequestBuilder = new AuthnRequestBuilder();
AuthnRequest authRequest =
authRequestBuilder.buildObject("urn:oasis:names:tc:SAML:2.0:protocol",
"AuthnRequest", "samlp");
authRequest.setForceAuthn(new Boolean(false));
authRequest.setIsPassive(new Boolean(false));
authRequest.setIssueInstant(issueInstant.plusHours(4));
authRequest.setProtocolBinding(
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST");
authRequest.setAssertionConsumerServiceURL(consumerUrl);
authRequest.setDestination(idPDestinationUrlSSO);
authRequest.setIssuer(issuer);
authRequest.setID(authReqRandomId);
authRequest.setVersion(SAMLVersion.VERSION_20);
return authRequest;
}
Then this message is compressed and encoded in Base64:
private String encodeRequestMessage(RequestAbstractType requestMessage)
throws MarshallingException, IOException {
Marshaller marshaller =
Configuration.getMarshallerFactory().getMarshaller(requestMessage);
Element authDOM = marshaller.marshall(requestMessage);
Deflater deflater = new Deflater(Deflater.DEFLATED, true);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DeflaterOutputStream deflaterOutputStream =
new DeflaterOutputStream(byteArrayOutputStream,
deflater);
StringWriter rspWrt = new StringWriter();
XMLHelper.writeNode(authDOM, rspWrt);
deflaterOutputStream.write(rspWrt.toString().getBytes());
deflaterOutputStream.close();
String encodedRequestMessage =
Base64.encodeBytes(byteArrayOutputStream.toByteArray(),
Base64.DONT_BREAK_LINES);
return URLEncoder.encode(encodedRequestMessage, "UTF-8").trim();
}
Thus, this part - "SAMLRequest =" + SAMLRequest - is formed.
"https://domain_name_of_idp_here/idp/profile/SAML2/Redirect/SSO?" +
"SAMLRequest=" + encodedRequestMessage
As for SigAlg. I use http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23dsa-sha1
Therefore, this part also is formed.
"https://domain_name_of_idp_here/idp/profile/SAML2/Redirect/SSO?" +
"SAMLRequest=" + encodedRequestMessage + "&SigAlg=" + SigAlg
Question in forming of this part:
"&Signature=" + Signature
I get a signature so (but this method does not give the signature):
public Signature getSignature() {
KeyStore keyStore =
KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream fileInputStream =
new FileInputStream(new File(jksFileName));
keyStore.load(fileInputStream, jksPassword);
fileInputStream.close();
KeyStore.PrivateKeyEntry privateKeyEntry =
(KeyStore.PrivateKeyEntry) keyStore.getEntry(alias,
new KeyStore.PasswordProtection(jksPassword));
PrivateKey privateKey = privateKeyEntry.getPrivateKey();
X509Certificate certificate =
(X509Certificate) privateKeyEntry.getCertificate();
BasicX509Credential credential = new BasicX509Credential();
credential.setEntityCertificate(certificate);
credential.setPrivateKey(privateKey);
Signature signature =
(Signature) org.opensaml.xml.Configuration.getBuilderFactory()
.getBuilder(org.opensaml.xml.signature.Signature.DEFAULT_ELEMENT_NAME)
.buildObject(org.opensaml.xml.signature.Signature.DEFAULT_ELEMENT_NAME);
signature.setSigningCredential(credential);
SecurityConfiguration securityConfiguration =
Configuration.getGlobalSecurityConfiguration();
String keyInfoGeneratorProfile = null;
SecurityHelper.prepareSignatureParams(signature,
credential, securityConfiguration, keyInfoGeneratorProfile);
return signature;
}
In the method buildAuthnRequestObject() is added:
private AuthnRequest buildAuthnRequestObject() {
...
authRequest.setSignature(getSignature()); // <---- to sign the request
return authRequest;
}
This message also compressed and encoded in Base64 and takes the form:
<?xml version="1.0" encoding="UTF-8"?>
<samlp:AuthnRequest AssertionConsumerServiceURL=
"https://ip_of_my_sp_here/EsiaChecker_war/resp/"
Destination=
"https://domain_name_of_idp_here/idp/profile/SAML2/Redirect/SSO"
ForceAuthn="false"
ID="0"
IsPassive="false"
IssueInstant="2014-09-1T19:07:42.718Z"
ProtocolBinding=
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
<samlp:Issuer xmlns:samlp=
"urn:oasis:names:tc:SAML:2.0:assertion">my_issuer_here
</samlp:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm=
"http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm=
"http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#0">
<ds:Transforms>
<ds:Transform Algorithm=
"http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm=
"http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm=
"http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue/>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue/>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIEXD...0CFtd6whg==
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
</samlp:AuthnRequest>
It is seen that the element SignatureValue is empty.
How can I get the signature using OpenSaml and add it as a GET request parameter? To make it so: "&Signature =" + Signature.
There is a component called HTTPRedirectDeflateEncoder that will help with this, adding the sigalg, encoding and deflating and redirecting the user.
I have an example of usage on my blog, https://blog.samlsecurity.com/2011/01/redirect-with-authnrequest.html
I also have wider examples of its usage in my book, A Guide to OpenSAML

How to sign a generic text with RSA key and encode with Base64 in Java?

I have the following code in bash:
signed_request = $(printf "PLAIN TEXT REQUEST" |
openssl rsautl -sign -inkey "keyfile.pem" | openssl enc -base64 | _chomp )
Basically, this code takes a plain text, signs it with a private key and encodes using Base64
How could I do a code with exactly the same functionality in Java?
You can use JDK security API. Take a look at this working sample, hope it can get you started:
public static void main(String[] args) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair keyPair = kpg.genKeyPair();
byte[] data = "test".getBytes("UTF8");
Signature sig = Signature.getInstance("MD5WithRSA");
sig.initSign(keyPair.getPrivate());
sig.update(data);
byte[] signatureBytes = sig.sign();
System.out.println("Singature:" + new BASE64Encoder().encode(signatureBytes));
sig.initVerify(keyPair.getPublic());
sig.update(data);
System.out.println(sig.verify(signatureBytes));
}
EDIT:
The example above uses internal Sun's encoder (sun.misc.BASE64Encoder). It is best to use something like Base64 from Commons Codec.
Also, you can use not-yet-commons-ssl to obtain the private key from a file and encode using org.apache.commons.ssl.Base64. Using Max's example:
import java.security.Signature;
import org.apache.commons.ssl.Base64;
import org.apache.commons.ssl.PKCS8Key;
// [...]
PKCS8Key pkcs8 = new PKCS8Key(new FileInputStream("keyfile.pem"),
"changeit".toCharArray());
Signature sig = Signature.getInstance("MD5WithRSA");
sig.initSign(pkcs8.getPrivateKey());
sig.update(data);
byte[] signatureBytes = sig.sign();
System.out.println("Singature: " +
Base64.encodeBase64String(signatureBytes));
I copy the link #Aqua posted as a new answer, because I think it's FAR more useful than any of the answers given yet. Use THIS to read/write private/public keys from files:
http://codeartisan.blogspot.ru/2009/05/public-key-cryptography-in-java.html
The link doesn't say anythig about signing and verifying, but signing is a lot easier. I used this code to sign:
Signature signature = Signature.getInstance("SHA256WithRSA");
signature.initSign(privateKey);
signature.update("text to sign".getBytes());
signature.sign();
And to verify:
Signature signature = Signature.getInstance("SHA256WithRSA");
signature.initVerify(publicKey);
signature.update("text to sign".getBytes);
signature.verify(signatureMadeEarlier);

Categories