5 # Marcelo Fernandez - bugfix and NPN support
6 # Martin von Loewis - python 3 port
8 # See the LICENSE file for legal information regarding use of this file.
9 from __future__
import print_function
18 from SocketServer
import *
19 from BaseHTTPServer
import *
20 from SimpleHTTPServer
import *
23 from http
import client
as httplib
24 from socketserver
import *
25 from http
.server
import *
27 if __name__
!= "__main__":
28 raise "This must be run as a command, not used as a module!"
30 from tlslite
.api
import *
31 from tlslite
import __version__
34 from tack
.structures
.Tack
import Tack
39 def printUsage(s
=None):
41 print("ERROR: %s" % s
)
44 print("Version: %s" % __version__
)
46 print("RNG: %s" % prngName
)
50 print(" tackpy : Loaded")
52 print(" tackpy : Not Loaded")
54 print(" M2Crypto : Loaded")
56 print(" M2Crypto : Not Loaded")
58 print(" pycrypto : Loaded")
60 print(" pycrypto : Not Loaded")
62 print(" GMPY : Loaded")
64 print(" GMPY : Not Loaded")
70 [-k KEY] [-c CERT] [-t TACK] [-v VERIFIERDB] [-d DIR]
74 [-k KEY] [-c CERT] [-u USER] [-p PASS]
80 """Print error message and exit"""
81 sys
.stderr
.write("ERROR: %s\n" % s
)
85 def handleArgs(argv
, argString
, flagsList
=[]):
86 # Convert to getopt argstring format:
87 # Add ":" after each arg, ie "abc" -> "a:b:c:"
88 getOptArgString
= ":".join(argString
) + ":"
90 opts
, argv
= getopt
.getopt(argv
, getOptArgString
, flagsList
)
91 except getopt
.GetoptError
as e
:
93 # Default values if arg not present
103 for opt
, arg
in opts
:
105 s
= open(arg
, "rb").read()
106 privateKey
= parsePEMKey(s
, private
=True)
108 s
= open(arg
, "rb").read()
111 certChain
= X509CertChain([x509
])
118 s
= open(arg
, "rU").read()
119 tacks
= Tack
.createFromPemList(s
)
121 verifierDB
= VerifierDB(arg
)
125 elif opt
== "--reqcert":
131 printError("Missing address")
133 printError("Too many arguments")
134 #Split address into hostname/port tuple
136 address
= address
.split(":")
137 if len(address
) != 2:
138 raise SyntaxError("Must specify <host>:<port>")
139 address
= ( address
[0], int(address
[1]) )
141 # Populate the return list
144 retList
.append(privateKey
)
146 retList
.append(certChain
)
148 retList
.append(username
)
150 retList
.append(password
)
152 retList
.append(tacks
)
154 retList
.append(verifierDB
)
156 retList
.append(directory
)
157 if "reqcert" in flagsList
:
158 retList
.append(reqCert
)
162 def printGoodConnection(connection
, seconds
):
163 print(" Handshake time: %.3f seconds" % seconds
)
164 print(" Version: %s" % connection
.getVersionName())
165 print(" Cipher: %s %s" % (connection
.getCipherName(),
166 connection
.getCipherImplementation()))
167 if connection
.session
.srpUsername
:
168 print(" Client SRP username: %s" % connection
.session
.srpUsername
)
169 if connection
.session
.clientCertChain
:
170 print(" Client X.509 SHA1 fingerprint: %s" %
171 connection
.session
.clientCertChain
.getFingerprint())
172 if connection
.session
.serverCertChain
:
173 print(" Server X.509 SHA1 fingerprint: %s" %
174 connection
.session
.serverCertChain
.getFingerprint())
175 if connection
.session
.serverName
:
176 print(" SNI: %s" % connection
.session
.serverName
)
177 if connection
.session
.tackExt
:
178 if connection
.session
.tackInHelloExt
:
179 emptyStr
= "\n (via TLS Extension)"
181 emptyStr
= "\n (via TACK Certificate)"
182 print(" TACK: %s" % emptyStr
)
183 print(str(connection
.session
.tackExt
))
184 print(" Next-Protocol Negotiated: %s" % connection
.next_proto
)
188 (address
, privateKey
, certChain
, username
, password
) = \
189 handleArgs(argv
, "kcup")
191 if (certChain
and not privateKey
) or (not certChain
and privateKey
):
192 raise SyntaxError("Must specify CERT and KEY together")
193 if (username
and not password
) or (not username
and password
):
194 raise SyntaxError("Must specify USER with PASS")
195 if certChain
and username
:
196 raise SyntaxError("Can use SRP or client cert for auth, not both")
199 sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_STREAM
)
201 sock
.connect(address
)
202 connection
= TLSConnection(sock
)
204 settings
= HandshakeSettings()
205 settings
.useExperimentalTackExtension
= True
209 if username
and password
:
210 connection
.handshakeClientSRP(username
, password
,
211 settings
=settings
, serverName
=address
[0])
213 connection
.handshakeClientCert(certChain
, privateKey
,
214 settings
=settings
, serverName
=address
[0])
216 print("Handshake success")
217 except TLSLocalAlert
as a
:
218 if a
.description
== AlertDescription
.user_canceled
:
223 except TLSRemoteAlert
as a
:
224 if a
.description
== AlertDescription
.unknown_psk_identity
:
226 print("Unknown username")
229 elif a
.description
== AlertDescription
.bad_record_mac
:
231 print("Bad username or password")
234 elif a
.description
== AlertDescription
.handshake_failure
:
235 print("Unable to negotiate mutually acceptable parameters")
239 printGoodConnection(connection
, stop
-start
)
244 (address
, privateKey
, certChain
, tacks
,
245 verifierDB
, directory
, reqCert
) = handleArgs(argv
, "kctbvd", ["reqcert"])
248 if (certChain
and not privateKey
) or (not certChain
and privateKey
):
249 raise SyntaxError("Must specify CERT and KEY together")
250 if tacks
and not certChain
:
251 raise SyntaxError("Must specify CERT with Tacks")
253 print("I am an HTTPS test server, I will listen on %s:%d" %
254 (address
[0], address
[1]))
257 print("Serving files from %s" % os
.getcwd())
259 if certChain
and privateKey
:
260 print("Using certificate and private key...")
262 print("Using verifier DB...")
264 print("Using Tacks...")
267 sessionCache
= SessionCache()
269 class MyHTTPServer(ThreadingMixIn
, TLSSocketServerMixIn
, HTTPServer
):
270 def handshake(self
, connection
):
271 print("About to handshake...")
276 elif len(tacks
) == 2:
281 settings
= HandshakeSettings()
282 settings
.useExperimentalTackExtension
=True
283 connection
.handshakeServer(certChain
=certChain
,
284 privateKey
=privateKey
,
285 verifierDB
=verifierDB
,
287 activationFlags
=activationFlags
,
288 sessionCache
=sessionCache
,
290 nextProtos
=[b
"http/1.1"])
291 # As an example (does not work here):
292 #nextProtos=[b"spdy/3", b"spdy/2", b"http/1.1"])
294 except TLSRemoteAlert
as a
:
295 if a
.description
== AlertDescription
.user_canceled
:
300 except TLSLocalAlert
as a
:
301 if a
.description
== AlertDescription
.unknown_psk_identity
:
303 print("Unknown username")
307 elif a
.description
== AlertDescription
.bad_record_mac
:
309 print("Bad username or password")
313 elif a
.description
== AlertDescription
.handshake_failure
:
314 print("Unable to negotiate mutually acceptable parameters")
319 connection
.ignoreAbruptClose
= True
320 printGoodConnection(connection
, stop
-start
)
323 httpd
= MyHTTPServer(address
, SimpleHTTPRequestHandler
)
324 httpd
.serve_forever()
327 if __name__
== '__main__':
328 if len(sys
.argv
) < 2:
329 printUsage("Missing command")
330 elif sys
.argv
[1] == "client"[:len(sys
.argv
[1])]:
331 clientCmd(sys
.argv
[2:])
332 elif sys
.argv
[1] == "server"[:len(sys
.argv
[1])]:
333 serverCmd(sys
.argv
[2:])
335 printUsage("Unknown command: %s" % sys
.argv
[1])