ทำระบบเซ็นเอกสาร PDF ด้วยลายเซ็นดิจิทัลในองค์กรแบบง่าย ๆ
14 มีนาคม 2022
เชื่อว่าทุกคนเคยเซ็นลายมือชื่อลงในเอกสาร ไม่ว่าจะเป็นการเปิดบัญชีธนาคาร หรือลายเซ็นประกอบกับข้อความสำเนาถูกต้องให้กับสำเนาเอกสารต่าง ๆ สำหรับคนที่ไม่ได้มีหน้าที่ ที่จะต้องเซ็นเอกสารบ่อยนักก็คงไม่ได้เป็นปัญหาอะไร แต่ในองค์กรหรือหน่วยงานราชการ ที่มีเอกสารหนา ๆ เป็นปึก ๆ ทุก ๆ เดือน ที่จะต้องลงลายมือชื่อทุกหน้า ก็เป็นอะไรที่ไม่มีใครอยากเสียเวลาทำ
คำถามคือ จะดีแค่ไหน ถ้าหาก เราสามารถที่จะลงลายมือชื่อในเอกสาร แบบอิเล็กทรอนิกส์ภายในองค์กรได้? โดยมีคุณสมบัติดังนี้
- สามารถยืนยันตัวตนผู้ลงลายมือชื่อได้ว่าเป็นตัวจริง (ไม่ใช่เอกสารที่ใครก็ได้เอาภาพลายเซ็นผู้บริหารไปแปะ โดยผู้บริหารหรือเจ้าของลายเซ็นอาจไม่ยินยอม)
- ใช้เวลาในการลงลายมือชื่อเอกสารจำนวนมากภายในเวลาไม่นาน
- สามารถใช้ระบบอัตโนมัติในการตรวจสอบลายเซ็นในเอกสารจำนวนมาก ๆ ได้ในเวลาหลักวินาที
- เสียค่าใช้จ่ายในการบริหารจัดการน้อย (ไม่ต้องซื้อซอฟต์แวร์ราคาแพง ๆ มาใช้) และไม่เสียเงินตามจำนวนผู้เซ็นเอกสารที่มากขึ้น
- ใช้งานง่าย หลังจากการติดตั้งระบบต่าง ๆ และทำความเข้าใจเรียบร้อยแล้ว
หลายคนอาจจะยังไม่รู้ว่าประเทศไทย เรามี พ.ร.บ. ว่าด้วยธุรกรรมทางอิเล็กทรอนิกส์ พ.ศ. 2544 ที่แก้ไขเพิ่มเติม (ฉบับที่ 3) พ.ศ. 2562 สรุปเป็นภาษาเข้าใจง่าย ๆ ลายมือชื่ออิเล็กทรอนิกส์ “ตามกฏหมาย” แบ่งออกเป็น 2 ประเภทหลัก ๆ คือ
- มาตรา 9: ลายมือชื่อแบบ (ง่าย ๆ) ทั่วไป อันนี้รวมถึง การพิมพ์ชื่อตัวเองลงไปท้ายอีเมลหรือเอกสาร, การกดปุ่ม “ยอมรับ”, การติ๊กถูกลงไปกล่อง “ยินยอม…” หรือการ ใส่รูปลายเซ็นลงไปในเอกสาร พวกนี้ก็เสมือนกับว่า เราลงลายเซ็นไปแล้ว!
- มาตรา 26: ลายเซ็นดิจิทัลแบบที่ “เชื่อถือได้” โดยสามารถยืนยันได้ด้วยวิธีการทางการเข้ารหัส ของคอมพิวเตอร์ ด้วยเทคนิคอย่างการใช้ Public Key Infrastructure (PKI) มีเรื่องเกี่ยวกับกุญแจการเข้ารหัสหรือใบรับรองเข้ามาเกี่ยวข้อง
ในบทความนี้ขอไม่พูดถึง PKI เชิงลึกมากเกินเดี๋ยวจะง่วงนอน ขอนิดเดียวพอ.. PKI ในเรื่องของลายเซ็นดิจิทัล คือ ชื่อเรียกรวม ๆ ของกระบวนการที่ใช้ในการบริหารจัดการกุญแจ และใบรับรองต่าง ๆ ที่ให้ผู้ใช้งานแต่ละคนเอาไว้ (1) เซ็นเอกสารจากเจ้าของลายเซ็นตัวจริง (2) ยืนยันได้ว่าเอกสาร ที่มีคนเซ็นนั้นเป็นลายเซ็นของคน ๆ นั้นจริง ๆ
สิ่งที่อยากให้ผู้อ่านได้กลับไปจากการอ่านบทความนี้คือมี คู่มือหรือ Playbook ที่สามารถนำไป Copy & Paste เพื่อทำระบบตัวอย่างแบบใช้ได้จริง (Proof of Concept) เอาไปลองใช้ในองค์กรสำหรับการทำลายเซ็นดิจิทัลให้เอกสารประเภท PDF ที่น่าจะใช้ส่งหากันแล้วติดลายเซ็นมากที่สุด
มาตรฐานลายเซ็นดิจิทัลใน PDF (PAdES)
ก่อนจะลงวิธีทำ มาทำความคุ้น ๆ คำศัพท์กันก่อนเล็กน้อยว่า ลายเซ็นดิจิทัลด้วยซอฟต์แวร์ ทำได้หลายแบบ ไม่ว่าจะเป็น PGP หรือใช้ กุญแจลับ (Private Key) สร้างลายเซ็นไฟล์ด้วยอัลกอริทึมอย่าง RSA (ใช้โปรแกรม openssl ก็ทำได้) แต่ว่า เหตุผลที่เราน่าจะมาสนใจวิธีการตามมาตรฐาน PAdES ในบทความนี้มากกว่า PGP หรือ RSA ทั่วไปเพราะว่า
- เป็นมาตรฐานสำหรับคนทั่วไปใช้ได้ง่าย ตัว PAdES (PDF Advanced Electronic Signatures) นั้นออกแบบมามีข้อดีเด่น ๆ ว่า นอกจากให้คนไอที (Geek) ใช้แล้วนั้น ยังทำให้คนที่ไม่ได้เข้าใจด้านเทคนิคมากก็สามารถใช้ได้ ผ่านโปรแกรมเปิดเอกสารยอดนิยมอย่าง Adobe Reader สำหรับไฟล์ PDF ได้อีกด้วย ตอนจะเซ็นหรือจะตรวจกดคลิก ๆ ไม่กี่ทีก็เสร็จ
- รวมถึงไม่มีการสร้างไฟล์ใด ๆ แยกออกจากไฟล์เอกสารเดิม รวมเป็นไฟล์ .pdf เดียวกันได้เลย
นอกจากลายเซ็นดิจิทัลที่ถูกรวมไปในเอกสาร PDF ของผู้ลงลายมือชื่อแล้ว (ไม่ได้แยกออกมาเป็นไฟล์อื่นเหมือนบางมาตรฐาน) ยังมีการเก็บข้อมูลอื่น ๆ ในลายเซ็นรวมไปกับเอกสาร PDF อีก ซึ่งการเซ็นลายเซ็นในกระดาษอาจไม่ได้มีด้วยอย่าง เช่น วัน-เวลาที่เซ็นเอกสาร รวมถึงมีความสามารถในการลงลายเซ็นซ้อน ๆ กันหลายครั้ง (จากคนเดียวกัน หรือต่างคนก็ได้)
ตัวอย่างการ เซ็นลายเซ็นดิจิทัลบนเอกสาร PDF ที่เปิดด้วยโปรแกรม Adobe Reader
นอกเหนือจากมาตรฐาน PAdES แล้วยังมีมาตรฐานอื่น ๆ ที่ใช้ลงลายเซ็นดิจิทัลได้อีกและอยู่ภายใต้กลุ่มของมาตรฐาน Advanced Electronic Signature (AdES) เดียวกัน เช่น XAdES ไว้ใส่ลายเซ็นใน XML อย่างที่ระบบ e-Tax ของกรมสรรพากรใช้ หรือ CAdES ไว้สร้างไฟล์ลายเซ็นแยกกับเอกสารอื่น ๆ นอกจาก PDF ได้ แต่จะไม่ขอพูดถึง ถ้าใครสนใจไปหาอ่านกันต่อเองโลด
ปัจจุบันก็มีผู้ให้บริการแบบเสียเงินสำหรับการสร้างลายเซ็นดิจิทัลมากมาย เช่น ของ Adobe เจ้าของโปรแกรม Adobe Reader เองก็มีเช่นกัน โดยส่วนมากจะเสียค่าใช้จ่ายเป็นต่อจำนวนผู้ใช้งาน โดยบริการประเภทเสียเงินก็จะเข้ามาช่วยจัดการในแง่มุมของ การออกใบรับรอง (Certificate) และชุดกุญแจ ที่สำหรับออกให้ผู้ใช้งานที่จะต้องเซ็นเอกสาร โดยจะประกอบไปด้วยมีข้อมูลที่เรียกว่ากุญแจสาธารณะ (Public Key) และกุญแจลับ (Private Key) ของแต่ละคน โดยบางเจ้าอาจรวมถึง การจัดเก็บและบริหารจัดการเอกสารให้ด้วย
แต่ในบทความนี้เราจะมาดู ท่าที่ทำฟรี ไม่ต้องเสียเงิน และเอาไปปรับใช้ได้ง่าย ๆ ในองค์กรกัน !
วิธีการทำระบบลายเซ็นดิจิทัลในองค์กรฟรีด้วย openssl
ความท้าทายของการทำ “ลายเซ็นดิจิทัล” อย่างหนึ่งคือ เราจะตรวจสอบได้อย่างไรว่า เอกสารที่ถูกเซ็นมานั้น ถูกเซ็นมาด้วยเจ้าของลายเซ็นจริง ๆ วิธีการโดยย่อก็คือ ในลายเซ็นจะมีข้อมูล “ใบรับรองของลายเซ็น” ที่ประกอบด้วย กุญแจสาธารณะ และข้อมูลของเจ้าของลายเซ็นอยู่ เราก็เลยสามารถตรวจสอบได้ว่า ลายเซ็นนั้นเป็นของจริง
แต่เดี๋ยวก่อน.. แล้วเราจะมั่นใจได้อย่างไรว่า “ใบรับรองของลายเซ็น” ข้างในลายเซ็นดิจิทัลนั้น เป็นของจริง? ไม่ใช่มีแฮกเกอร์ ที่ออกใบรับรองแล้วใส่ข้อมูลชื่อคนอื่นลงไป มาเซ็นเอกสารนั้น?
คำตอบแบบเข้าใจง่าย ๆ ก็คือ ใบรับรองของแต่ละคน จะถูกรับรอง ต่อมาอีกทีโดย หน่วยงานผู้ให้บริการออกใบรับรอง (Root Certificate Authority หรือ Root CA หรือย่อ ๆ ว่า CA) .. ทีนี้กลับไปคำถามเดิมอีกที
แต่เดี๋ยวก่อน.. แล้วเราจะมั่นใจได้อย่างไรว่า ใบรับรองของ “ผู้ให้บริการออกใบรับรอง หรือ CA” ที่มารับรองใบรับรองของลายเซ็นในเอกสารนั้นเป็นของจริง?
คำตอบ ก็คือในโปรแกรมเปิดเอกสาร PDF อย่าง Adobe Reader จะมีการ ติดตั้ง CA ที่น่าเชื่อถือและตรวจสอบมาแล้วให้ล่วงหน้า ดังนั้น ถ้าใบรับรองของผู้ให้บริการออกใบรับรอง (CA) ใด ที่ Adobe Reader บอกว่าน่าเชื่อถือได้ จึงถือว่าเชื่อถือได้ไปโดยปริยายเป็นค่าเริ่มต้น
ซึ่งเจ้าของ CA เองก็จะมีค่าใช้จ่ายในการถูกตรวจสอบอย่างเข้มข้น และนำตัวเองเข้าไปอยู่ในโปรแกรม Adobe Reader และในระบบปฏิบัติการต่าง ๆ เป็นค่าเริ่มต้น ดังนั้น การที่เราจะไปขอ ใบรับรองสำหรับการเซ็นเอกสาร จาก CA โดยทั่วไปจึงเสียเงินนั่นเอง
แต่ช้าก่อน ถ้าหาก การทำลายเซ็นดิจิทัลนั้น มีจุดประสงค์เพื่อใช้ภายในองค์กรเป็นหลัก หรือข้ามองค์กร ที่อยู่ภายใต้เงื่อนไขอะไรบางอย่างร่วมกัน เช่น เป็นบริษัทหลัก กับบริษัทลูก หรือบริษัทในเครือ หรือมีข้อตกลงร่วมกัน เราสามารถที่จะออกแบบกระบวนการให้ องค์กรเราสร้าง CA ไว้ใช้เองได้ฟรี ๆ หรือเรียกกันว่า Internal Root CA และให้ พนักงาน ที่จะเซ็นเอกสารดิจิทัล หรือตรวจสอบลายเซ็นดิจิทัล ติดตั้งเจ้า Internal Root CA นี้ลงไปในคอมพิวเตอร์ขององค์กร เราก็จะไม่ต้องเสียค่าใช้จ่าย เพื่อซื้อใบรับรองจาก CA มาเซ็นลายเซ็นดิจิทัลให้เอกสาร แนวทางเดียวกันกับ การเปิดใช้ใบรับรองการเข้ารหัส https ให้เว็บในระบบเครือข่ายภายในขององค์กรด้วย Internal Root CA เป๊ะ ๆ ถ้าใครเคยทำมาก่อน
การสร้าง CA อาจซับซ้อน เอ๊ย!! ปลอดภัยได้มากกว่านั้นอีก คือการมี CA ย่อยจาก Root CA มาอีกเรียกว่า Intermediate CA สำหรับให้แต่ละหน่วยงานภายใต้ Root CA นั้น ๆ ออกใบรับรองสำหรับการใช้งานจริงของแต่ละบุคคล ซึ่งจะเรียกว่า Leaf Certificate
กระบวนการออกและยืนยันความน่าเชื่อถือของ Root CA, Intermediate CA และ Leaf Certificate จะเป็นไปตามรูป ด้านล่างนี้ คือ Root CA ใหญ่สุด ออก Intermediate CA และ Intermediate CA ออก Leaf Certificate ย่อย ๆ สำหรับการใช้งานจริง ๆ
จะสังเกตเห็นว่า Root CA ใส่ลายเซ็นดิจิทัลของตัวเองลงในใบรับรอง (และ Issuer คือตัวเองด้วย) ดังนั้น Root CA ในเชิงเทคนิคแล้วจริง ๆ อาจถือว่าเป็น Self-Signed Certificate คือรับรองให้ตัวเอง ว่าตัวเองน่าเชื่อถือ แต่ในบทความนี้จะขอข้าม Intermediate CA ไปจะมีแค่ Root CA ที่สร้างขึ้นเองภายในองค์กรหรือเรียกรวม ๆ ว่า Internal Root CA และใบรับรองของพนักงานแต่ละคนที่ใช้ในการเซ็นเอกสาร หรือ Leaf Certificate ตามรูปด้านบนนั้นเอง
สรุปสิ่งที่จะต้องทำ เพื่อทำให้เกิดลายเซ็นดิจิทัลในบทความนี้ได้ก็จะมี 4 ส่วนได้แก่
- สร้างกุญแจลับและ Internal Root CA ขององค์กร ที่คู่กัน
- สร้างกุญแจลับและ (Leaf) Certificate ของพนักงานแต่ละคน ที่คู่กัน
- วิธีการใส่ลายเซ็นดิจิทัลลงในเอกสาร PDF ของพนักงานแต่ละคน
- วิธีการตรวจสอบว่าลายเซ็นดิจิทัลนั้น ถูกเซ็นมาโดยเจ้าของลายเซ็นตัวจริง
มาเริ่มกันเลยดีกว่า
1.สร้าง Internal Root CA ขององค์กรด้วย openssl
เราสามารถใช้โปรแกรม openssl ที่มีอยู่ในระบบปฏิบัติการ Linux ทั่วไป ในตัวอย่างนี้จะใช้ MacOS แต่ใน Ubuntu หรือ CentOS ก็ใช้วิธีเดียวกันได้ การสร้าง Internal Root CA มี 2 ขั้นตอนย่อยง่าย ๆ คือ
– การสร้าง กุญแจลับ (Private Key) ในรูปแบบ RSA
– การสร้าง Internal Root CA จากกุญแจลับ (Private Key)
1.1 การสร้าง กุญแจลับ (Private Key) ในรูปแบบ RSA
โดยการใช้คำสั่ง openssl ต่อไปนี้ สร้างไฟล์ ca.key
$ openssl genrsa -out ca.key 4096
ถัดจากนั้นจะเป็น
1.2 การสร้าง Internal Root CA จากกุญแจลับ (Private Key)
จริง ๆ แล้ว Root CA ก็จะคล้ายกับ (Leaf) Certificate ธรรมดานี่แหละ เป็นไฟล์ Binary ที่อ้างอิงโครงสร้างจากมาตรฐานชื่อว่า X.509 ที่เก็บว่ามีคุณสมบัติเป็นค่าอะไรบ้าง เป็นคู่ ๆ Key/Value แต่จะมีคุณสมบัติที่ต่างกันหลัก ๆ คือการที่เป็น Self-Signed Certificate เป็นคนรับรองให้ตัวเอง ว่าตัวเองนั้นถูกต้อง ในเชิงเทคนิคคือค่า Field ชื่อว่า Issued to (Subject) คนถูกเซ็น กับ Issued by (Issuer) คนเซ็น เป็นคนเดียวกัน ตัวอย่าง Root CA ของเว็บไซต์ที่ใช้ https ก็มีคุณสมบัตินี้เช่นกัน
รวมถึงถ้าเป็น มาตรฐาน X.509 รุ่น 3 จะมี Field อันหนึ่งชื่อว่า isCA อยู่ในส่วนที่เรียกว่า Extension Block เอาไว้ตรวจสอบว่า Certificate ใด ๆ เป็น CA หรือเปล่าด้วย (แต่เว็บเบราว์เซอร์หลัก ๆ ไม่แปลใส่มาในรายละเอียด Certificate ให้ อยากเห็นต้อง Hex dump!)
โดยทั่วไป Root CA จะมีวันหมดอายุ และมีการกำหนด วันหมดอายุที่ค่อนข้างนานอย่าง 20 ปี (หรือก่อนหน้านั้นถ้าหาก กุญแจลับถูกแฮก) และใช้ในการรับรองให้ CA ลำดับถัดไปเรียกว่า Intermediate CA ที่จะมีอายุน้อยกว่าเช่น 5 ปี และนำ Intermediate CA ไปออกใบรับรองสุดท้าย (Leaf Certificate) ในกรณีนี้คือ ใบรับรองของพนักงานแต่ละคน ที่อาจจะมีอายุน้อยสุดเช่น 1 ปี โดยความน่าเชื่อถือของใบรับรองดิจิทัล จะเป็นการเซ็นรับรองต่อ ๆ กันมาเป็นทอด ๆ อย่าง Root CA รับรองให้ Intermediate CA และจากนั้น Intermediate CA รับรองให้ Leaf Certificate โดยเราจะเรียกการรับรองต่อ ๆ กันมานี้ว่า Chain of Trust (ตามในรูปวงกลมสามวงด้านบนนั่นเอง)
คำสั่ง openssl ต่อไปนี้เป็นตัวอย่างที่ใช้ในการสร้าง Root CA จะได้ไฟล์ ca.crt (อายุ 10 ปี)
$ openssl req -x509 -new -nodes -key ca.key -sha256 -days 3560 -subj "/C=TH/ST=Bangkok/L=Bangkok/O=Siam Thanat Hack/OU=STH/CN=STH Root CA/[email protected]" -out ca.crt
สุดท้ายแล้วจากขั้นตอนที่ 1 นี้ เราจะได้ไฟล์ชื่อ ca.key (กุญแจลับ) และ ca.crt (ใบรับรอง) ของ Internal Root CA
สิ่งสำคัญมาก ๆ ในขั้นตอนนี้คือ ca.key หรือกุญแจลับนั้น ต้องถูกเก็บรักษาไว้อย่างปลอดภัย ไม่ให้บุคคลที่ไม่มีสิทธิ์ล่วงรู้ ถ้าให้ดีคือไม่ควรย้ายออกไปที่ไหน สร้างและเก็บไว้ในเครื่อง ๆ หนึ่งโดยเฉพาะ หรือถ้าให้ดีกว่า เก็บไว้ในระบบบริหารจัดการกุญแจโดยเฉพาะ เช่นซอฟต์แวร์ Secret Vault หรือ Hardware Security Module (HSM) แต่จะไม่ขอพูดถึงในบทความนี้ ขอย้ำแค่ห้ามหายหรือห้ามเอาไปให้ใครที่ไม่ได้รับอนุญาต!
2. สร้าง Private/Public Key ของพนักงานแต่ละคน ด้วย openssl
ถัดจากที่เรามี Internal Root CA แล้ว (ca.key กับ ca.crt) จากนั้น เราจะนำ Internal Root CA ที่ได้ มาสร้างใบรับรอง (Leaf Certificate) ให้พนักงานแต่ละคน นำไปเซ็นเอกสาร PDF กัน ! โดยมีขั้นตอนดังนี้
– เตรียมไฟล์ cert.ext เก็บข้อมูลเกี่ยวกับใบรับรองที่จะสร้าง
– เตรียมไฟล์ create_signing_cert.sh สำหรับสร้างใบรับรอง PKCS#12 (.p12) ของพนักงาน
จากตัวอย่างต่อไปนี้เราจะใช้สคริปท์ Bash ง่าย ๆ ชื่อ create_signing_cert.sh ในการสร้างใบรับรองให้พนักงาน 1 คน แต่ในทางปฏิบัติ ผู้อ่านสามารถ เขียนโปรแกรมวนลูปดึงข้อมูลจาก ฐานข้อมูลหรือไฟล์มาสร้าง ใบรับรองให้พนักงานครั้งละจำนวนมาก ๆ ได้เช่นกัน
2.1 เตรียมไฟล์ cert.ext เก็บข้อมูลเกี่ยวกับใบรับรองที่จะสร้าง
โดยไฟล์นี้จะใช้เก็บค่าที่จะถูกใส่ในใบรับรอง เพื่อบอกซอฟต์แวร์ต่าง ๆ ตอนจังหวะมีการใช้งาน ว่าใบรับรองนี้เอาไว้ใช้งานเกี่ยวกับลายเซ็นดิจิทัล
File: cert.ext
[ user_signing_cert ]
basicConstraints = CA:FALSE
nsCertType = objsign
nsComment = "User Signing Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = digitalSignature
2.2 เตรียมไฟล์ create_signing_cert.sh สำหรับสร้างใบรับรอง PKCS#12 (.p12) ของพนักงาน
ขั้นตอนนี้จะซับซ้อนหน่อย โดยจะมีสิ่งต่าง ๆ ในสคริปท์ดังนี้
- ไฟล์ ca.crt กับ ca.key ในขั้นตอนก่อนหน้า สำหรับการเซ็นรับรอง ใบรับรองของพนักงานแต่ละคน จากผู้ดูแลระบบ (หรือระบบอัตโนมัติ) ที่ถือ Internal Root CA ในมือ
- ไฟล์ PKCS#12 (pichaya_pdf_signing.p12) เป็น “กล่อง” ที่เก็บ กุญแจลับ (Private Key) กับ ใบรับรอง ของ พนักงานแต่ละคนในองค์กร ซึ่งไฟล์นี้ คือไฟล์สำคัญ ที่พนักงานที่จะเซ็นลายเซ็นดิจิทัลให้เอกสาร PDF จะต้องเอาไปใช้ ใส่ในโปรแกรม Adobe Reader เพื่อเซ็นรับรองเอกสารต่าง ๆ ของตัวเอง
- สุ่มค่ายาว 16 ตัว สำหรับการเปิดไฟล์ PKCS#12 (.p12) นี้ขึ้นมาเซ็นเอกสาร จะเรียกว่าค่า Passphrase (ในตัวแปร PFX_PASS)
- ไฟล์ tmp.key เป็น กุญแจลับ ของใบรับรองพนักงาน แต่เราจะสร้างชั่วคราวก่อนเอาไปยัดในกล่องไฟล์ PKCS#12 แล้วจะลบออกทันทีหลังจากยัดเสร็จแล้ว
- ไฟล์ tmp.csr เป็นใบรับรองของพนักงาน ที่รับรองจาก กุญแจลับ (tmp.key) ที่สร้างเอง แต่ยังไม่มีการรับรองจาก Internal Root CA (คือ ca.key ที่ได้มาจากขั้นตอนที่ 1 นั่นเอง)
หมายเหตุ: ปกติแล้วจะเรียกไฟล์นี้ว่า Certificate Signing Request (CSR) เพราะพนักงาน ควรจะเป็นคนสร้างใบรับรอง นี้เองด้วยกุญแจลับที่ตัวเองสุ่มขึ้นมาเอง (tmp.key) รู้คนเดียว แล้วส่ง Certificate นี้เพื่อร้องขอ (Request) ให้ ผู้ดูแลระบบ หรือระบบอัตโนมัตินำมาเซ็น (Signing) รับรอง รวมกันเลยเป็น Certificate Signing Request (CSR) ตามชื่อ - โดยใบรับรอง tmp.csr ที่สร้างขึ้น จะระบุตัวตน คนที่สร้างให้ได้ ที่ช่องเก็บข้อมูล (Field) ชื่อ Subject โดยใน Field นี้จะมีการเก็บข้อมูลแยกประเภทย่อยไปอีกเช่น CN, C, ST, L, O, OU, … อ้างอิงตามมาตรฐานชื่อว่า IETF PKIX (RFC 5280) จะมีข้อมูลเช่น ชื่อคน อีเมล ชื่อบริษัท ฯลฯ อยู่ในรายละเอียดของใบรับรอง
- ไฟล์ tmp.crt คือไฟล์ ใบรับรองของพนักงาน (tmp.csr) ที่ถูกรับรองโดย Internal Root CA (ca.key) เรียบร้อยแล้ว แต่เราจะลบออก หลังจากยัดลงกล่อง PKCS#12 (ไฟล์ .p12)
มาดูโค้ดกันเลยดีกว่า จะได้เห็นภาพมากยิ่งขึ้น
File: create_signning_cert.sh
#!/bin/bash
FULLNAME="Pichaya Morimoto"
EMAIL="[email protected]"
CA_CERT="ca.crt"
CA_KEY="ca.key"
OUT_PFX="pichaya_pdf_signing.p12"
PFX_PASS=$(xxd -l 16 -p /dev/urandom)
echo "[*] Passphrase: ${PFX_PASS}"
echo "[*] Generate client certificate private key"
openssl genrsa -out tmp.key 2048
echo "[*] Generate client csr"
openssl req -new -key tmp.key -out tmp.csr -subj "/CN=$FULLNAME/C=TH/ST=Bangkok/L=Bangkok/O=Siam Thanat Hack/OU=STH/emailAddress=$EMAIL"
echo "[*] Sign csr with generated CA"
openssl x509 -req -in tmp.csr -CA $CA_CERT -CAkey $CA_KEY -CAcreateserial -out tmp.crt -days 825 -sha256 -extfile ./cert.ext -extensions user_signing_cert
echo "[*] Generate keystore PKCS#12"
openssl pkcs12 -export -in tmp.crt -inkey tmp.key -out $OUT_PFX -passout "pass:$PFX_PASS"
rm tmp.csr tmp.key tmp.crt
จะได้ผลลัพธ์เป็นไฟล์ PKCS#12 (pichaya_pdf_signing.p12) ดังนี้
สรุปคือไฟล์ tmp.key, tmp.csr และ tmp.crt ใช้แค่ชั่วคราวในขั้นตอนการสร้างไฟล์ PKCS#12 (.p12) ที่สุดท้ายแล้ว พนักงานแต่ละคนจะได้ไฟล์ PKCS#12 (.p12) นี้กลับไปเก็บไว้สำหรับการ เซ็นเอกสาร โดยในไฟล์ PKCS#12 (.p12) จะมี 2 อย่างหลัก ๆ คือ
- ใบรับรองหรือ Certificate ของพนักงานรายคน
- กุญแจลับ ที่ใช้ในการเซ็นเอกสาร
อ่านแล้วอาจจะดูซับซ้อนหน่อย ๆ ถ้าเขียนเป็นสมการให้เข้าใจง่าย ๆ จะได้เป็น
PKCS#12 (.p12) = [tmp.key กุญแจลับของพนักงาน, ใบรับรองพนักงานที่เซ็นรับรองโดย tmp.key กุญแจลับของพนักงาน พร้อมกับ ca.key ใบรับรองขององค์กรแล้ว] + ถูกเข้ารหัสอีกชั้นด้วย Passphrase
ดังนั้นไฟล์ PKCS#12 (.p12) กับ Passphrase นี้พนักงานแต่ละคนจะต้องเก็บเป็นความลับมาก ๆ ห้ามหาย ห้ามโดนขโมย และก่อนจะให้ Internal Root CA (ca.key) เซ็นรับรองให้ใบรับรองพนักงานใด ๆ ต้องมีกระบวนการตรวจสอบให้แน่ใจว่า ใบรับรองที่ร้องขอมาให้เซ็น (CSR) นั้น มาจากพนักงานคนนั้นจริง ๆ (ถ้าเซ็นรับรองมั่ว ๆ ก็อาจจะโดนหลอกสร้างใบรับรองจริง ให้แฮกเกอร์ได้)
ในขั้นตอนจริง ๆ แบบปลอดภัยสูงสุด เราสามารถให้พนักงานแต่ละคน สร้างกุญแจลับ (tmp.key) กับ CSR (tmp.csr) ของตัวเอง จากนั้นส่งไฟล์ CSR มาให้ ผู้ดูแลระบบ เซ็นรับรอง ออกมาเป็นไฟล์ tmp.crt ส่งกลับคืนพนักงานคนนั้น จากนั้น ให้พนักงานเอาไฟล์ tmp.crt กลับไปยัดลงกล่อง ไฟล์ PKCS#12 (pichaya_pdf_signing.p12) ของตัวเองพร้อมกับ tmp.key ก็จะทำให้ ผู้ดูแลระบบไม่เคยเข้าถึง กุญแจลับของพนักงานแต่ละคนเลย
สิ่งที่เราข้ามไปไม่ได้อธิบายในบทความนี้ และผู้อ่านสามารถไปหาอ่านต่อกันเองได้คือ จะทำยังไงถ้าหากไฟล์ PKCS#12 (.p12) ของพนักงานถูกแฮก ขโมยออกไป? (keyword: certificate revocation list, OCSP stapling)
ณ จุดนี้สิ่งที่เราได้มาในมือแล้วคือ
- ใบรับรอง Internal Root CA (ca.key, ca.crt) ขององค์กร
- ไฟล์ PKCS#12 (pichaya_pdf_signing.p12) สำหรับเซ็นเอกสารของพนักงาน
ต่อไปเราจะมาดูกระบวนการเซ็นเอกสารและตรวจสอบลายเซ็นกัน!
3. การทำลายเซ็นดิจิทัลจาก Private Key พนักงานใน Adobe Reader
3.1 การใช้งานครั้งแรกติดตั้ง Internal Root CA
ผู้ใช้งานจะต้องดาวน์โหลดและติดตั้งโปรแกรม Adobe Acrobat Reader DC (ต่อไปจะขอเรียกย่อ ๆ ว่า Adobe Reader) ก่อน
URL: https://get.adobe.com/uk/reader/
ติ๊กถูกที่ Optional Offers ต่าง ๆ ออกและกดปุ่ม “Download Acrobat Reader” ได้เลย
จากนั้นเมื่อเปิดโปรแกรม Adobe Reader ขึ้นมา เนื่องจาก CA ของเราสร้างขึ้นมาเอง ไม่ได้อยู่ใน รายชื่อที่ถูกติดตั้งมาโดยอัตโนมัติของ Adobe Reader ดังนั้น พนักงานในองค์กร ทั้งผู้รับและผู้ส่งไฟล์เอกสาร PDF จะต้องนำไฟล์ ca.crt มาติดตั้งในเครื่อง (ไฟล์นี้เป็นข้อมูลกุญแจสาธารณะไม่เป็นความลับ)
ขั้นตอนคือ ในตัวเลือกเมนูด้านบนโปรแกรมไปที่ Edit → Preferences… > เลือก Categories เป็น Signature จากไปที่ Identities & Trusted Certificates แล้วกด More… จากนั้นเลือกเมนู Trusted Certificates และกด ปุ่ม Import > กดปุ่ม Browse
เลือกไฟล์ Internal Root CA ที่เราสร้างมา (ca.crt) โดยโปรแกรม Adobe Reader อาจจะเห็นไฟล์นามสกุล .cer เท่านั้นให้เปลี่ยนนามสกุลไฟล์จาก ca.crt เป็น ca.cer ได้เลย
จากนั้นกดตามรูปภาพ ตามลำดับ (1) เลือก ชื่อ Internal Root CA -> (2) เลือกเสร็จจะมีรายการ Certificate ขึ้นมาให้เลือก คลิกหนึ่งครั้ง -> (3) กดปุ่ม Trust … -> (4) ติ๊กถูกในช่อง Certified documents -> (5) กดปุ่ม OK -> (6) กดปุ่ม Import
กด OK ออกมาจากเมนูการตั้งค่า เป็นอันเสร็จสิ้นการติดตั้ง Internal Root CA ครั้งแรกให้โปรแกรม Adobe Reader ในคอมพิวเตอร์แต่ละเครื่อง
3.2 วิธีการเซ็นเอกสารครั้งแรก ติดตั้งใบรับรองของผู้ใช้งาน PKCS#12 (.p12)
เมื่อพนักงาน ได้รับไฟล์เอกสาร PDF ที่จะต้องการเซ็นรับรองการอนุมัติ เปิดในโปรแกรม Adobe Reader จากนั้นไปที่เมนู Tools ด้านบน แล้วเลือก Certificates แถวที่ 2 แล้วกดปุ่ม Open (ถ้าคนไม่ทราบอาจจะเผลอกดผิดไป เลือก Fill & Sign ได้ เพราะเป็นรูปลายเซ็น แต่สำหรับลายเซ็นดิจิทัล ต้องเลือกที่ Certificates)
จากนั้นกด Digitally Sign ที่ เมนูด้านบนตรงกลาง และเมาส์เราจะสามารถคลิกและลากกล่องสี่เหลี่ยม บริเวณที่เราต้องการจะ ลงลายเซ็นดิจิทัลได้
สำหรับการเซ็นเอกสารครั้งแรกจะเจอข้อความแบบนี้ จำเป็นจะต้องเพิ่ม ใบรับรองของพนักงานที่เราสร้างก่อนหน้านี้ ให้กดปุ่ม “Configure Digital ID” -> เลือก “Use a Digital ID from a file” -> กด Browse เลือกไฟล์ PKCS#12 (.p12) และใส่ Passphrase
กดปุ่ม Continue รัว ๆ จะพบฟังก์ชันของ Adobe Reader ให้เรากด Create
และเลือกได้ว่า เราอยากให้ลายเซ็นดิจิทัลของเราแนบไปกับสิ่งที่แสดงในเอกสารเป็นรูปแบบไหน ได้แก่
- Text: เป็นข้อความพิมพ์ลงไป
- Draw: วาดลายเซ็นของเราลงไป
- Image: เลือกรูปที่จะใช้เป็นลายเซ็นของเรา
- None: เซ็นเอกสารแบบดิจิทัล โดยไม่ต้องมีอะไรแสดงเพิ่มเติมบนหน้าเอกสาร
ส่วนมากแล้วเอกสารเป็นทางการ อาจจะ มีไฟล์รูปลายเซ็นแล้วใช้ ลายเซ็นดิจิทัลเซ็นลงไปที่รูปนั้นในเอกสารอีกทีหนึ่ง เพื่อที่ว่าในกรณีที่ไฟล์ถูกพิมพ์เป็นกระดาษจะได้มีรูปลายเซ็นเราติดไปด้วย แต่ถ้าเป็นเอกสารอิเล็กทรอนิกส์ (.pdf) จะสามารถยืนยันได้ว่ามีการเซ็นลายเซ็นดิจิทัล จากเจ้าของลายเซ็นนั้น ๆ แล้ว (น่าเชื่อถือกว่า) เรียกว่า Backward Compatible เซ็นครั้งเดียวให้รองรับแบบกระดาษได้ด้วยนั่นเอง
ในตัวอย่างนี้ขอเลือกเป็น Draw วาดลายเซ็นเองไปก่อน จากนั้นใส่ Passphrase และกด Sign และตั้งชื่อไฟล์ใหม่ แนะนำว่าถ้าเซ็นคนเดียวอาจจะเติมคำว่า _signed ไปต่อท้ายชื่อไฟล์ เช่นจาก doc.pdf เป็น doc_signed.pdf เป็นต้น เพื่อจัดระเบียบเอกสารให้เข้าใจง่าย
จากนั้นเมื่อเรากด Sign ครั้งถัด ๆ ไปจะไม่จำเป็นต้องเพิ่มใบรับรองหรือสิ่งที่จะแสดงในเอกสารประกอบกับลายเซ็นดิจิทัลอีกรอบแล้ว สามารถใช้ที่ตั้งค่าไว้ครั้งแรกได้เลย (ถ้าต้องการ)
4. วิธีการตรวจสอบว่าลายเซ็นดิจิทัลนั้น ถูกเซ็นมาโดยเจ้าของลายเซ็นตัวจริง
ถ้าหาก ผู้รับไฟล์ ได้ติดตั้ง Internal Root CA เรียบร้อย และได้รับไฟล์เอกสาร PDF ที่ถูกเซ็นด้วยลายเซ็นดิจิทัลมานั้น สามารถที่จะตรวจสอบด้วย Adobe Reader ได้ทันทีว่า ลายเซ็นดิจิทัลนั้นถูกเซ็นมาอย่างถูกต้อง จากกุญแจลับของเจ้าของลายเซ็นนั้นจริง ๆ
จากเครื่องหมายติ๊กถูกสีเขียว ๆ และข้อความ “Signed and all signatures are valid.”
ในทางกลับกัน ถ้าหากเอกสารมีการเซ็นมาโดยลายเซ็นดิจิทัลปลอม ที่สร้างจาก CA ที่เราไม่ได้เชื่อถือ ก็จะรู้ได้ในทันทีอีกเช่นกันจากภาพต่อไปนี้
- มีการเซ็น ด้วยลายเซ็นดิจิทัลถูกต้องครั้งแรกจาก Somporn Thanathack
- แต่มีการ(แก้ไข?) และเซ็นลายเซ็นซ้ำด้วย ลายเซ็นดิจิทัลจาก Somchai Pwnie ที่มาจาก ใบรับรองปลอม ที่ไม่ได้ถูกเชื่อถือโดยโปรแกรม Adobe Reader
กรณี ลายเซ็นเกิดปัญหา (ไม่ถูกต้อง) จะเห็นเป็นเครื่องหมายตกใจ พร้อมข้อความ “At least one signature has problems.” ให้ตรวจสอบเอกสารจากผู้ส่งหรือผู้เซ็นใหม่อีกครั้ง อาจโดนปลอมแปลงไปแล้ว!
ในเชิงเทคนิคสำหรับชาว Geek แล้ว การรับรองว่าเอกสาร PDF ใด ๆ ตามมาตรฐาน PAdES ถูกเซ็นรับรองมาด้วยลายเซ็นดิจิทัลหรือเปล่านั้น สามารถอ้างอิงได้จากรูปด้านล่างนี้
- ในไฟล์เอกสาร (เอกสาร.pdf) จะมีส่วนของเนื้อหาไฟล์ PDF ปกติ และส่วนของลายเซ็นดิจิทัล รวมอยู่ในไฟล์เดียวกัน
- เมื่อโปรแกรม Adobe Reader จะทำการตรวจสอบ ขั้นแรกจะนำ คนรับรองของ “ใบรับรองของลายเซ็น” นั้นไปตรวจสอบก่อนว่า ถูกรับรองมาโดยคนที่น่าเชื่อถือใช่ไหม (เป็น CA ที่ถูกติดตั้งเป็นค่าเริ่มต้น หรือใส่ไปเพิ่มเติมในโปรแกรมหรือในคอมพิวเตอร์เครื่องนั้น)
- ถ้าใช่ก็จะนำ “กุญแจสาธารณะ” ของ “ใบรับรองของลายเซ็น” นั้นไปใช้ถอดรหัสค่า Hash (SHA-256) ที่ถูกเข้ารหัสด้วยกุญแจลับที่คู่กันแต่ไม่ได้ฝังมา และเซ็นเก็บไว้ว่าค่า Hash ที่จะถูกถอดรหัสนี้แหละเป็นของเอกสารจริง (เพราะคนที่สร้างมามีกุญแจลับ ของใบรับรองของลายเซ็น)
- จากนั้นคำนวณค่า Hash เดียวกันจาก เนื้อหาเอกสาร PDF ปกติ
- สุดท้ายนั้นค่า Hash ที่ฝังมาในไฟล์และถอดรหัสได้จากกุญแจสาธารณะ มาเทียบกับค่า Hash ของไฟล์เอกสารจริง ๆ ว่าตรงกันไหม ถ้าตรงกัน แสดงว่าเนื้อหาไฟล์ PDF ถูกต้องถูกรับรองมาด้วย เจ้าของใบรับรองของลายเซ็น ตัวจริง นั่นเอง
5. นำ Internal Root CA เชื่อมต่อกับระบบอื่น ๆ ในองค์กร (ทำ Automation)
จะเห็นว่าจากตัวอย่างนี้เราทำหลายอย่างด้วยมือพิมพ์คำสั่ง openssl เองทั้งตอนสร้าง Internal Root CA, สร้างใบรับรองของผู้ใช้งาน และเซ็นเอกสารด้วยลายเซ็นดิจิทัลผ่านโปรแกรม Adobe Reader แต่ในสถานการณ์จริงแล้วนั้น ผู้อ่านสามารถพัฒนาระบบ ขึ้นมาเพื่อเชื่อมต่อกับ Internal Root CA ได้ตัวอย่างเช่น
- มีระบบที่ใช้ในการสร้าง ใบรับรองของพนักงานอัตโนมัติ
- มีระบบที่ใช้ในการยืนยันเอกสารครั้งละจำนวนมาก ๆ เช่น 100 ไฟล์ ว่าทุกไฟล์ถูกเซ็นด้วยลายเซ็นดิจิทัลที่รับรองโดย Internal Root CA ขององค์กร
- มีระบบที่สามารถเซ็นเอกสาร PDF ที่ถูกสร้างจากแอปพลิเคชัน หรือคน โดยไม่ต้องใช้คนเซ็นผ่านโปรแกรม Adobe Reader
โดยตัวอย่างโค้ดภาษา Python ต่อไปนี้ ผู้อ่านสามารถนำไปศึกษาและปรับใช้ได้ เป็นกรณีที่ทำฟังก์ชันขึ้นมา สำหรับการรับไฟล์ PDF เข้ามา และนำ ใบรับรองมาสร้างลายเซ็นดิจิทัล ด้วยไฟล์ PKCS#12 (.p12) ว่าเป็นเอกสารที่ออกอย่างถูกต้องโดยองค์กร โดยไม่จำเป็นต้องใช้คนมาเซ็นผ่านโปรแกรม Adobe Reader
File: pdf_signer.py
import datetime
from cryptography.hazmat import backends
from cryptography.hazmat.primitives.serialization import pkcs12
from endesive.pdf import cms
def sign_pdf(app, pdffile):
fname = pdffile
date = datetime.datetime.utcnow() # + datetime.timedelta(hours=7)
date = date.strftime("D:%Y%m%d%H%M%S+00'00'")
dct = {
"sigfield": "Signature_STH",
"sigandcertify": True,
"signature": "Siam Thanat Hack Co., Ltd.",
"contact": "[email protected]",
"location": "Thailand",
"signingdate": date,
"reason": "To confirm that this document was created by STH and did not modify by others",
}
with open(app.config['STH_PFX_FILE'], "rb") as fp:
p12 = pkcs12.load_key_and_certificates(
fp.read(), app.config['STH_PASS'].encode(), backends.default_backend()
)
datau = open(fname, "rb").read()
datas = cms.sign(datau, dct, p12[0], p12[1], p12[2], "sha256")
return datau + datas
ในบทความนี้ผู้อ่านน่าจะได้รับแนวทางท่าหนึ่ง ที่จะสร้างและนำ Internal Root CA ไปปรับใช้ภายในองค์กร เพื่อการสร้างลายเซ็นดิจิทัล โดยไม่ต้องเสียค่าใช้จ่ายจาก บริการเสียเงินต่าง ๆ ภายใต้เงื่อนไขที่เครื่องคอมพิวเตอร์ของพนักงานในองค์กร จะต้องติดตั้ง Internal Root CA นั้น ๆ ซึ่งโดยทั่วไปแล้ว องค์กรขนาดใหญ่ มักจะมี Internal Root CA ที่ใช้ในการออกใบรับรองให้บริการเว็บที่เข้ารหัส (https) ในเครือข่ายภายในอยู่แล้ว จึงอาจไม่มีความจำเป็นจะต้องติดตั้ง Internal Root CA เพิ่มเติม สิ่งที่ต้องทำเพิ่มเติมคือการสร้างใบรับรองให้พนักงานแต่ละคนและการออกนโยบาย, อบรม, จัดทำวิธีการเซ็นเอกสารด้วยลายเซ็นดิจิทัล หรือพัฒนาระบบอัตโนมัติสำหรับการทำลายเซ็นดิจิทัลให้เอกสาร ที่ออกจากแอปพลิเคชันภายในของบริษัทให้กับคู่ค้าหรือบริษัทในเครือที่มีการติดตั้ง Internal Root CA ดังกล่าวนั้นเอง
บทความที่เกี่ยวข้อง