สร้าง Certificates ด้วย OpenSSL แบบ “แป๊บเดียวเข้าใจ”

Tanakorn Luengpattanapadung
PRACTISTS
Published in
4 min readMar 1, 2020

ก่อนอื่นขอแจ้งก่อนว่า ผมไม่ได้โปรฯทางด้านนี้ และข้อมูลในบทความนี้ อาจจะไม่ได้ครบถ้วนหรือถูกต้องเสียทั้งหมด เพียงแต่ว่าทำแล้ว work !

เกริ่นที่มา … พอดีผมมี project ที่กำลังทำต้องใช้ cert ผ่าน TLS ก็เลยค้นหาวิธีการสร้าง certificates ( gen cert ) มาใช้ใน project ดังกล่าว ยิ่งอ่านยิ่ง งง
วิธีการ gen มีร้อยแปดพันเก้า และหลายมาตรฐาน ( ล่าสุดมีของค่าย cfssl ด้วย ซึ่งจะไม่ได้กล่าวในบทความนี้ ) แต่ผมเลือกใช้วิธี OpenSSL ซึ่งค่อนข้างมาตรฐานที่สุดละ
และเมื่อรวบรวมข้อมูลและทำเรียบร้อยแล้ว จึงสรุปวิธีทำเก็บเอาไว้ดู(เอง)

คิดว่าวิธีทำนี้น่าจะเป็นประโยชน์ จึงนำมาออกมาแชร์เป็นบทความนี้ โดยจะแยกเป็น 2 ส่วนคือ

  1. อธิบายไฟล์ Certificates แต่ละไฟล์คืออะไร มีหน้าที่ทำอะไร
  2. อธิบายวิธีการ gen certificates แต่ละชนิด ( ไฟล์ )

บทความนี้เน้น กระชับ สั้นๆ เข้าใจง่ายๆ แบบสรุป ไม่ได้เน้นรายละเอียดลงลึก เน้น “แป๊บเดียวเข้าใจ” ( หวังว่าอ่ะนะ )

1. รู้จ้กไฟล์ certificates ( .key .csr .crt .pem ) แต่ละชนิด

[ .Key ]
- .key จะเป็นไฟล์ที่ gen ขึ้นมาได้แบบดื้อๆ มีให้เลือกขนาด 1024 , 2048 , 4096 ( ยิ่งมากยิ่งปลอดภัย )
- .key มักนิยมใช้เป็นค่า private key
- .key จะต้องเก็บไว้ในที่ลับ , ไม่ share
- .key อาจจะอยู่ใน format ของ .pem ก็ได้ ( base64-encoded )
- เราสามารถเข้ารหัส ( ใส่ pass ) ให้ .key ได้ด้วย ( encryption key )
- เราไม่จำเป็นต้องเข้ารหัส ( ใส่ pass ) ให้ .key ก็ได้ ( decryption key )
- .key ไม่มีการกำหนด expire

[ .CSR ]
- .csr เป็นไฟล์ระบุตัวตนของเรา เพื่อใช้ในการ request ไปยัง server
- .csr เราจะต้องระบุ Country , City , Address , Email , อื่นๆ ทุกครั้งในการ gen ไฟล์ .csr
- .csr อาจจะอยู่ใน format ของ .pem ก็ได้ ( base64-encoded )
- .csr ไม่มีการกำหนด expire

[ .CRT ]
- .crt คือไฟล์ที่รวมเอาไฟล์ key + csr ( หรือ .crt = .key + .csr นั่นเอง )
- .crt มักนิยมใช้เป็นค่า public key
- .crt มักจะเอาไว้ share กันใน communicate ( public )
- .crt อาจจะอยู่ใน format ของ .pem ก็ได้ ( base64-encoded )
- .crt ต้องกำหนด expire เสมอ

