As you may already know, a signed tag is a SignedInfo
The public certificate always in X509Certificate
And the content of the SignatureValuetag is a digital signature itself.

require 'openssl'
require 'base64'
require 'nokogiri'

xml = '...'

signed_info = xml.scan(/\<SignedInfo\>[\s\S]*?\<\/SignedInfo\>/)[0].gsub(/>\s+</,"><")
signed_info.gsub!("<SignedInfo>",%{<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">})
signed_info = Nokogiri::XML(signed_info.gsub(/>\s+</,"><")).canonicalize(Nokogiri::XML::XML_C14N_1_1) 

signature_value = xml.scan(/(?<=\<SignatureValue\>)[\s\S]*?(?=\<\/SignatureValue\>)/)[0]

x509_certificate = xml.scan(/(?<=\<X509Certificate\>)[\s\S]*?(?=\<\/X509Certificate\>)/)[0]
x509_certificate = %{-----BEGIN CERTIFICATE-----\n#{x509_certificate}\n-----END CERTIFICATE-----}

certificate = OpenSSL::X509::Certificate.new x509_certificate

digest_method_algorithm = signed_info.scan(/(\<DigestMethod[\s\S]*?\#)([\s\S]*?)(\"|\')/)[0][1]

certificate.public_key.verify OpenSSL::Digest.new(digest_method_algorithm), Base64.decode64(signature_value), signed_info
import re
import lxml.etree as ET
from io import BytesIO
import base64
from OpenSSL import crypto

xml = '...'
signed_info = re.search(r"\<SignedInfo>[\s\S]*?\<\/SignedInfo\>", xml).group()
signed_info = signed_info.replace("<SignedInfo>",'<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">')

tree = ET.ElementTree(ET.fromstring(signed_info))
output = BytesIO()
tree.write_c14n(output)

signed_info = output.getvalue()

signature_value = re.search(r"(?<=\<SignatureValue\>)[\s\S]*?(?=\<\/SignatureValue\>)", xml).group()

x509_certificate = re.search(r"(?<=\<X509Certificate\>)[\s\S]*?(?=\<\/X509Certificate\>)", xml).group()

certificate = crypto.load_certificate(crypto.FILETYPE_PEM, "-----BEGIN CERTIFICATE-----\n" + x509_certificate + "\n-----END CERTIFICATE-----")
digest_method_algorithm = re.search(r"(\<DigestMethod[\s\S]*?\#)([\s\S]*?)(\"|\')", xml).group(2)

pk = certificate.get_pubkey()
x509 = crypto.X509()
x509.set_pubkey(pk)

print(crypto.verify(x509, base64.b64decode(signature_value), signed_info, digest_method_algorithm) == None)
import java.io.ByteArrayInputStream;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;

public class SignatureCheck {
  public static void main(String[] args) throws Exception {   
    String xml = "...";
    Matcher matcher = Pattern.compile("\\<SignedInfo\\>[\\s\\S]*?\\<\\/SignedInfo\\>").matcher(xml);
    matcher.find();
    String signed_info = matcher.group(0);
    signed_info = signed_info.replace("<SignedInfo>", "<SignedInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">");
    com.sun.org.apache.xml.internal.security.Init.init();
    Canonicalizer c = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS);
    byte[] signed_info_b = c.canonicalize(signed_info.getBytes());
    signed_info = new String(signed_info_b);
    matcher = Pattern.compile("(?<=\\<SignatureValue\\>)[\\s\\S]*?(?=\\<\\/SignatureValue\\>)").matcher(xml);
    matcher.find();
    String signature_value = matcher.group(0);
    matcher = Pattern.compile("(?<=\\<X509Certificate\\>)[\\s\\S]*?(?=\\<\\/X509Certificate\\>)").matcher(xml);
    matcher.find();
    String x509_certificate = matcher.group(0);
    x509_certificate = "-----BEGIN CERTIFICATE-----\n" + x509_certificate + "\n-----END CERTIFICATE-----";
    CertificateFactory cf = CertificateFactory.getInstance("X509");
    X509Certificate certificate = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(x509_certificate.getBytes()));
    matcher = Pattern.compile("(\\<DigestMethod[\\s\\S]*?\\#)([\\s\\S]*?)(\\\"|\\')").matcher(signed_info);
    matcher.find();
    String digest_method_algorithm =  matcher.group(2);
    Signature sig = Signature.getInstance(digest_method_algorithm.toUpperCase()+"withRSA");   sig.initVerify(certificate.getPublicKey());
    sig.update(signed_info.getBytes());
    System.out.println(sig.verify(Base64.getDecoder().decode(signature_value.getBytes())));
  }
}

🗓 2019-01-09
254 👀