Friday 18 February 2011

LDAP + OTP over CHAP

Many peope wish they can use LDAP Password + OTP in RADIUS authentication to enhance their security. MSCHAP(CHAP) is defacto the common protocol used in RADIUS, as PAP is denounced due to its plain text transmission across the Internet. However it is technically impossible for LDAP + OTP over CHAP. Why? you will certainly ask the same question as I did when I first dealt with it. Basically, you can regard CHAP as a hash algorithm like the popular MD5 or SHA1. In mathematics,


HASH(StaticPass + OTP) != HASH(StaticPass) + HASH(OTP)


At VPN client side, you input StaticPass + OTP, at VPN server side, the server receives HASH(StaticPass + OTP). If the server has no plain text of StaticPass, then it is impossible for the server to decide if there is a match. Unfortunately LDAP password is not available as a plain text. According to MS, the password itself is actually a LM hash. As a result, none of any two factor authentiction service providers can support LDAP + OTP over CHAP. If you know any vendors who claim they support this, please let me know.


Here is the summary of Deepnet Radius Authentication. X = supported.


In the situation where StaticPass token doesn't physically exist in Deepent database, LDAP password is used instead.
































MSCHAP2(CHAP)PAP
StaticPass
X
OTP
X1
X
StaticPass + OTP
X
StaticPass >> OTP
X


If a StaticPass token exists, the password can be retrieved in Deepnet.

































MSCHAP2(CHAP)PAP
StaticPass
X
X
OTP
X1
X
StaticPass + OTP
X1
X
StaticPass >> OTP
X1
X

Note: 1 All OTP tokens except vasco token.

Wednesday 16 February 2011

Passing Username

Deepnet IIS solution adds an additional login page, that means the user has to type his username twice which is inconvenience. Is there any way to pass the username typed on the first login (deepnet) page down to the second login(the original) page?


The answer is YES. Let's take Microsoft Remote Web Workplace in SBS as an example, find the related file "logon.aspx", locate the line



<TD class="linkText"><INPUT id="txtUserName" tabIndex="1" type="text" name="txtUserName" ></TD>


change it to



<TD class="linkText"><INPUT id="txtUserName" tabIndex="1" type="text" name="txtUserName" value='<%=Request.Cookies["DasUserName"] == null ? string.Empty : Request.Cookies["DasUserName"].Value%>' ></TD>


As you can see, the value attribute is added: value='<%=Request.Cookies["DasUserName"] == null ? string.Empty : Request.Cookies["DasUserName"].Value%>'


If the object is run at server (runat="server"), then you should change it to be like



<td align=right class=linkText><%=loadResString("L_LOGON_USER_NAME")%></td>
<TD class="linkText"><INPUT id="txtUserName" tabIndex="1" type="text" name="txtUserName" runat="server"></TD>
<td class="linkText"></td>
<script type="text/javascript">
<!-- //
var cookie = GetDASCookie('DasUserName');
document.getElementById('<%=txtUserName.ClientID%>').value = cookie.split('=')[1];
//-->
</script>



Furthermore, in order to prevent the field from editing, you can add readonly attribute.



<TD class="linkText"><INPUT id="txtUserName" tabIndex="1" type="text" name="txtUserName" readonly="readonly" value='<%=Request.Cookies["DasUserName"] == null ? string.Empty : Request.Cookies["DasUserName"].Value%>' runat="server"></TD>

Deepnet mandate option on ActiveSync

Somehow the mandate option in Deepnet IIS solution doesn't work on ActiveSync protection. Once you add the deepnet protection on ActiveSync node, then each mobile device which synchronizes with Exchange server will need two-factor authentication, no matter you check on/off the mandate option.


In testing phase, It's quite likely that you want one or two devices to be protected with Deepnet 2-factor authentication while the others still work with the original one factor(Windows username/password).


Well, how to achieve this purpose? Here it is the workaround.