[ .PEM ]
- คำสั่ง openssl จะให้ผลลัพธ์ที่ออกมาเป็น PEM format เสมอ
- ดังนั้นตอนที่เราใช้คำสั่ง openssl เราเลือกได้ว่าจะให้ output เป็นนามสกุล .crt หรือ .pem เลยก็ได้ เพราะภายในมีค่าเหมือนกันเด๊ะ , ชัวร์
- แต่แนะนำให้ใช้นามสกุล .key .csr .crt ดีกว่า จะเข้าใจได้ง่ายว่าคือไฟล์อะไร ( ถ้าใช้ .pem แล้วบางทีไม่รู้ว่าคือไฟล์สำหรับใช้ทำอะไร ) , ชัวร์
- .pem คือ การ encode ให้อยู่ในรูปแบบของ base64
- .pem นิยมใช้กันกว้างขวาง เพราะ transport ได้ง่าย
- .pem อาจจะบรรจุได้ทั้ง public key หรือ private key หรือ root certificates หรืออาจจะบรรจุทั้งหมดรวมกันก็ได้
- PEM file by allusion to the old Privacy-Enhanced Mail standards which preceded S/MIME as a mail security standard.
- เราสามารถดูไฟล์ .pem ภายในได้ ใช้คำสั่ง
$ cat cert.pem
— — -BEGIN <whatever> — — -
ตามด้วย base64-encoded data
— — -END <whatever> — —
- วิธี decode ไฟล์ .pem ใช้คำสั่ง
$ openssl x509 -in cert.pem -text -noout
ก็จะได้ข้อมูล Certificate เป็นตัวอักษรที่อ่านออกว่าใครออกให้ ใครขอ ที่อยู่ผู้ขอ ฯลฯ

[ .der ]
- .der จะเป็น binary
- .der นิยมใช้ในแอพ java
- .der สามารถแปลงได้จากไฟล์ .crt หรือ .pem ทั่วไป
- เราสามารถแปลงไฟล์ .der (binary) กลับมาเป็น .pem (base64) ได้เหมือนเดิม

[ .pkcs12 .pfx .p12 ]
- เป็นมาตรฐาน ssl ของ Microsoft Windows
- ไม่ขอกล่าวในที่นี้ ( ไม่นิยม )

2. สร้างไฟล์ certificates ( key, csr, crt, pem, der ) จาก OpenSSL

[ สร้าง private key (key) ]
$ openssl genrsa 2048 > host.key
$ cat host.key

[ Encrypt a Private Key ]
$ openssl rsa -des3 -in host.key -out host_enc.key
- ใส่ pass phrase 2 ครั้งตอน encrypt ( อย่าลืม pass phrase เด็ดขาด )
$ cat host_enc.key

[ Decrypt a Private Key ]
$ openssl rsa -in host_enc.key -out host.key
- ใส่ pass phrase ตอน decrypt ( ถ้าลืม pass phrase จะ decrypt ไม่ได้เด้อ )
$ cat host.key

[ สร้าง Certificate Signing Requests (csr) ]
$ openssl genrsa 2048 > host.key
$ openssl req -key host.key -new -out request.csr
- วิธีนี้จะถามข้อมูลของ CSR ( Address , email , อื่นๆ ) เพราะไม่มีข้อมูลจาก crt ให้ดึง
$ cat request.csr

[ สร้าง CSR มาจาก key , crt ที่มี ( csr = key + crt ) ]
$ openssl x509 -in host.crt -signkey host.key -x509toreq -out request.csr
- วิธีนี้จะไม่ถูกถามข้อมูลของ CSR ( Address , email , อื่นๆ ) เพราะจะดึงจาก crt มาเลย
$ request.csr

[ ดู CSR (csr) Entries ]
$ openssl req -text -noout -verify -in request.csr

[ สร้าง public key (crt) จาก .key ที่มี ]
$ openssl genrsa 2048 > host.key
$ chmod 400 host.key
$ openssl req -new -x509 -nodes -sha256 -days 365 -key host.key -out host.crt
- วิธีนี้จะถามข้อมูลของ CSR ( Address , email , อื่นๆ ) เพราะไม่มีข้อมูลจาก csr ให้ดึง
$ cat host.crt

