Wednesday, July 7, 2010

Anatomy of a signed SOAP message

I will explain a WSS signed web service SOAP message,signed using a X509 certificate.

The sample signed message is:


The following illustrates the anatomy of the message
1. SignedInfo

The SignedInfo element describes the signed content of the message.



1.1. CanonicalizationMethod
The element CanonicalizationMethod is used to describe the canonicalization algorithm used on the xml for the generation of the digest.
1.2. SignatureMethod
The element SignatureMethod is used to describe the algorithm used for the generation of the SignatureValue from the output of the canonicalization algorithm.
1.3. Reference
The optional URI attribute for Reference element identifies the data object that was signed.

In the above case the body is being signed thus the URI attribute refers to the soap body.
Transform Algorithm indicates the transformation algorithm. I still need to understand why do we need a duplicate of the canonicalization algortithm?
DigestMethod Algorithm indicates the algorithm used to generate the digest value and DigestValue contains the computed digest value.
2.SignatureValue
SignatureValue contain the signature value, which is actually the encrypted digest value. This value is the output of the Signature Method Algorithm indicated

3.BinarySecurityToken
The signed data contain a core bare name reference (as defined by the XPointer specification [XPointer]) to the element that contains the security token referenced, or a core reference to the external data source containing the security token.
In this example the BinarySecurityToken contains the Base64Encoded public key that can be used for verification.

The signed content was created using a Microsoft file (.pfx) containing x509 certificates. The public key can be regenerated using the BinarySecurityToken element.
Sample code to generate .cer from BinarySecurityToken

// from tag BinarySecurityToken
private static final String b64Str = "MIIECTCCAvGgAwIBAgICLy4wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMCQUUxETAPBgNVBAoTCEV0aXNhbGF0MSQwIgYDVQQLExtFdGlzYWxhdCBlQnVzaW5lc3MgU2VydmljZXMxLjAsBgNVBAMTJUNvbXRydXN0IFVzZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDkwMjEyMDQ0ODMxWhcNMTEwMjEyMDQ0ODMxWjCBqjELMAkGA1UEBhMCQUUxDjAMBgNVBAcTBUR1YmFpMQ8wDQYDVQQKEwZFVENEQzIxHjAcBgNVBAsTFURlbHV4ZSBJbnRsIENhcmdvIExMQzENMAsGA1UELhMENTgwODEnMCUGCSqGSIb3DQEJARYYZGVsdXhlcGFAZW1pcmF0ZXMubmV0LmFlMSIwIAYDVQQDExlBYmR1bCBTYXR0YXIgQWJkdWwgUmF3b29mMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfge/HNFnO/SEVdvNPTQ0ziLEMDz/EKwSWWCBK94yU58y75AsTArK/QG4+wHSALd9HDW+wxaBLd7ZLz4mjMgAJgGEEWIP9XYMvSTO2li7SI9fKANQ3/uoXTgJU0N/CLyLBZkW2Z7Vb6bsdhN6HGzsFcd5SoDmxYDh+z26RenbtUQIDAQABo4HvMIHsMAkGA1UdEwQCMAAwIwYDVR0RBBwwGoEYZGVsdXhlcGFAZW1pcmF0ZXMubmV0LmFlMEwGA1UdIARFMEMwQQYLKwYBBAGyXQIBAQAwMjAwBggrBgEFBQcCARYkaHR0cDovL2NvbXRydXN0LmV0aXNhbGF0LmFlL2Nwcy5odG1sMA4GA1UdDwEB/wQEAwIE8DAfBgNVHSMEGDAWgBTOP/R2v2Tj4qbCev148AwSjFT9fjA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY29tdHJ1c3QuZXRpc2FsYXQuYWUvY3JsL3VzZXJjYS5jcmwwDQYJKoZIhvcNAQEFBQADggEBAKO44b564tmzCLCZhlE5gQkGzQF1tgW954nJMcfthO89C9X3QuLbBoNLrrKeQoqumKYDMiODF5Rkn1pRlgJlGSWKOkjPwF+wB4PlHjd/BijNDnyv2VJUWw7gqE6uffu2E0c4kEfun2leNY03Qtcvu9FmUL7JDj0seibEhOXzy63r+o5rf5x5/vER8vUz1MBypHea3EWbCSJ2yAEw2fJ3Syq/vuihr4yP3VOb7KBeVXL353J5pdpql4UjAwlGAdmiihAAQMCKicE6qDZ2i4jC4bS+lSDv2wE/CiTCj1DN1eEyQnajuTWvFYq88ZAHtru7q5CrsMcHMa8WXENMrUzlKdM=";

public static int decode(char c) {
if (c >= 'A' && c <= 'Z')
return c - 65;
else if (c >= 'a' && c <= 'z')
return c - 97 + 26;
else if (c >= '0' && c <= '9')
return c - 48 + 26 + 26;
else
switch (c) {
case '+':
return 62;
case '/':
return 63;
case '=':
return 0;
default:
throw new RuntimeException(
new StringBuffer("unexpected code: ").append(c)
.toString());
}
}

public static byte[] decode(String s) {

int i = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int len = s.length();

while (true) {
while (i < len && s.charAt(i) <= ' ')
i++;

if (i == len)
break;

int tri = (decode(s.charAt(i)) << 18)
+ (decode(s.charAt(i + 1)) << 12)
+ (decode(s.charAt(i + 2)) << 6)
+ (decode(s.charAt(i + 3)));

bos.write((tri >> 16) & 255);
if (s.charAt(i + 2) == '=')
break;
bos.write((tri >> 8) & 255);
if (s.charAt(i + 3) == '=')
break;
bos.write(tri & 255);

i += 4;
}
return bos.toByteArray();
}

public static void main(String[] args) throws Exception {
byte[] back = decode(b64Str);
OutputStream out = new FileOutputStream("aa.cer");
out.write(back);
//perform your exception handling
out.close();
}


4. KeyInfo


In order to ensure a consistent processing model across all the token types supported by WSS: SOAP Message
Security, the element specify all references to X.509 token types in signature or encryption elements that comply with this profile.
The element contains a element that specifies the token data by means of a X.509 SubjectKeyIdentifier reference.
Reference:-
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0.pdf

1 comment:

Angelo said...

Hello, Look at this blog, we provide another example of how to do that.
http://www.systemdeveloper.info/2013/11/digital-signature-in-c.html