After assigning the event filter(see the related user guide from Deepnet), edit its content. The following python script will function as non-mandate option on deepnet ActiveSync protection.



"""
This is a trigger script used by DAS

# return integer:
# zero: continue trigger chain
# nonzero: quit chain

# return boolean
# False: continue trigger chain
# True: quit chain

# return dictionary
# dict['noContinue']
# dict['noLog']
# dict['newReturnVal']
#
"""
#import socket
import sys
import java.util.Hashtable

def Log(msg):
return
# HOST = '192.168.111.168' # The remote host
# PORT = 7000 # The same port as used by the server
# s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# s.connect((HOST, PORT))
# s.send(str(msg) +'\r\n')
# s.close()

class Trigger:
def __init__(self):
pass

def execute(self, *args, **dict):

try:
if filter_context is None:
return 0
except:
return 0

Log('------------------------')
#Log(filter_context['DasAPI'].hello()[0])
Log(filter_context['appID'])
Log(filter_context['resultCode'])

for i in filter_context.keys():
#Log(i)
#Log(filter_context[i])
Log(i + ': ' + str(filter_context[i]))

if not filter_context.containsKey('method'):
return 0

if filter_context['method'].lower()!='devicepass':
return 0

Log('DevicePass found')

# if user account not found, try to import it from LDAP
if filter_context['resultCode']=='E-USERID-NOT-FOUND' or filter_context['resultCode']=='E-LOGINNAME-NOT-FOUND':
# bRet = self.importAccount()

# if bRet==True:
# bRet = self.createToken()
# if bRet==True:
# return self.changeReturn('E-TOKEN-INACTIVE')
return self.changeReturn('TRUE')

if filter_context['resultCode']=='E-TOKEN-NOT-FOUND' or filter_context['resultCode']=='E-METHOD-NOT-FOUND':
bRet = self.createToken()
if bRet==True:
return self.changeReturn('E-TOKEN-INACTIVE')

return 0

def importAccount(self):
try:
result = filter_context['DasAPI'].importAccount(
filter_context['appID'], filter_context['loginName'])
Log( 'importAccount: ' + str(result) )
if result[0]=='OK':
self.newUserID = str(result[1])
return True
return False
except:
Log(sys.exc_info()[0])
return False

def createToken(self):
try:
tokenInfo = java.util.Hashtable()
tokenInfo['credential'] = filter_context['credential']
tokenInfo['method'] = filter_context['method']
tokenInfo['description'] = 'created by trigger'
userID = filter_context['userID']
if userID=='':
userID = self.newUserID

result = filter_context['DasAPI'].createToken(
filter_context['appID'],
userID, tokenInfo, False)
Log( 'createToken: ' + str(result) )
if result[0]=='OK':
return True
return False
except:
Log(sys.exc_info()[0])
return False;


def changeReturn(self, val):
r={'newReturnVal':val}
return r


def main():
trigger = Trigger()
return trigger.execute()

if __name__ == '__main__':
main()

If you compare it with the original python script, you will see the difference.



#original
if filter_context['resultCode']=='E-USERID-NOT-FOUND' or filter_context['resultCode']=='E-LOGINNAME-NOT-FOUND':
bRet = self.importAccount()

if bRet==True:
bRet = self.createToken()
if bRet==True:
return self.changeReturn('E-TOKEN-INACTIVE')
return 0

#new
if filter_context['resultCode']=='E-USERID-NOT-FOUND' or filter_context['resultCode']=='E-LOGINNAME-NOT-FOUND':
# bRet = self.importAccount()

# if bRet==True:
# bRet = self.createToken()
# if bRet==True:
# return self.changeReturn('E-TOKEN-INACTIVE')
return self.changeReturn('TRUE')


Monday 7 February 2011

Experiment of SMSLib on GPRS Modem in Ubuntu

