test_rfc6030.doctest - test for examples from RFC 6030 Copyright (C) 2014-2016 Arthur de Jong This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA >>> from binascii import a2b_hex, b2a_hex >>> def tostr(x): ... return str(x.decode()) >>> def decode(f): ... return lambda x: tostr(f(x)) >>> b2a_hex = decode(b2a_hex) >>> import datetime >>> now = datetime.datetime(2016, 3, 23, 0, 0, 0) >>> from pskc import PSKC This tests figure 2 from RFC 6030. It is a basic key container example with a simple plain text secret key. >>> pskc = PSKC('tests/rfc6030/figure2.pskcxml') >>> [tostr(key.secret) for key in pskc.keys] ['1234'] >>> key = pskc.keys[0] >>> key.id '12345678' >>> key.algorithm 'urn:ietf:params:xml:ns:keyprov:pskc:hotp' >>> key.issuer 'Issuer-A' >>> tostr(key.secret) '1234' This tests figure 3 from RFC 6030. Relative to figure 2 this includes device, cryptographic module and user identification as well as some more parameters. >>> pskc = PSKC('tests/rfc6030/figure3.pskcxml') >>> pskc.id 'exampleID1' >>> key = pskc.keys[0] >>> key.manufacturer 'Manufacturer' >>> key.serial '987654321' >>> key.device_userid 'DC=example-bank,DC=net' >>> key.crypto_module 'CM_ID_001' >>> key.id '12345678' >>> key.algorithm 'urn:ietf:params:xml:ns:keyprov:pskc:hotp' >>> key.issuer 'Issuer' >>> key.response_encoding 'DECIMAL' >>> key.response_length 8 >>> tostr(key.secret) '12345678901234567890' >>> key.counter 0 >>> key.key_userid 'UID=jsmith,DC=example-bank,DC=net' This tests figure 4 from RFC 6030. In this case the key value itself is not contained but can be derived using the serial and out-of-band agreements on the meanings of key_profile and key_reference. >>> pskc = PSKC('tests/rfc6030/figure4.pskcxml') >>> key = pskc.keys[0] >>> key.serial '987654321' >>> key.key_profile 'keyProfile1' >>> key.key_reference 'MasterKeyLabel' >>> key.counter 0 This tests the key policy properties as illustrated in figure 5 of RFC 6030. >>> pskc = PSKC('tests/rfc6030/figure5.pskcxml') >>> len(pskc.keys) 2 >>> key1, key2 = pskc.keys >>> key1.serial '987654321' >>> key.algorithm 'urn:ietf:params:xml:ns:keyprov:pskc:hotp' >>> key.response_length 8 >>> key.response_encoding 'DECIMAL' >>> tostr(key1.secret) '12345678901234567890' >>> key1.counter 0 >>> key1.policy.pin_min_length 4 >>> key1.policy.pin_max_length 4 >>> key1.policy.pin_key_id '123456781' >>> key1.policy.pin_encoding 'DECIMAL' >>> key1.policy.pin_usage 'Local' >>> key1.policy.key_usage ['OTP'] >>> key1.policy.may_use('OTP', now) True >>> key1.policy.may_use('Encrypt', now) False >>> key1.policy.unknown_policy_elements False >>> key2.id '123456781' >>> key2.serial '987654321' >>> key2.algorithm 'urn:ietf:params:xml:ns:keyprov:pskc:pin' >>> key2.response_length 4 >>> key2.response_encoding 'DECIMAL' >>> tostr(key2.secret) '1234' >>> key1.policy.pin '1234' This tests key encryption based on pre-shared keys as illustrated in figure 6 of RFC 6030. The first attempt at extracting the key will fail due to the encryption. >>> pskc = PSKC('tests/rfc6030/figure6.pskcxml') >>> key = pskc.keys[0] >>> key.id '12345678' >>> key.secret # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... DecryptionError: No key available >>> pskc.encryption.key_name 'Pre-shared-key' >>> pskc.encryption.key = a2b_hex('12345678901234567890123456789012') >>> pskc.encryption.algorithm 'http://www.w3.org/2001/04/xmlenc#aes128-cbc' >>> b2a_hex(pskc.mac.key) '1122334455667788990011223344556677889900' >>> pskc.mac.algorithm 'http://www.w3.org/2000/09/xmldsig#hmac-sha1' >>> b2a_hex(key.secret) '3132333435363738393031323334353637383930' >>> key.check() True >>> key.algorithm 'urn:ietf:params:xml:ns:keyprov:pskc:hotp' >>> key.response_length 8 >>> key.manufacturer 'Manufacturer' This tests a derived master key using PBKDF2 as seen in figure 7 of RFC 6030. >>> pskc = PSKC('tests/rfc6030/figure7.pskcxml') >>> pskc.encryption.key_name 'My Password 1' >>> pskc.encryption.derive_key('qwerty') >>> b2a_hex(pskc.encryption.key) '651e63cd57008476af1ff6422cd02e41' >>> pskc.encryption.algorithm 'http://www.w3.org/2001/04/xmlenc#aes128-cbc' >>> b2a_hex(pskc.mac.key) 'bdaab8d648e850d25a3289364f7d7eaaf53ce581' >>> pskc.mac.algorithm 'http://www.w3.org/2000/09/xmldsig#hmac-sha1' >>> key = pskc.keys[0] >>> tostr(key.secret) '12345678901234567890' >>> key.check() True >>> key.algorithm 'urn:ietf:params:xml:ns:keyprov:pskc:hotp' >>> key.response_length 8 >>> key.manufacturer 'TokenVendorAcme' This tests a PSKC file that uses asymmetric encryption as seen in figure 8 of RFC 6030. Note thet python-pskc does not yet support asymmetric encryption so this test is really limited. >>> pskc = PSKC('tests/rfc6030/figure8.pskcxml') >>> pskc.id 'KC0001' >>> pskc.encryption.algorithm 'http://www.w3.org/2001/04/xmlenc#rsa_1_5' >>> key = pskc.keys[0] >>> key.manufacturer 'TokenVendorAcme' >>> key.serial '987654321' >>> key.id 'MBK000000001' >>> key.algorithm 'urn:ietf:params:xml:ns:keyprov:pskc:hotp' >>> key.issuer 'Example-Issuer' >>> key.response_encoding 'DECIMAL' >>> key.response_length 6 >>> tostr(key.secret) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... DecryptionError: No key available >>> key.counter 0 This tests a PSKC file that uses digital signature to sign the PSKC file as seen in figure 8 of RFC 6030. Note that python-pskc currently does not yet support checking this signature so this test is very limited. >>> pskc = PSKC('tests/rfc6030/figure9.pskcxml') >>> key = pskc.keys[0] >>> key.manufacturer 'TokenVendorAcme' >>> key.serial '0755225266' >>> key.id '123' >>> key.algorithm 'urn:ietf:params:xml:ns:keyprov:pskc:hotp' >>> key.issuer 'Example-Issuer' >>> key.response_encoding 'DECIMAL' >>> key.response_length 6 >>> tostr(key.secret) '12345678901234567890' >>> key.counter 0 This tests bulk provisioning as shown in figure 10 of RFC 6030. >>> pskc = PSKC('tests/rfc6030/figure10.pskcxml') >>> all(key.manufacturer == 'TokenVendorAcme' for key in pskc.keys) True >>> [key.serial for key in pskc.keys] ['654321', '123456', '9999999', '9999999'] >>> all(key.algorithm == 'urn:ietf:params:xml:ns:keyprov:pskc:hotp' for key in pskc.keys) True >>> all(key.issuer == 'Issuer' for key in pskc.keys) True >>> all(key.response_length == 8 for key in pskc.keys) True >>> all(key.response_encoding == 'DECIMAL' for key in pskc.keys) True >>> all(key.secret == b'12345678901234567890' for key in pskc.keys) True >>> all(key.counter == 0 for key in pskc.keys) True >>> pskc.keys[0].policy.start_date datetime.datetime(2006, 5, 1, 0, 0, tzinfo=tzutc()) >>> pskc.keys[0].policy.expiry_date datetime.datetime(2006, 5, 31, 0, 0, tzinfo=tzutc()) >>> pskc.keys[1].policy.start_date datetime.datetime(2006, 5, 1, 0, 0, tzinfo=tzutc()) >>> pskc.keys[1].policy.expiry_date datetime.datetime(2006, 5, 31, 0, 0, tzinfo=tzutc()) >>> pskc.keys[2].policy.start_date datetime.datetime(2006, 3, 1, 0, 0, tzinfo=tzutc()) >>> pskc.keys[2].policy.expiry_date datetime.datetime(2006, 3, 31, 0, 0, tzinfo=tzutc()) >>> pskc.keys[3].policy.start_date datetime.datetime(2006, 4, 1, 0, 0, tzinfo=tzutc()) >>> pskc.keys[3].policy.expiry_date datetime.datetime(2006, 4, 30, 0, 0, tzinfo=tzutc())