Permalink
Browse files

completed unit tests, updated README

  • Loading branch information...
1 parent b17ebec commit 266b35f0320f001e55dac87cd8952456864c46ff Andrew D. Yates committed Mar 23, 2011
Showing with 91 additions and 32 deletions.
  1. +27 −9 README
  2. +3 −3 __init__.py
  3. +61 −20 test.py
View
36 README
@@ -1,28 +1,46 @@
xmldsig
Sign and verify RSA-SHA1 XML Digital Signatures in native Python.
+Version 2
-Copyright © 2010 Andrew D. Yates
+Copyright © 2011 Andrew D. Yates
All Rights Reserved
http://github.com/andrewdyates/xmldsig
git@github.com:andrewdyates/xmldsig.git
-
-Version 1
+andrewyates.name@gmail.com
xmldsig is cryptographic key implementation agnostic. xmldsig is not
a complete implementation of http://www.w3.org/2000/09/xmldsig. See
module documentation for details.
-===
+See "test.py" for unit tests and sample use.
+
+=================================
+
+EXAMPLE
+-------
+ given predefined public / private cryptographic pair: (f_private, f_public)
+
+>>> signed_xml = xmldsig.sign(xml, f_private, key_info_xml, key_size)
+... is_verified = xmldsig.verify(signed_xml, f_public, key_size)
+... assert(is_verified)
-Example:
+RUN UNIT TESTS
+--------------
+$ python test.py
->>> signed_xml = xmldsig.sign(xml, f_private, mod, exp)
-... is_verified = xmldsig.verify(signed_xml, f_public, mod)
+NOTE
+----
+I use the identity function as my cryptographic function pair in the
+unit tests. You will need a real cryptographic implementation, like
+RSA, to use xmldsig in practice. A working example of xmldsig using
+RSA can be found in my github repository at
+http://github.com/andrewdyates
-See test.py for sample use.
+=================================
-Commentary:
+UNNECESSARY COMMENTARY
+----------------------
XMLDSIG is a ridiculous but necessary protocol for identification and
authentication in computer systems. Why is XMLDSIG ridiculous? The
View
@@ -97,7 +97,7 @@ def sign(xml, f_private, key_info_xml, key_size, sig_id_value=None):
Args:
xml: str of bytestring xml to sign
f_private: func of RSA key private function
- key_size: int of RSA key modulus size; i.e. len(modulus)
+ key_size: int of RSA key modulus size; i.e. len(modulus) > 0
key_info_xml: str of <KeyInfo> bytestring xml including public key
sig_id_value: str of signature id value
Returns:
@@ -129,7 +129,7 @@ def verify(xml, f_public, key_size):
Args:
xml: str of XML with xmldsig <Signature> element
f_public: func from RSA key public function
- key_size: int of RSA key modulus size; i.e. len(modulus)
+ key_size: int of RSA key modulus size; i.e. len(modulus) > 0
Returns:
bool: signature for `xml` is valid
"""
@@ -179,7 +179,7 @@ def key_info_xml_cert(cert_b64, subject_name=None):
}
xml = PTN_KEY_INFO_X509_CERT % {
'cert_b64': cert_b64,
- 'subject_name': subject_name_xml,
+ 'subject_name_xml': subject_name_xml,
}
return xml
View
81 test.py
@@ -4,34 +4,75 @@
# All Rights Reserved
"""Sanity test for xmldsig."""
+import unittest
import __init__ as top
KEY_SIZE = 128
+XML = '<samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="123"></samlp:Response>'
+# trivial public key (values not used in encryption)
+MOD = '\x00' * KEY_SIZE
+EXP = '\x03'
-def main():
- """Sign and verify a sample SAML XML response with trivial keys.
+# obviously fake certificate encoding
+CERT = "ABCD" * 30
+SUBJECT_NAME = "DUMMY SUBJECT"
- Raises:
- AssertionError: sign and verify test failed
- """
- # trivial inverse function pair
- private = public = lambda x: x
-
- xml = '<samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="123"></samlp:Response>'
- mod = '\x00' * KEY_SIZE
- exp = '\x03'
- key_info = top.PTN_KEY_INFO_RSA_KEY % {
- 'modulus': top.b64e(mod),
- 'exponent': top.b64e(exp),
- }
-
- signed_xml = top.sign(xml, private, key_info, KEY_SIZE)
- is_verified = top.verify(signed_xml, public, KEY_SIZE)
-
- assert is_verified
+# trivial inverse function pair (identity function)
+private_f = lambda x: x
+public_f = lambda x: x
+KEY_INFO_XML = "<KeyInfo>Dummy</KeyInfo>"
+SIG_ID = "DUMMY ID 123"
+
+# expected values for tests
+EXP_KEY_INFO_XML_RSA = \
+"<KeyInfo><KeyValue><RSAKeyValue><Modulus>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</Modulus><Exponent>Aw==</Exponent></RSAKeyValue></KeyValue></KeyInfo>"
+EXP_KEY_INFO_XML_CERT = \
+"<KeyInfo><X509Data><X509SubjectName>DUMMY SUBJECT</X509SubjectName><X509Certificate>ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD</X509Certificate></X509Data></KeyInfo>"
+EXP_KEY_INFO_XML_CERT_NO_SUBJECT = \
+"<KeyInfo><X509Data><X509Certificate>ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD</X509Certificate></X509Data></KeyInfo>"
+EXP_SIGNED_XML = \
+'<samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="123"><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"></CanonicalizationMethod><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue>H7olMzu7Zog9nSS7Yl+FQ1Mp8eQ=</DigestValue></Reference></SignedInfo><SignatureValue>Af///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wAwITAJBgUrDgMCGgUABBS2LaIdRUmFpxZc4I16PGDU0hNzEQ==</SignatureValue><KeyInfo>Dummy</KeyInfo></Signature></samlp:Response>'
+EXP_SIGNED_XML_WITH_ID = \
+'<samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="123"><Signature Id="DUMMY ID 123" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"></CanonicalizationMethod><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue>H7olMzu7Zog9nSS7Yl+FQ1Mp8eQ=</DigestValue></Reference></SignedInfo><SignatureValue>Af///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wAwITAJBgUrDgMCGgUABBS2LaIdRUmFpxZc4I16PGDU0hNzEQ==</SignatureValue><KeyInfo>Dummy</KeyInfo></Signature></samlp:Response>'
+
+
+class TestKeyInfo(unittest.TestCase):
+ def test_key_info_xml_rsa(self):
+ key_info_xml = top.key_info_xml_rsa(MOD, EXP)
+ self.assertEqual(key_info_xml, EXP_KEY_INFO_XML_RSA)
+
+ def test_key_info_xml_cert_no_subject(self):
+ key_info_xml = top.key_info_xml_cert(CERT)
+ self.assertEqual(key_info_xml, EXP_KEY_INFO_XML_CERT_NO_SUBJECT)
+
+ def test_key_info_xml_cert(self):
+ key_info_xml = top.key_info_xml_cert(CERT, SUBJECT_NAME)
+ self.assertEqual(key_info_xml, EXP_KEY_INFO_XML_CERT)
+
+
+class TestTrivialKeys(unittest.TestCase):
+
+ def test_sign(self):
+ signed_xml = top.sign(XML, private_f, KEY_INFO_XML, KEY_SIZE)
+ self.assertEqual(signed_xml, EXP_SIGNED_XML)
+
+ def test_sign_with_id(self):
+ signed_xml = \
+ top.sign(XML, private_f, KEY_INFO_XML, KEY_SIZE, sig_id_value=SIG_ID)
+ self.assertEqual(signed_xml, EXP_SIGNED_XML_WITH_ID)
+
+ def test_verify(self):
+ # signed_xml = top.sign(XML, private_f, KEY_INFO_XML, KEY_SIZE)
+ signed_xml = EXP_SIGNED_XML
+ is_verified = top.verify(signed_xml, public_f, KEY_SIZE)
+ self.assertTrue(is_verified)
+
+
+def main():
+ unittest.main()
if __name__ == '__main__':
main()

0 comments on commit 266b35f

Please sign in to comment.