I spent a lot of time on this GPRS 609 MODEM. Somehow this device I purchased on Ebay is faulty, or it isn't powerful enough in my area. Anyway it doesn't work very well. Basically, it can connect with "cu -l /dev/ttyUSB0", but sometimes it had no echo even I tried "AT+ATE1". The command AT+CMGS almost failed with error 33825, altough I did manage to send SMS twice. However, SMSLib SendMessage never succeeded. Interestingly enough, all other commands(listed below) were OK on the condition that the echo was fine.


Finally, I gave up the lame duck(I am afraid say so), as my friend offered me his Motorola V3 mobile phone which can be taken as a GPRS modem. Life became much easier with this mobile phone. Almost everything was straightforward.



With Ubuntu 10.10 32bit guest OS in Vmware Workstation,

dmesg shows this device is recognized as ttyACM0, no additional driver needed.



[ 233.820553] usb 2-1: new full speed USB device using uhci_hcd and address 3
[ 234.057913] usb 2-1: configuration #1 chosen from 2 choices
[ 234.284872] cdc_acm 2-1:1.0: ttyACM0: USB ACM device
[ 234.297306] usbcore: registered new interface driver cdc_acm
[ 234.297901] cdc_acm: v0.26:USB Abstract Control Model driver for USB modems and ISDN adapters


No hassle at all when using AT commands to send SMS. However, the tricks suggested by SMSLib Troubleshooting are applied during SMSLib tests. In details, the parameter -Dsmslib.serial.polling is used for no response exception. A symbolic link (sudo ln -s /dev/ttyACM0 /dev/ttyS20) is created for NoSuchPortException, but I haven't tried the alternative - gnu.io.rxtx.SerialPorts.



/*
* Register ports specified in the file "gnu.io.rxtx.properties"
* Key system properties:
* gnu.io.rxtx.SerialPorts
* gnu.io.rxtx.ParallelPorts
*
* The file gnu.io.rxtx.properties must reside in the java extension dir
*
* Example: /usr/local/java/jre/lib/ext/gnu.io.rxtx.properties
*
* The file contains the following key properties:
*
* gnu.io.rxtx.SerialPorts=/dev/ttyS0:/dev/ttyS1:
* gnu.io.rxtx.ParallelPorts=/dev/lp0:
*
*/

In addition, I chose the RXTX library distribution from CloudHopper's web site. Also I installed Sun Java, as I know the folder structure of Sun Java better than built-in Open JDK on Ubuntu. The command to run this jar is,


 /opt/java/bin/java -Dsmslib.serial.polling -Djava.library.path=/opt/java/bin -jar smslearn.jar


The modified java source code of SendMessage example.




// SendMessage.java - Sample application.
//
// This application shows you the basic procedure for sending messages.
// You will find how to send synchronous and asynchronous messages.
//
// For asynchronous dispatch, the example application sets a callback
// notification, to see what's happened with messages.

package com.deepnet.smslearn;

import org.smslib.AGateway;
import org.smslib.IOutboundMessageNotification;
import org.smslib.Library;
import org.smslib.OutboundMessage;
import org.smslib.Service;
import org.smslib.modem.SerialModemGateway;

