Skip to content

Commit 8149b23

Browse files
committed
Add test case for CryptoBackendXMLSecurity with PKCS#11.
1 parent f21b9d2 commit 8149b23

File tree

2 files changed

+231
-0
lines changed

2 files changed

+231
-0
lines changed

tests/test.key.p8

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMmDZyazsyqOeJPw
3+
WL9eQ0dk09s1VDIxQxcT21c52rBgIDVxzy9B3OSKGxxAxfLeI/DZwyCAG7qCMxM5
4+
I7EQKS69flkJyUqvylcAkzlxjqBU5pU7Y91Nly8MEoZuJo15+ITDmGehmiapkanz
5+
Ac0sBSTC0f2+Oqq/HJL+9yVzqTZ7AgMBAAECgYEAoPZ6ZbqyybKF9D3O1gW4ngWX
6+
CIl/mJwq5/svgGwxGCOgdrBS+3+Tr2X1o8rFk2sHsHJxX7uU6pTnsVo5/UxYZ5bO
7+
xTlthRWkXM5XCxji6a2w7vxAYotl773Vn6S06WYvexwDKYCATzwmavSDwULjpW/h
8+
JqbvMwK2Y68D19iiDVkCQQDyUB75eKFK5kjohlx1F0HpAnlyAAmhl1Yoq1Si9vkC
9+
HbDgP95uR+mxAkrjhpJHkZueuepJox4skxHP75N3R50fAkEA1OVQHOijeKFwE5nR
10+
XMZiAMgbx+gJMR/eMMFg1hpj1Ef9zg/nQaQNrg8Gq1/V/5U5HACwLY1N5jodQRYy
11+
m99fJQJBAKFDcVnWToHqgNs/kIjc0aChZPHZ1I8WiODIJavPcilWWUDlQMNkWMLV
12+
I8II7ZFz9n3MfYBEbvB7cH9SknHv10ECQQCI9zqyTo0VB6+mPJhwOoVEgXk2BDcd
13+
rqXw8ghN1k6RfPtxfdPG7DeM2sfsq0xvEN7cAClYNQd/7bVycUh/9ZYtAkB4bQoo
14+
F9nDWJG72+VxhqQZZFRKBrvxAPLTy4cO3FAtfE59K+b/Lw3UqsSxd/9wnMdQZAmu
15+
qTycvNHmZNGqcBlY
16+
-----END PRIVATE KEY-----

