วันพฤหัสบดีที่ 1 ธันวาคม พ.ศ. 2554

Birthday paradox

หากคุณไปงานเลี้ยง แล้วเดินถามวันเกิด (เอาเฉพาะวันกับเดือน) ของคนที่คุณคุยด้วย คุณจะพบว่าใน 23 คนที่คุณถามวันเกิด จะมีโอกาสสูงที่คนที่เกิดวันเดียวกันอยู่ 1 คน

ใน 1 ปีหนึ่งมีตั้ง 365 วัน แต่ถามแค่ 23 คน กลับเจอคนที่เกิดวันเดียวกันคนเดียว

สรุปตามหลักสถิติ
sample 2^n จะมีโอกาสเกิด collision ที่ 2^n/2

365 = 2^8.51 => collision ที่ 2^8.51/2 = 19.104 ใกล้เคียงกับความจริงคือ 23 มากเลย

เพื่อป้องการปัญหาการ collision ของ hash function ควรจะ hash ที่ 160 bits

Why not Client Auth? on TLS/SSL

- สร้าง TLS/SSL โดยใช้ JSSE ซึ่งใช้ public/private (keystore/truststore) ในการเข้ารหัส โดยกำหนดค่าผ่าน SSLContext

- Server อ่านค่า private key ของตนเอง แล้ว เปิด port รอไว้ เมื่อ client จะติดต่อ ก็ไป load public key ของ server มา แล้วก็ connect server โดยใช้ TLS/SSL ไร้ปัญหา สำหรับ server เพราะเป็นตัวจริงแน่ ๆ ถ้า public key ของ server เป็นของจริง

- ปัญหาคือ หาก server ต้องการ Authen Client ด้วย ถ้ามีแค่ 2 เครื่องแบบ client-server ก็ง่ายนิดเดียว ซึ่งเราสามารถสั่ง Client Auth ได้ผ่านคำสั่ง sslserversocket.setNeedClientAuth(true); โดยการกำหนด public key ของ client และ private key ของ server ที่ server ก่อนที่จะเปิด port รอ และ client ก็ set ในแบบเดียวกัน

- แต่ถ้าในระบบ P2P/DHT/Chord Server ไม่สามารถทราบได้ว่า client มีใครจะมาติดต่อบ้าง และ server ต้องเปิด port รอ โดยที่ยังไม่ทราบ public key ของ client และ ปัญหาใหญ่คือ ทุก ๆ เครื่องเป็น ทั้ง client/server ในตัว

- วิธีแก้ปัญหาในตอนนี้คือ ให้ verify เฉพาะ server อย่างเดียว เพราะ server เปิด port รอไว้ โดยใช้ private key ของตัวเอง client ก็ verify server โดยใช้ public key ของ server (อาจจะไป download จาก CA ที่ไหนสักแห่งที่ไว้ใจได้) ส่วนการ verify client ให้ใช้วิธีการ verify แบบอื่นที่ง่ายกว่า เช่น HTTP Digest เนื่องจาก วิธีนี้ มี overhead น้อย และ ปลอดภัย เนื่องจากมันถูกห่อหุ้มด้วย TLS/SSL อยู่ด้วย

- แต่การใช้ HTTP Digest มันก็ต้องมี pre-shared key ซึ่งส่งกันลำบาก ถ้ามองในแง่การส่งข้อมูล ที่ได้ทำการ implement แบบ stateless เวลา P1 -> P2, P2 ถูก verify แต่ P1 ไม่ถูก verify แต่เมื่อ P2 ตอบกลับ P1 ถูก verify แต่ P2 ไม่ถูก verify สุดท้ายแล้วก็ได้ verify ทั้ง 2 ฝ่ายอยู่ดี (เหลือปัญหาอยู่อย่างเดียวคือ คนที่เริ่ม connection อาจจะไม่ใช่คนนั้นจริง ๆ แต่ก็ตรวจสอบได้ภายหลัง)

CA Keystore/Truststore

Set up own Certificate Authority (need openssl for CA)

1. download openSSL from http://www.slproweb.com/products/Win32OpenSSL.html


2. สร้าง private key/certificate โดยคำสั่ง

C:\OpenSSL-Win32\bin> openssl req -x509 -new -config openssl.cfg -days 365 -out ./new/ca.pem -keyout ./new/ca_pk.pem
Pass: 123456

จากคำสั่งนี้จะได้ certificate ca.pem กับ private key ca_pk.pem


3. นำ certificate มาสร้าง CA truststore โดยคำสั่ง

C:\OpenSSL-Win32\bin> keytool -import -alias certificatekey -file ca.pem -keystore catruststore.jks



Create Keystore and Truststore for a user

1. สร้าง keystore

