In Magic Signatures for Salmon, John Panzer describes a way to pass signed XML data without involving XML canonicalization (c14n). Anyone who has dealt with WS-Security specs knows that canonicalization can be fragile (back in my days at BEA, getting signatures to work on the WebLogic stack turned out to be hard due to bugs in the c14n implementation) and slow. John Panzer’s approach is quite simple, but it requires introducing an XML based envelope format.
In John’s approach, to send signed XML, the sender does the following.
- Serialize the XML using into UTF-8 encoded text.
- Generate a signature of the BASE64 encoded data.
- Use an XML envelope to send the BASE64 encoded data and the signature.
Before decoding BASE64 data, the receiver first verifies the signature of the BASE64 encoded data. If the signature matches, the receiver BASE64 decodes the data, and then parses the decoded text into XML.The most elegant part of this process is that canonicalization is not needed.
The envelope in his example looks like the following:
<me:env xmlns:me='http://salmon-protocol.org/ns/magic-env'> <me:data type='application/atom+xml' encoding='base64'> PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz4KPGVudHJ5IHhtbG5 zPSdodHRwOi8vd3d3LnczLm9yZy8yMDA1L0F0b20nPgogIDxpZD50YWc6ZXhhbXBsZ S5jb20sMjAwOTpjbXQtMC40NDc3NTcxODwvaWQ-ICAKICA8YXV0aG9yPjxuYW1lPnRlc3RAZXhhbXBsZS5jb208L25hbWU-PHVyaT5hY2N0OmpwYW56ZXJAZ29vZ2xlLmNvbTwvdXJpPjwvYXV0aG9yPgogIDx0 aHI6aW4tcmVwbHktdG8geG1sbnM6dGhyPSdodHRwOi8vcHVybC5vcmcvc3luZGljYX Rpb24vdGhyZWFkLzEuMCcKICAgICAgcmVmPSd0YWc6YmxvZ2dlci5jb20sMTk5OTp ibG9nLTg5MzU5MTM3NDMxMzMxMjczNy5wb3N0LTM4NjE2NjMyNTg1Mzg4NTc5 NTQnPnRhZzpibG9nZ2VyLmNvbSwxOTk5OmJsb2ctODkzNTkxMzc0MzEzMzEyNzM 3LnBvc3QtMzg2MTY2MzI1ODUzODg1Nzk1NAogIDwvdGhyOmluLXJlcGx5LXRvPgog IDxjb250ZW50PlNhbG1vbiBzd2ltIHVwc3RyZWFtITwvY29udGVudD4KICA8dGl0bGU-U2FsbW9uIHN3aW0gdXBzdHJlYW0hPC90aXRsZT4KICA8dXBkYXRlZD4yMDA5LTEyLT E4VDIwOjA0OjAzWjwvdXBkYXRlZD4KPC9lbnRyeT4KICAgIA==</me:data> <me:alg>RSA-SHA1</me:alg> <me:sig>EvGSD2vi8qYcveHnb-rrlok07qnCXjn8YSeCDDXlbhILSabgvNsPpbe 76up8w63i2fWHvLKJzeGLKfyHg8ZomQ==>/me:sig> </me:env>
In this XML envelope, the me:data element contains BASE64 encoded data. The type attribute tells that the data is an Atom document. The me:sig element contains the signature.
But does sending a signature require an envelope? Here is an alternative that does not use an envelope.
Content-Encoding: base64 Content-Type: application/atom+xml;chatset=UTF-8 Authorization: salmon EvGSD2vi8qYcveHnb-rrlok07qnCXjn8YSeCDDXlbhILSabgvNsPpbe76up8w63i2fWHvLKJzeGLKfyHg8ZomQ== D94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz4KPGVudHJ5IHhtbG5 zPSdodHRwOi8vd3d3LnczLm9yZy8yMDA1L0F0b20nPgogIDxpZD50YWc6ZXhhbXBsZ S5jb20sMjAwOTpjbXQtMC40NDc3NTcxODwvaWQ-ICAKICA8YXV0aG9yPjxuYW1lPnRlc3RAZXhhbXBsZS5jb208L25hbWU-PHVyaT5hY2N0OmpwYW56ZXJAZ29vZ2xlLmNvbTwvdXJpPjwvYXV0aG9yPgogIDx0 aHI6aW4tcmVwbHktdG8geG1sbnM6dGhyPSdodHRwOi8vcHVybC5vcmcvc3luZGljYX Rpb24vdGhyZWFkLzEuMCcKICAgICAgcmVmPSd0YWc6YmxvZ2dlci5jb20sMTk5OTp ibG9nLTg5MzU5MTM3NDMxMzMxMjczNy5wb3N0LTM4NjE2NjMyNTg1Mzg4NTc5 NTQnPnRhZzpibG9nZ2VyLmNvbSwxOTk5OmJsb2ctODkzNTkxMzc0MzEzMzEyNzM 3LnBvc3QtMzg2MTY2MzI1ODUzODg1Nzk1NAogIDwvdGhyOmluLXJlcGx5LXRvPgog IDxjb250ZW50PlNhbG1vbiBzd2ltIHVwc3RyZWFtITwvY29udGVudD4KICA8dGl0bGU-U2FsbW9uIHN3aW0gdXBzdHJlYW0hPC90aXRsZT4KICA8dXBkYXRlZD4yMDA5LTEyLT E4VDIwOjA0OjAzWjwvdXBkYXRlZD4KPC9lbnRyeT4KICAgIA==
In this case, the Authorization header contains the signature, and the body of HTTP message contains base64 encoded bytes. I extended Content-Encoding to specify base64. I left out details like the signature method name, and the Authorization header can be extended to include such data, or such details can be specified as part of the authorization scheme (the way basic auth, digest auth, or OAuth do).
The magic envelope is HTTP (thanks to MIME).