tests/test_80_p11_backend.py

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
"""
2+
Testing CryptoBackendXMLSecurity with SoftHSM as backend
3+
"""
4+
5+
# Command to convert test.pem to PKCS#8 PEM format readable by softhsm :
6+
#
7+
# openssl pkcs8 -topk8 -inform PEM -outform PEM -in test.key -out test.key.p8 -nocrypt
8+
#
9+
10+
__author__ = 'leifj' # based on p11_test from pyXMLSecurity
11+
12+
import logging
13+
import os
14+
import traceback
15+
import subprocess
16+
import tempfile
17+
import pytest
18+
from pathutils import full_path
19+
20+
from saml2 import sigver
21+
from saml2 import class_name
22+
from saml2 import time_util
23+
from saml2 import saml
24+
from saml2.s_utils import factory, do_attribute_statement
25+
26+
xmlsec = pytest.importorskip("xmlsec")
27+
28+
def _find_alts(alts):
29+
for a in alts:
30+
if os.path.exists(a):
31+
return a
32+
return None
33+
34+
35+
PUB_KEY = full_path("test.pem")
36+
PRIV_KEY = full_path("test.key.p8")
37+
38+
P11_MODULES = ['/usr/lib/libsofthsm.so', '/usr/lib/softhsm/libsofthsm.so']
39+
P11_MODULE = _find_alts(P11_MODULES)
40+
P11_ENGINE = '/usr/lib/engines/engine_pkcs11.so'
41+
42+
43+
def _eq(l1, l2):
44+
return set(l1) == set(l2)
45+
46+
47+
class FakeConfig():
48+
"""
49+
Configuration parameters for signature validation test cases.
50+
"""
51+
def __init__(self, pub_key = PUB_KEY):
52+
self.xmlsec_binary = None
53+
self.crypto_backend = 'XMLSecurity'
54+
self.only_use_keys_in_metadata = False
55+
self.metadata = None
56+
self.cert_file = pub_key
57+
self.key_file = "pkcs11://%s:0/test?pin=secret1" % P11_MODULE
58+
self.debug = False
59+
60+
61+
class TestPKCS11():
62+
63+
def __init__(self):
64+
self.private_keyspec = None
65+
self.public_keyspec = None
66+
self.p11_test_files = []
67+
self.softhsm_conf = None
68+
self.softhsm_db = None
69+
self.configured = False
70+
self.sec = None
71+
self._assertion = None
72+
73+
def setup_class(self):
74+
logging.debug("Creating test pkcs11 token using softhsm")
75+
try:
76+
self.softhsm_db = self._tf()
77+
self.softhsm_conf = self._tf()
78+
self.signer_cert_pem = self._tf()
79+
self.openssl_conf = self._tf()
80+
self.signer_cert_der = self._tf()
81+
82+
logging.debug("Generating softhsm.conf")
83+
with open(self.softhsm_conf, "w") as f:
84+
f.write("#Generated by pysaml2 cryptobackend test\n0:%s\n" % self.softhsm_db)
85+
logging.debug("Initializing the token")
86+
self._p(['softhsm',
87+
'--slot', '0',
88+
'--label', 'test',
89+
'--init-token',
90+
'--pin', 'secret1',
91+
'--so-pin', 'secret2'])
92+
93+
logging.debug("Importing test key {!r} into SoftHSM".format(PRIV_KEY))
94+
self._p(['softhsm',
95+
'--slot', '0',
96+
'--label', 'test',
97+
'--import', PRIV_KEY,
98+
'--id', 'a1b2',
99+
'--pin', 'secret1',
100+
'--so-pin', 'secret2'])
101+
102+
logging.debug("Transforming PEM certificate to DER")
103+
self._p(['openssl', 'x509',
104+
'-inform', 'PEM',
105+
'-outform', 'DER',
106+
'-in', PUB_KEY,
107+
'-out', self.signer_cert_der])
108+
109+
logging.debug("Importing certificate into token")
110+
111+
self._p(['pkcs11-tool',
112+
'--module', P11_MODULE,
113+
'-l',
114+
'--slot', '0',
115+
'--id', 'a1b2',
116+
'--label', 'test',
117+
'-y', 'cert',
118+
'-w', self.signer_cert_der,
119+
'--pin', 'secret1'])
120+
121+
# list contents of SoftHSM
122+
self._p(['pkcs11-tool',
123+
'--module', P11_MODULE,
124+
'-l',
125+
'--pin', 'secret1', '-O'])
126+
self._p(['pkcs11-tool',
127+
'--module', P11_MODULE,
128+
'-l',
129+
'--pin', 'secret1', '-T'])
130+
self._p(['pkcs11-tool',
131+
'--module', P11_MODULE,
132+
'-l',
133+
'--pin', 'secret1', '-L'])
134+
self.sec = sigver.security_context(FakeConfig(pub_key = PUB_KEY))
135+
self._assertion = factory(saml.Assertion,
136+
version="2.0",
137+
id="11111",
138+
issue_instant="2009-10-30T13:20:28Z",
139+
signature=sigver.pre_signature_part("11111", self.sec.my_cert, 1),
140+
attribute_statement=do_attribute_statement(
141+
{("", "", "surName"): ("Foo", ""),
142+
("", "", "givenName"): ("Bar", ""),
143+
})
144+
)
145+
self.configured = True
146+
except Exception, ex:
147+
print "-" * 64
148+
traceback.print_exc()
149+
print "-" * 64
150+
logging.warning("PKCS11 tests disabled: unable to initialize test token: %s" % ex)
151+
raise
152+
153+
def teardown_class(self):
154+
"""
155+
Remove temporary files created in setup_class.
156+
"""
157+
for o in self.p11_test_files:
158+
if os.path.exists(o):
159+
os.unlink(o)
160+
self.configured = False
161+
self.p11_test_files = []
162+
163+
def _tf(self):
164+
f = tempfile.NamedTemporaryFile(delete=False)
165+
self.p11_test_files.append(f.name)
166+
return f.name
167+
168+
def _p(self, args):
169+
env = {}
170+
if self.softhsm_conf is not None:
171+
env['SOFTHSM_CONF'] = self.softhsm_conf
172+
#print "env SOFTHSM_CONF=%s " % softhsm_conf +" ".join(args)
173+
logging.debug("Environment {!r}".format(env))
174+
logging.debug("Executing {!r}".format(args))
175+
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
176+
out, err = proc.communicate()
177+
if err is not None and len(err) > 0:
178+
logging.error(err)
179+
if out is not None and len(out) > 0:
180+
logging.debug(out)
181+
rv = proc.wait()
182+
if rv:
183+
raise RuntimeError("command exited with code != 0: %d" % rv)
184+
185+
def test_SAML_sign_with_pkcs11(self):
186+
"""
187+
Test signing a SAML assertion using PKCS#11 and then verifying it.
188+
"""
189+
os.environ['SOFTHSM_CONF'] = self.softhsm_conf
190+
191+
ass = self._assertion
192+
print ass
193+
sign_ass = self.sec.sign_assertion("%s" % ass, node_id=ass.id)
194+
#print sign_ass
195+
sass = saml.assertion_from_string(sign_ass)
196+
#print sass
197+
assert _eq(sass.keyswv(), ['attribute_statement', 'issue_instant',
198+
'version', 'signature', 'id'])
199+
assert sass.version == "2.0"
200+
assert sass.id == "11111"
201+
assert time_util.str_to_time(sass.issue_instant)
202+
203+
print "Crypto version : %s" % (self.sec.crypto.version())
204+
205+
item = self.sec.check_signature(sass, class_name(sass), sign_ass)
206+
207+
assert isinstance(item, saml.Assertion)
208+
209+
print "Test PASSED"
210+
211+
212+
def test_xmlsec_cryptobackend():
213+
t = TestPKCS11()
214+
t.setup_class()
215+
t.test_SAML_sign_with_pkcs11()

0 commit comments

Comments
 (0)