[ สร้าง public key (crt) จาก .key และ .csr ที่มี ( crt = key + csr ) ]
$ openssl x509 -signkey host.key -in request.csr -req -days 365 -out host.crt
- วิธีนี้จะไม่ถูกถามข้อมูลของ CSR ( Address , email , อื่นๆ ) เพราะจะดึงจาก csr มาเลย
$ cat host.crt

[ ดู Certificate (crt) Entries ]
$ openssl x509 -text -noout -in host.crt

[ เช็คดูว่าไฟล์ Private Key นั้น Match กับ Cert และ CSR หรือไม่ ]
$ openssl rsa -noout -modulus -in host.key | openssl md5
$ openssl x509 -noout -modulus -in host.crt | openssl md5
$ openssl req -noout -modulus -in request.csr | openssl md5

[ แปลง key, crt ไปเป็น pem ]
$ openssl x509 -in host.crt -out host.pem -outform PEM
$ cat host.pem
$ cat host.crt
- ทั้ง 2 ไฟล์ดันได้ค่า host.pem และ host.crt เหมือนกันเด๊ะ , แสดงว่าค่า .crt ที่ openssl gen มานั้นอยู่ใน format ของ PEM (base64-encoded) อยู่แล้ว
- แสดงว่าตอน gen ค่าต่างๆจากคำสั่ง openssl นั้นเราสามารถเลือกได้ว่าจะใช้นามสกุล .crt หรือ .pem ก็ได้

[ สรุปเรื่อง PEM ]
- คำสั่ง openssl จะให้ผลลัพธ์ที่ออกมาเป็น PEM format เสมอ
- ดังนั้นตอนที่เราใช้คำสั่ง openssl เราเลือกได้ว่าจะให้ output เป็นนามสกุล .crt หรือ .pem เลยก็ได้ เพราะภายในมีค่าเหมือนกัน
- แต่แนะนำให้ใช้นามสกุล .key .csr .crt ดีกว่า จะเข้าใจได้ง่ายว่าคือไฟล์อะไร ( ถ้าใช้ .pem แล้วบางทีไม่รู้ว่าคือไฟล์สำหรับใช้ทำอะไร )
- .pem คือ การ encode ให้อยู่ในรูปแบบของ base64
- .pem นิยมใช้กันกว้างขวาง เพราะ transport ได้ง่าย
- .pem อาจจะบรรจุได้ทั้ง public key หรือ private key หรือ root certificates หรืออาจจะบรรจุทั้งหมดรวมกันก็ได้

— — — — — — — ด้านล่างนี้ไม่ค่อยสำคัญ ( ไม่รู้ก็ได้ ) — — — — —

[ สร้าง key, crt ไปเป็นไฟล์แบบ pem เลย ]
- วิธีที่ 1 คือระบุ pass phrase
$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
$ cat key.pem
$ cat cert.pem
- วิธีที่ 2 คือไม่ระบุ pass phrase โดยใส่พารามิเตอร์ -nodes ( no DES )
$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
$ cat key.pem
$ cat cert.pem

[ แปลง PEM ไปเป็น DER ]
$ openssl x509 -in host.crt -outform der -out host.der
$ cat host.der
จะเห็นเป็น binary อ่านไม่ออก

[ แปลง DER กลับมาเป็น PEM ]
$ openssl x509 -inform der -in host.der -out host.crt
$ cat host.crt

หลังจากได้ไฟล์มาแล้ว เราก็เอาไฟล์ certificates เหล่านี้ไปใช้ใน app เราได้เลย หรือใช้ในพวก web server ก็ได้

ทดสอบแล้วทุกคำสั่งถูกต้อง แต่ถ้าหากผิดพลาด ขออภัยเด้อ

บทความหน้า (อาจจะ) เอาวิธีทำแบบ Cloudflare SSL ( cfssl ) มาแชร์ลงบทความครับ

20200301://TNK.Theory

--

--

Tanakorn Luengpattanapadung
PRACTISTS

DevOps สไตล์ TNK ติดตามกันได้ที่เวบ www.tanakorn.com เด้อ