test_sspi.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. # Some tests of the win32security sspi functions.
  2. # Stolen from Roger's original test_sspi.c, a version of which is in "Demos"
  3. # See also the other SSPI demos.
  4. import re
  5. import win32security, sspi, sspicon, win32api
  6. from pywin32_testutil import TestSkipped, testmain, str2bytes
  7. import unittest
  8. # It is quite likely that the Kerberos tests will fail due to not being
  9. # installed. The NTLM tests do *not* get the same behaviour as they should
  10. # always be there.
  11. def applyHandlingSkips(func, *args):
  12. try:
  13. return func(*args)
  14. except win32api.error as exc:
  15. if exc.winerror == sspicon.SEC_E_NO_CREDENTIALS:
  16. raise TestSkipped(exc)
  17. raise
  18. class TestSSPI(unittest.TestCase):
  19. def assertRaisesHRESULT(self, hr, func, *args):
  20. try:
  21. return func(*args)
  22. raise RuntimeError("expecting %s failure" % (hr,))
  23. except win32security.error as exc:
  24. self.failUnlessEqual(exc.winerror, hr)
  25. def _doAuth(self, pkg_name):
  26. sspiclient=sspi.ClientAuth(pkg_name,targetspn=win32api.GetUserName())
  27. sspiserver=sspi.ServerAuth(pkg_name)
  28. sec_buffer=None
  29. err = 1
  30. while err != 0:
  31. err, sec_buffer = sspiclient.authorize(sec_buffer)
  32. err, sec_buffer = sspiserver.authorize(sec_buffer)
  33. return sspiclient, sspiserver
  34. def _doTestImpersonate(self, pkg_name):
  35. # Just for the sake of code exercising!
  36. sspiclient, sspiserver = self._doAuth(pkg_name)
  37. sspiserver.ctxt.ImpersonateSecurityContext()
  38. sspiserver.ctxt.RevertSecurityContext()
  39. def testImpersonateKerberos(self):
  40. applyHandlingSkips(self._doTestImpersonate, "Kerberos")
  41. def testImpersonateNTLM(self):
  42. self._doTestImpersonate("NTLM")
  43. def _doTestEncrypt(self, pkg_name):
  44. sspiclient, sspiserver = self._doAuth(pkg_name)
  45. pkg_size_info=sspiclient.ctxt.QueryContextAttributes(sspicon.SECPKG_ATTR_SIZES)
  46. msg=str2bytes('some data to be encrypted ......')
  47. trailersize=pkg_size_info['SecurityTrailer']
  48. encbuf=win32security.PySecBufferDescType()
  49. encbuf.append(win32security.PySecBufferType(len(msg), sspicon.SECBUFFER_DATA))
  50. encbuf.append(win32security.PySecBufferType(trailersize, sspicon.SECBUFFER_TOKEN))
  51. encbuf[0].Buffer=msg
  52. sspiclient.ctxt.EncryptMessage(0,encbuf,1)
  53. sspiserver.ctxt.DecryptMessage(encbuf,1)
  54. self.failUnlessEqual(msg, encbuf[0].Buffer)
  55. # and test the higher-level functions
  56. data_in = str2bytes("hello")
  57. data, sig = sspiclient.encrypt(data_in)
  58. self.assertEqual(sspiserver.decrypt(data, sig), data_in)
  59. data, sig = sspiserver.encrypt(data_in)
  60. self.assertEqual(sspiclient.decrypt(data, sig), data_in)
  61. def _doTestEncryptStream(self, pkg_name):
  62. # Test out the SSPI/GSSAPI interop wrapping examples at
  63. # https://docs.microsoft.com/en-us/windows/win32/secauthn/sspi-kerberos-interoperability-with-gssapi
  64. sspiclient, sspiserver = self._doAuth(pkg_name)
  65. pkg_size_info=sspiclient.ctxt.QueryContextAttributes(sspicon.SECPKG_ATTR_SIZES)
  66. msg=str2bytes('some data to be encrypted ......')
  67. trailersize=pkg_size_info['SecurityTrailer']
  68. blocksize=pkg_size_info['BlockSize']
  69. encbuf=win32security.PySecBufferDescType()
  70. encbuf.append(win32security.PySecBufferType(trailersize, sspicon.SECBUFFER_TOKEN))
  71. encbuf.append(win32security.PySecBufferType(len(msg), sspicon.SECBUFFER_DATA))
  72. encbuf.append(win32security.PySecBufferType(blocksize, sspicon.SECBUFFER_PADDING))
  73. encbuf[1].Buffer=msg
  74. sspiclient.ctxt.EncryptMessage(0,encbuf,1)
  75. encmsg = encbuf[0].Buffer + encbuf[1].Buffer + encbuf[2].Buffer
  76. decbuf=win32security.PySecBufferDescType()
  77. decbuf.append(win32security.PySecBufferType(len(encmsg), sspicon.SECBUFFER_STREAM))
  78. decbuf.append(win32security.PySecBufferType(0, sspicon.SECBUFFER_DATA))
  79. decbuf[0].Buffer = encmsg
  80. sspiserver.ctxt.DecryptMessage(decbuf,1)
  81. self.failUnlessEqual(msg, decbuf[1].Buffer)
  82. def testEncryptNTLM(self):
  83. self._doTestEncrypt("NTLM")
  84. def testEncryptStreamNTLM(self):
  85. self._doTestEncryptStream("NTLM")
  86. def testEncryptKerberos(self):
  87. applyHandlingSkips(self._doTestEncrypt, "Kerberos")
  88. def testEncryptStreamKerberos(self):
  89. applyHandlingSkips(self._doTestEncryptStream, "Kerberos")
  90. def _doTestSign(self, pkg_name):
  91. sspiclient, sspiserver = self._doAuth(pkg_name)
  92. pkg_size_info=sspiclient.ctxt.QueryContextAttributes(sspicon.SECPKG_ATTR_SIZES)
  93. msg=str2bytes('some data to be encrypted ......')
  94. sigsize=pkg_size_info['MaxSignature']
  95. sigbuf=win32security.PySecBufferDescType()
  96. sigbuf.append(win32security.PySecBufferType(len(msg), sspicon.SECBUFFER_DATA))
  97. sigbuf.append(win32security.PySecBufferType(sigsize, sspicon.SECBUFFER_TOKEN))
  98. sigbuf[0].Buffer=msg
  99. sspiclient.ctxt.MakeSignature(0,sigbuf,0)
  100. sspiserver.ctxt.VerifySignature(sigbuf,0)
  101. # and test the higher-level functions
  102. sspiclient.next_seq_num = 1
  103. sspiserver.next_seq_num = 1
  104. data = str2bytes("hello")
  105. key = sspiclient.sign(data)
  106. sspiserver.verify(data, key)
  107. key = sspiclient.sign(data)
  108. self.assertRaisesHRESULT(sspicon.SEC_E_MESSAGE_ALTERED,
  109. sspiserver.verify, data + data, key)
  110. # and the other way
  111. key = sspiserver.sign(data)
  112. sspiclient.verify(data, key)
  113. key = sspiserver.sign(data)
  114. self.assertRaisesHRESULT(sspicon.SEC_E_MESSAGE_ALTERED,
  115. sspiclient.verify, data + data, key)
  116. def testSignNTLM(self):
  117. self._doTestSign("NTLM")
  118. def testSignKerberos(self):
  119. applyHandlingSkips(self._doTestSign, "Kerberos")
  120. def _testSequenceSign(self):
  121. # Only Kerberos supports sequence detection.
  122. sspiclient, sspiserver = self._doAuth("Kerberos")
  123. key = sspiclient.sign("hello")
  124. sspiclient.sign("hello")
  125. self.assertRaisesHRESULT(sspicon.SEC_E_OUT_OF_SEQUENCE,
  126. sspiserver.verify, 'hello', key)
  127. def testSequenceSign(self):
  128. applyHandlingSkips(self._testSequenceSign)
  129. def _testSequenceEncrypt(self):
  130. # Only Kerberos supports sequence detection.
  131. sspiclient, sspiserver = self._doAuth("Kerberos")
  132. blob, key = sspiclient.encrypt("hello",)
  133. blob, key = sspiclient.encrypt("hello")
  134. self.assertRaisesHRESULT(sspicon.SEC_E_OUT_OF_SEQUENCE,
  135. sspiserver.decrypt, blob, key)
  136. def testSequenceEncrypt(self):
  137. applyHandlingSkips(self._testSequenceEncrypt)
  138. def testSecBufferRepr(self):
  139. desc = win32security.PySecBufferDescType()
  140. assert re.match('PySecBufferDesc\(ulVersion: 0 \| cBuffers: 0 \| pBuffers: 0x[\da-fA-F]{8,16}\)', repr(desc))
  141. buffer1 = win32security.PySecBufferType(0, sspicon.SECBUFFER_TOKEN)
  142. assert re.match('PySecBuffer\(cbBuffer: 0 \| BufferType: 2 \| pvBuffer: 0x[\da-fA-F]{8,16}\)', repr(buffer1))
  143. 'PySecBuffer(cbBuffer: 0 | BufferType: 2 | pvBuffer: 0x000001B8CC6D8020)'
  144. desc.append(buffer1)
  145. assert re.match('PySecBufferDesc\(ulVersion: 0 \| cBuffers: 1 \| pBuffers: 0x[\da-fA-F]{8,16}\)', repr(desc))
  146. buffer2 = win32security.PySecBufferType(4, sspicon.SECBUFFER_DATA)
  147. assert re.match('PySecBuffer\(cbBuffer: 4 \| BufferType: 1 \| pvBuffer: 0x[\da-fA-F]{8,16}\)', repr(buffer2))
  148. desc.append(buffer2)
  149. assert re.match('PySecBufferDesc\(ulVersion: 0 \| cBuffers: 2 \| pBuffers: 0x[\da-fA-F]{8,16}\)', repr(desc))
  150. if __name__=='__main__':
  151. testmain()