openbsd-ports/security/yubiserve/patches/patch-yubiserve_py
sthen ffbfde3b63 import ports/security/yubiserve, ok jsaper@
YubiServe is a lightweight Validation Server supporting both OATH/HOTP
and Yubico Yubikey implementations, written in Python that uses an
SQLite database or, optionally, a MySQL database. It has an integrated
threaded webserver, with HTTPS/SSL support, compatible with the
Yubico validation protocol 2.0 including HMAC SHA-1 signatures to
provide for authentication of the server.
2012-07-18 08:25:07 +00:00

165 lines
8.1 KiB
Plaintext

$OpenBSD: patch-yubiserve_py,v 1.1.1.1 2012/07/18 08:25:07 sthen Exp $
sqlite3 support from
http://code.google.com/p/yubico-yubiserve/source/list r39
--- yubiserve.py.orig Wed Jul 18 01:16:24 2012
+++ yubiserve.py Wed Jul 18 01:16:13 2012
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!${MODPY_BIN}
import re, os, time, socket
import urlparse, SocketServer, urllib, BaseHTTPServer
from Crypto.Cipher import AES
@@ -10,12 +10,16 @@ try:
except ImportError:
pass
try:
+ import sqlite3
+except ImportError:
+ pass
+try:
import sqlite
except ImportError:
pass
def parseConfigFile(): # Originally I wrote this function to parse PHP configuration files!
- config = open(os.path.dirname(os.path.realpath(__file__)) + '/yubiserve.cfg', 'r').read().splitlines()
+ config = open('${SYSCONFDIR}/yubiserve/yubiserve.cfg', 'r').read().splitlines()
keys = {}
for line in config:
match = re.search('(.*?)=(.*);', line)
@@ -45,7 +49,7 @@ class OATHValidation():
def validateOATH(self, OATH, publicID):
cur = self.con.cursor()
cur.execute("SELECT counter, secret FROM oathtokens WHERE publicname = '" + publicID + "' AND active = '1'")
- if (cur.rowcount != 1):
+ if cur:
validationResult = self.status['BAD_OTP']
return validationResult
(actualcounter, key) = cur.fetchone()
@@ -99,6 +103,7 @@ class OTPValidation():
def getResponse(self):
return self.validationResponse
def validateOTP(self, OTP):
+ global config
self.OTP = re.escape(OTP)
self.validationResult = 0
if (len(OTP) <= 32) or (len(OTP) > 48):
@@ -109,15 +114,21 @@ class OTPValidation():
if match.group(1) and match.group(2):
self.userid = match.group(1)
self.token = self.modhex2hex(match.group(2))
+ # pdb.set_trace()
cur = self.con.cursor()
cur.execute('SELECT aeskey, internalname FROM yubikeys WHERE publicname = "' + self.userid + '" AND active = "1"')
- if (cur.rowcount != 1):
+ if not cur:
+ if config['yubiserveDebugLevel'] > 0:
+ print "Yubikey rejected because it is not found in the database, using the query: 'SELECT aeskey, internalname FROM yubikeys WHERE publicname = \"%s\" AND active = \"1\"'" % (self.userid)
self.validationResult = self.status['BAD_OTP']
return self.validationResult
(self.aeskey, self.internalname) = cur.fetchone()
self.plaintext = self.aes128ecb_decrypt(self.aeskey, self.token)
uid = self.plaintext[:12]
if (self.internalname != uid):
+ if config['yubiserveDebugLevel'] > 0:
+ print "Yubikey rejected because the uid (6 byte secret) in the decrypted AES key (set with with ykpersonalise -ouid) does not match the secret key (internalname) in the database"
+ print "Decrypted AES: %s\n Username from yubikey: %s shoould equal the database username: %s" % (self.plaintext, uid, self.internalname)
self.validationResult = self.status['BAD_OTP']
return self.validationResult
if not (self.CRC() or self.isCRCValid()):
@@ -126,7 +137,7 @@ class OTPValidation():
self.internalcounter = self.hexdec(self.plaintext[14:16] + self.plaintext[12:14] + self.plaintext[22:24])
self.timestamp = self.hexdec(self.plaintext[20:22] + self.plaintext[18:20] + self.plaintext[16:18])
cur.execute('SELECT counter, time FROM yubikeys WHERE publicname = "' + self.userid + '" AND active = "1"')
- if (cur.rowcount != 1):
+ if not cur:
self.validationResult = self.status['BAD_OTP']
return self.validationResult
(self.counter, self.time) = cur.fetchone()
@@ -147,11 +158,13 @@ class OTPValidation():
class YubiServeHandler (BaseHTTPServer.BaseHTTPRequestHandler):
__base = BaseHTTPServer.BaseHTTPRequestHandler
__base_handle = __base.handle
- server_version = 'Yubiserve/3.0'
+ server_version = 'Yubiserve/3.1'
global config
#try:
- if config['yubiDB'] == 'sqlite':
- con = sqlite.connect(os.path.dirname(os.path.realpath(__file__)) + '/yubikeys.sqlite')
+ if config['yubiDB'] == 'sqlite3':
+ con = sqlite3.connect('/var/db/yubiserve/yubikeys.sqlite3', check_same_thread = False)
+ elif config['yubiDB'] == 'sqlite':
+ con = sqlite.connect('/var/db/yubiserve/yubikeys.sqlite', check_same_thread = False)
elif config['yubiDB'] == 'mysql':
con = MySQLdb.connect(host=config['yubiMySQLHost'], user=config['yubiMySQLUser'], passwd=config['yubiMySQLPass'], db=config['yubiMySQLName'])
#except:
@@ -200,16 +213,16 @@ class YubiServeHandler (BaseHTTPServer.BaseHTTPRequest
orderedResult = 'nonce=' + getData['nonce'] + '&otp=' + getData['otp'] + '&sl=100&status=' + [k for k, v in otpvalidation.status.iteritems() if v == validation][0] + '&t=' + iso_time
except KeyError:
result = 't=' + iso_time + '\r\notp=' + getData['otp'] + '\r\nnonce=\r\nsl=100\r\nstatus=' + [k for k, v in otpvalidation.status.iteritems() if v == validation][0] + '\r\n'
- orderedResult = 'nonce=&otp=' + getData['otp'] + 'sl=100&status=' + [k for k, v in otpvalidation.status.iteritems() if v == validation][0] + '&t=' + iso_time
+ orderedResult = 'nonce=&otp=' + getData['otp'] + '&sl=100&status=' + [k for k, v in otpvalidation.status.iteritems() if v == validation][0] + '&t=' + iso_time
otp_hmac = ''
try:
if (getData['id'] != None):
apiID = re.escape(getData['id'])
cur = self.con.cursor()
cur.execute("SELECT secret from apikeys WHERE id = '" + apiID + "'")
- if cur.rowcount != 0:
+ if cur:
api_key = cur.fetchone()[0]
- otp_hmac = hmac.new(api_key, msg=orderedResult, digestmod=hashlib.sha1).hexdigest().decode('hex').encode('base64').strip()
+ otp_hmac = hmac.new(str(api_key), msg=str(orderedResult), digestmod=hashlib.sha1).hexdigest().decode('hex').encode('base64').strip()
else:
result = 't=' + iso_time + '\r\notp=' + getData['otp'] + '\r\nstatus=NO_CLIENT\r\n'
except KeyError:
@@ -230,7 +243,7 @@ class YubiServeHandler (BaseHTTPServer.BaseHTTPRequest
apiID = re.escape(getData['id'])
cur = self.con.cursor()
cur.execute("SELECT secret from apikeys WHERE id = '" + apiID + "'")
- if cur.rowcount != 0:
+ if cur:
api_key = cur.fetchone()[0]
otp_hmac = hmac.new(api_key, msg=orderedResult, digestmod=hashlib.sha1).hexdigest().decode('hex').encode('base64').strip()
except KeyError:
@@ -264,7 +277,7 @@ class YubiServeHandler (BaseHTTPServer.BaseHTTPRequest
apiID = re.escape(getData['id'])
cur = self.con.cursor()
cur.execute("SELECT secret from apikeys WHERE id = '" + apiID + "'")
- if cur.rowcount != 0:
+ if cur:
api_key = cur.fetchone()[0]
otp_hmac = hmac.new(api_key, msg=result, digestmod=hashlib.sha1).hexdigest().decode('hex').encode('base64').strip()
else:
@@ -285,7 +298,7 @@ class YubiServeHandler (BaseHTTPServer.BaseHTTPRequest
apiID = re.escape(getData['id'])
cur = self.con.cursor()
cur.execute("SELECT secret from apikeys WHERE id = '" + apiID + "'")
- if cur.rowcount != 0:
+ if cur:
api_key = cur.fetchone()[0]
otp_hmac = hmac.new(api_key, msg=result, digestmod=hashlib.sha1).hexdigest().decode('hex').encode('base64').strip()
except KeyError:
@@ -305,7 +318,7 @@ class YubiServeHandler (BaseHTTPServer.BaseHTTPRequest
apiID = re.escape(getData['id'])
cur = self.con.cursor()
cur.execute("SELECT secret from apikeys WHERE id = '" + apiID + "'")
- if cur.rowcount != 0:
+ if cur:
api_key = cur.fetchone()[0]
otp_hmac = hmac.new(api_key, msg=result, digestmod=hashlib.sha1).hexdigest().decode('hex').encode('base64').strip()
except KeyError:
@@ -321,8 +334,8 @@ class YubiServeHandler (BaseHTTPServer.BaseHTTPRequest
class SecureHTTPServer(BaseHTTPServer.HTTPServer):
def __init__(self, server_address, HandlerClass):
BaseHTTPServer.HTTPServer.__init__(self, server_address, HandlerClass)
- ctx = SSL.Context(SSL.SSLv23_METHOD)
- fpem = os.path.dirname(os.path.realpath(__file__)) + '/yubiserve.pem'
+ ctx = SSL.Context(SSL.SSLv3_METHOD)
+ fpem = '${SYSCONFDIR}/yubiserve/yubiserve.pem'
ctx.use_privatekey_file (fpem)
ctx.use_certificate_file(fpem)
self.socket = SSL.Connection(ctx, socket.socket(self.address_family, self.socket_type))