public class SendMessage
{
public void doIt(String device, String speed, String phone, String message) throws Exception
{
OutboundNotification outboundNotification = new OutboundNotification();
System.out.println("Example: Send message from a serial gsm modem.");
System.out.println(Library.getLibraryDescription());
System.out.println("Version: " + Library.getLibraryVersion());
SerialModemGateway gateway = new SerialModemGateway("modem.ttyS20", device, Integer.parseInt(speed), "NoSuchPortException", "V3");
gateway.setInbound(true);
gateway.setOutbound(true);
// gateway.setSimPin("0000");
// Explicit SMSC address set is required for some modems.
// Below is for VODAFONE GREECE - be sure to set your own!
// gateway.setSmscNumber("+306942190000");
Service.getInstance().setOutboundMessageNotification(outboundNotification);
Service.getInstance().addGateway(gateway);
Service.getInstance().startService();
System.out.println();
System.out.println("Modem Information:");
System.out.println(" Manufacturer: " + gateway.getManufacturer());
System.out.println(" Model: " + gateway.getModel());
System.out.println(" Serial No: " + gateway.getSerialNo());
System.out.println(" SIM IMSI: " + gateway.getImsi());
System.out.println(" Signal Level: " + gateway.getSignalLevel() + " dBm");
System.out.println(" Battery Level: " + gateway.getBatteryLevel() + "%");
System.out.println();
// Send a message synchronously.
OutboundMessage msg = new OutboundMessage(phone, message);
Service.getInstance().sendMessage(msg);
System.out.println(msg);
// Or, send out a WAP SI message.
//OutboundWapSIMessage wapMsg = new OutboundWapSIMessage("+306974000000", new URL("http://www.smslib.org/"), "Visit SMSLib now!");
//Service.getInstance().sendMessage(wapMsg);
//System.out.println(wapMsg);
// You can also queue some asynchronous messages to see how the callbacks
// are called...
//msg = new OutboundMessage("+309999999999", "Wrong number!");
//srv.queueMessage(msg, gateway.getGatewayId());
//msg = new OutboundMessage("+308888888888", "Wrong number!");
//srv.queueMessage(msg, gateway.getGatewayId());
// System.out.println("Now Sleeping - Hit to terminate.");
// System.in.read();
Service.getInstance().stopService();
}

public class OutboundNotification implements IOutboundMessageNotification
{
public void process(AGateway gateway, OutboundMessage msg)
{
System.out.println("Outbound handler called from Gateway: " + gateway.getGatewayId());
System.out.println(msg);
}
}

public static void main(String args[])
{
if(args.length < 4)
{
System.out.println("Usage:smslearn device speed phone message");
return;
}

SendMessage app = new SendMessage();
try
{
app.doIt(args[0],args[1],args[2],args[3]);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}



Basic AT commands


you can try minicom instead.



$ cu -l /dev/ttyACM0
Connected.

//Phone activity status +CPAS. 0 Ready, 1 Unavailable,2 Unknown,3 Ringing,4 Call in progress,5 Asleep
at+cpas
+CPAS: 0

//Request manufacturer identification +CGMI
at+cgmi
+CGMI: "Motorola CE, Copyright 2004"

//Request model identification +CGMM
at+cgmm
+CGMM: "GSM900","GSM1800","GSM1900","GSM850","MODEL=V3"

//Request revision identification +CGMR
at+cgmr
+CGMR: "R374_G_0E.42.10R_A"

//Request product serial number identification +CGSN
at+cgsn
+CGSN: IMEI354759009930994

//AT+ATE1 : enable echo;

//Service Centre Address +CSCA
at+csca?
+CSCA: "+447973100973",145

//Report Mobile Equipment error +CMEE
AT+CMEE=1 //Report Mobile Equipment extend error. 0 = Disable, 1 = result code and use numeric values, 2 = result code and use verbose value

//Message Format +CMGF
AT+CMGF? // Query current format
AT+CMGF=1 // 0 = PDU mode (default), 1 = text mode

//Enter PIN +CPIN
at+cpin?
+CPIN: READY

//Send Message +CMGS
AT+CMGS="+31638740161"
Hello World !
+CMGS: 62
//Replace the above phone number with your own cell phone number. The modem will respond with: >
//You can now type the message text and send the message using the - key combination:
//After some seconds the modem will respond with the message ID of the message, indicating that the message was sent correctly:
//The message will arrive on the mobile phone shortly.


It is worth writing here how to exit cu: type '~' first, once you see computer name, then type '.'.




Reference



Send SMS using AT commands

USB Tri-band GPRS Modem / Cell Phone Radio (GSM 900/1800/1900Mhz)

Modify PL2303 PID & VID