C:\OpenSSL-Win32\bin\new> keytool -genkey -alias certificatekey -keypass 123456 -keystore CertName.jks -storepass 123456 -validity 365

หรือ ถ้าขี้เกียจพิมพ์ เอาแบบรวดเร็วก็
C:\OpenSSL-Win32\bin\new> keytool -genkey -alias certificatekey -dname "cn=147.127.240.90, ou=IRIT, o=Sun, c=FR" -keypass 123456 -keystore CertName.jks -storepass 123456 -validity 365

ต้องใส่ค่าต่าง ๆ ให้ตรงกับใน ca.pem ถ้าใส่ไม่ตรงต้องไปแก้ openssl.cfg ดังนี้

dir = ./PEM/demoCA # Where everything is kept
policy = policy_anything # otherwise, has to put exactly the same information


2. สร้าง certificate ที่ request การ sign

C:\OpenSSL-Win32\bin\new> keytool -certreq -alias certificatekey -file CertName_csr.pem -keypass 123456 -keystore CertName.jks -storepass 123456

จะได้ output คือ CertName_csr.pem


3. sign CSR (certificate)

C:\OpenSSL-Win32\bin> openssl ca -config openssl.cfg -days 365 -in ./new/CertName_csr.pem -out ./new/CertName.pem -cert ./new/ca.pem -keyfile ./new/ca_pk.pem


4. แปลงไฟล์ในรูปแบบ PEM format
openssl x509 -in ./new/CertName.pem -out ./new/CertName.pem -outform PEM


5. เอา certificate มาต่อกัน
copy CertName.pem + X509CA\ca\new_ca.pem CertName.chain


6. update keystore (private key)
keytool -import -file CertName.chain -keypass 123456 -keystore CertName.jks -storepass 123456


7. สร้าง truststore (public key)
C:\OpenSSL-Win32\bin\new>keytool -import -alias certificatekey -file CertName.chain -keystore truststore.jks


8. ดูผล โดยการ
keytool -list -v -keystore CertName.jks => จะมี Entry type: PrivateKeyEntry และ Entry type: trustedCertEntry
keytool -list -v -keystore truststore.jks => จะมี Entry type: trustedCertEntry อย่างเดียว


Reference links:
==== CA ======
http://fusesource.com/docs/esb/4.3/amq_security/i305191.html
http://fusesource.com/docs/esb/4.3/amq_security/i382664.html
http://www.linuxquestions.org/questions/linux-networking-3/trouble-generating-ssl-certificates-116973/
http://www.g-loaded.eu/2005/11/10/be-your-own-ca/
http://www.tldp.org/HOWTO/SSL-Certificates-HOWTO/index.html

Keytool: http://www.techbrainwave.com/?p=953

Dynamic keystore: http://jcalcote.wordpress.com/2010/06/22/managing-a-dynamic-java-trust-store/

วันพุธที่ 30 พฤศจิกายน พ.ศ. 2554

Java TLS/SSL #2

ตัวอย่าง code JSSE


ตัวอย่างในการ Run
Server:
D:\java\TLS>java ClassFileServer 80 . TLS true

Client:
D:\java\TLS>java SSLSocketClientWithClientAuth 147.127.xxx.90 80 /index.html


Modify to support Client authentication:

ClassFileServer:
ks.load(new FileInputStream("keystore-147.127.xxx.90"), passphrase);
kmf.init(ks, passphrase);
KeyStore ksTrust = KeyStore.getInstance("JKS");
ksTrust.load(new FileInputStream("truststore-147.127.xxx.91"), null);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ksTrust);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
===========================

SSLSocketClientWithClientAuth:
ks.load(new FileInputStream("keystore-147.127.xxx.91"), passphrase);
kmf.init(ks, passphrase);
KeyStore ksTrust = KeyStore.getInstance("JKS");
ksTrust.load(new FileInputStream("truststore-147.127.xxx.90"), null);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ksTrust);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

===========================
Just swap truststore and keystore for each other.



Trust store เหมือน public key แต่ทำไมจึงมี password?
Ans:
NOTE: Trust stores often have passwords but for validation of credentials the password is not needed because public key certificates are publicly accessible in any key or trust store. If you supply a password, the KeyStore.load method will use it when loading the store but only to validate the integrity of non-public information during the load – never during actual use of public key certificates in the store. Thus, you may always pass null in the second argument to KeyStore.load. If you do so, only public information will be loaded from the store.

วันพฤหัสบดีที่ 24 พฤศจิกายน พ.ศ. 2554

P2PNS vs RELOAD

Interested P2PSIP security solutions

