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

NAT [STUN/TURN/ICE]

มาขอจด note กันลืม เรื่อง NAT traversal หน่อย [How to deal with final users / End-to-end tunnel ]

1. Nat มี 4 ประเภท แบบ fix/no fix port, fix/no fix IP ถ้าเป็นแบบที่ fix ทั้งหมด จะเรียกว่า symmetric nat ซึ่งจัดการยากที่สุด

1.1 Full cone => เหมือนกับทำ dynamic port forward เวลาส่งออก iAddr:iPort จะ map กับ eAddr:ePort แล้วส่งไปหา hAddr:hPort จากนั้น hAny:hAny สามารถส่งเข้ามาได้ iAddr:iPort ได้ แม้ว่าจะไม่เคยได้รับการติดต่อมาก่อน

1.2 Restrict cone => iAddr:iPort ส่ง packet ออกไปยังเครื่องใด ๆ ด้วย eAddr:ePort เช่น ส่งไปหา hAddr:hPort แล้ว hAddr:hAny สามารถส่งเข้ามาได้ iAddr:iPort ได้
( เวลา internal ส่งออก ไม่ว่าปลายทางเป็นเครื่องเครื่องไหน ใช้ eAddr:ePort แต่เครื่องนอก hAddr:hAny สามารถส่งกลับมาได้ ก็ต่อเมื่อเคยได้รับ packet จาก internal ก่อน)

1.3 Port Restrict cone => iAddr:iPort ส่ง packet ออกไปยังเครื่องใด ๆ ด้วย eAddr:ePort เช่น ส่งไปหา hAddr:hPort แล้ว hAddr:hPort สามารถส่งเข้ามาได้ iAddr:iPort ได้
( เวลา internal ส่งออก ไม่ว่าปลายทางเป็นเครื่องเครื่องไหน ใช้ eAddr:ePort แต่เครื่องนอก hAddr:hPort สามารถส่งกลับมาได้ ก็ต่อเมื่อเคยได้รับ packet จาก internal ก่อน)

1.4 Symmetric cone => iAddr:iPort ส่ง packet ออกไปยังเครื่องนอก ด้วยการ map port ที่ต่างกัน ไม่เหมือน 3 อันที่กล่าวมา คือ ไม่ว่าปลายทางเครื่องไหน ใช้ eAddr:ePort เสมอ แต่แบบ Symmetric จะ map port ใหม่ สำหรับ เครื่องปลายใหม่ ส่วนเวลาตอบกลับ hAddr:hPort สามารถส่งกลับมาได้ ก็ต่อเมื่อเคยได้รับ packet จาก internal ก่อนเท่านั้น


2. ใช้ application layer gateway / session border controller มาช่วยจัดการ (อ่านแล้วยัง งง ๆ ว่าตกลงมันต่างกันยังไงวะ) แต่ มัน deploy ยาก และ ไม่ scalability + more delays

3. Stun เข้ามาแก้ปัญหาเรื่อง nat แบบที่ไม่ใช่ symmetric โดยการใช้ เทคนิค UDP hole punching (จะใช้ tcp ก็ได้ แต่ไม่ค่อยนิยม และ ทำโอกาสสำเร็จมีน้อยกว่า) คือ ให้ client หลัง nat คุยกับ stun server ก่อน เป็นการเจาะรู เพื่อให้ ผู้ติดต่ออีกฝ่าย สามารถเข้าถึง client คนนี้ ผ่านทาง รู ที่เจาะไว้ โดยอาศัยข้อมูลจาก stun server กรณีนี้ ถ้าเป็น full cone ก็ติดต่อได้เลย หลังจาก เจาะรูแล้ว แต่ถ้าเป็น แบบ (port) restrict cone พอเจารูเสร็จ ทั้งคู่ จะต้องติดต่ออีกฝ่าย คนที่รับข้อมูลก่อน NAT จะ drop packet ทิ้ง เพราะถือว่าไม่เคยได้รับการติดต่อ ส่วนอีกคนที่ได้รับข้อมูลทีหลัง NAT จะปล่อยผ่าน เพราะถือว่า เคยส่งไปหาก่อน ทีนี้ก็จะสามารถติดต่อกันได้

4. กรณีที่อยู่หลัง nat ที่เป็น symmetric ทั้งคู่ ก็คล้าย ๆ กัน แต่ relay server จะต้อง forward packet ทุกอย่างไปให้ผู้ที่ติดต่อทั้ง 2 ฝ่าย (เพราะถ้าเปลี่ยน destination ตัว nat มันจะ map port ใหม่ เราเลยต้องมี relay ไว้ส่งต่อ packet) เราเรียกว่า TURN นั่นเอง = Stun + Relay extentions

5. ICE = STUN + TURNS , ICE เป็น protocol ที่คอยมาตรวจสอบว่า จำเป็นต้องใช้ Turn ด้วยหรือเปล่า แล้วก็จัดตั้งการสื่อสารขึ้นมา

แต่สุดท้ายหลักการก็เหมือนกัน ก็คือเจาะรู เข้า nat ไว้ก่อน แล้วก็ส่ง หมายเลข port ที่ใช้ในการติดต่อ ถ้ามัน restrict ทั้ง IP และ port เมื่อส่งหากันครั้งแรก package จะโดน drop ที่ฝั่งผู้รับที่ได้รับข้อมูลก่อน (เพราะมัน restrict) แต่พอ ฟังผู้รับส่งมาให้ผู้ส่ง คราวนี้จะไม่ drop ที่ฝ่ายส่งครั้งแรก เนื่องจาก ฝ่ายส่งได้เคยส่งข้อมูลหาไปแล้ว

อธิบายไว้ละเอียดที่นี่

วันอังคารที่ 6 ธันวาคม พ.ศ. 2554

Keystore for TLS/SSL #3

Create ca.pem/ca_pk.pem for HTTPS

openssl req -x509 -new -config openssl.cfg -days 365 -out ./new/ca.pem -keyout ./new/ca_pk.pem
Pass: 123456

ca.pem
ca_pk.pem

========
create keystore:
keytool -import -alias certificatekey -file ca.pem -keystore catruststore.jks

========
Convert for Apache
openssl rsa -in ./new/ca_pk.pem -out ./new/ca_pk.key
Got ca_pk.key (key file for apache)

openssl x509 -x509toreq -days 365 -in ./new/ca.pem -signkey ./new/ca_pk.key -out ./new/ca.req
Got ca.req (For sign certificate)

openssl x509 -in ./new/ca.req -out ./new/ca.cert -req -signkey ./new/ca_pk.key -days 365
Got ca.cert (certificate for apache)

================
create keystore:
keytool -import -alias certificatekey -file ca.cert -keystore catruststore-cert.jks

================
Create cert for browser
There are 3 choices:

1. Directly load from browser.

2. openssl x509 -inform PEM -in ./new/ca.pem -outform DER -out ./new/ca.cer

3. openssl x509 -inform PEM -in ./new/ca.cert -outform DER -out ./new/ca1.cer

วันพฤหัสบดีที่ 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/