- P2PNS: เป็น p2p-sip overlay ที่ใช้ การ hash(public-key) ในการ create ID เพื่อป้องการพวก Sybil attack สามารถ config DHT algorithm ใช้งานผ่าน OpenSER ที่ติดต่อกับ overlay network ที่ได้จาก OverSim (ที่ Run ผ่าน Omnet++ อีกที)

default DHT algorithm คือ Kademlia

P2PNS ออกแบบมาเพื่อให้ peer เก็บค่าของ SIP AoR ที่ Peer เอง และ retrieve ผ่าน DHT algorithm แทนที่จะต้องไป Query ผ่าน Name Server (เลยตั้งชื่อว่า P2PNS) แต่ไม่ได้บอกรายละเอียดชัดเจน ของ security เกี่ยวกับ การรับส่งข้อมูล



- RELOAD: คล้าย ๆ กับ P2PNS แต่ กำหนดเงื่อนไข รายละเอียดการส่งข้อมูลเยอะกว่า มี security layer บังคับใช้ TLS/SSL รวมกับ PKI, มี Certificate server ไว้ตรวจสอบ กำหนดทุกการส่งต้องผ่าน TLS/SSL

default DHT algorithm คือ chord




วันศุกร์ที่ 21 ตุลาคม พ.ศ. 2554

SSLContext

วิธีการกำหนดให้ใช้ Java SSL/TLS ก่อนจะสร้าง SSLSocket ขึ้นมามีหลายวิธี

1. กำหนดผ่าน SystemProperty โดย ทาง commandline

-Djavax.net.ssl.keyStore=keystoreSrv

หรือ set ใน program
System.setProperty("javax.net.ssl.keyStore", "keystoreSrv");


2. กำหนดใน JAVA_HOME/lib/security/jssecacerts หรือ JAVA_HOME/lib/security/cacerts


สร้าง SSLSocket ได้ดังนี้
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();

หากโชคดี connect ได้พอดีกับ ตอนที่ GetDefault ของ SSLContext ที่อ่านข้อมูลจาก SystemProperty ได้ทัน ก็ Run ได้ผ่านไม่มีปัญหา ซึ่งกรณีที่ทำ 1 connection จะไม่เจอปัญหานี้ (เหมือนกับตัวอย่าง code ที่เคยเขียนไว้)

แต่วิธีที่กล่าวมานั้น ไม่สามารถใช้ได้ในกรณีที่ทำ multiple TLS/SSL connections รวมกับ การ create Multi-Thread ไว้รอรับ connections เพราะเวลาสั่ง getDefault() ของ SSLContext เพื่อสร้าง SSLSocket หรือ SSLServerSocket แล้ว มักจะเจอ error เช่น

PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

หรืออาจจะเป็น error อื่น ๆ เช่น certificate error, หา certificate ไม่เจอ ฯลฯ

ทั้ง ๆ ที่เราก็ set ค่า keyStore กับ trustStore ผ่าน SystemProperty ไปแล้ว

วิธีแก้ไขคือ
ให้สร้าง SSLContext ขึ้นมาเอง ดังนี้

public SSLContext createSSLContext(int type) {
//------------
char[] password;
SSLContext ctx = null;
InputStream in = null;
KeyStore ks = null;
KeyManagerFactory kmf = null;
TrustManagerFactory tmf = null;

try {

kmf = KeyManagerFactory.getInstance("SunX509", "SunJSSE");
tmf = TrustManagerFactory.getInstance("PKIX", "SunJSSE");

if (type == KEYSTORE) { // for authen incoming connection
ks = KeyStore.getInstance(KeyStore.getDefaultType());
password = "123456".toCharArray();
in = (new FileInputStream("keystoreSrv"));
ks.load(in, password);
kmf.init(ks, password);
} else { // for connect another to authen
ks = KeyStore.getInstance(KeyStore.getDefaultType());
//password = "123456".toCharArray();
in = (new FileInputStream("truststoreCli"));
ks.load(in, null);
kmf.init(ks, null);
}

in.close();
tmf.init(ks);
ctx = SSLContext.getInstance("TLS");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
} catch (Exception e) {
e.printStackTrace();
}
return ctx;
}

จากนั้นเราก็นำ ctx นี่แหละไปสร้าง SSLSocket หรือ SSLServerSocket ดังนี้

SSLServerSocketFactory sslserversocketfactory = ctx.getServerSocketFactory();

SSLSocketFactory sslsocketfactory = ctx.getSocketFactory();

เท่านี้ก็จะไม่เจอ Error ดังกล่าวแล้วครับ

วันอังคารที่ 18 ตุลาคม พ.ศ. 2554

Digital Home Networking Book

Some parts of my researches here are appeared in the book now. :-)

http://www.iste.co.uk/index.php?f=x&ACTION=View&id=442