ทำระบบเซ็นเอกสาร PDF ด้วยลายเซ็นดิจิทัลในองค์กรแบบง่าย ๆ

เชื่อว่าทุกคนเคยเซ็นลายมือชื่อลงในเอกสาร ไม่ว่าจะเป็นการเปิดบัญชีธนาคาร หรือลายเซ็นประกอบกับข้อความสำเนาถูกต้องให้กับสำเนาเอกสารต่าง ๆ สำหรับคนที่ไม่ได้มีหน้าที่ ที่จะต้องเซ็นเอกสารบ่อยนักก็คงไม่ได้เป็นปัญหาอะไร แต่ในองค์กรหรือหน่วยงานราชการ ที่มีเอกสารหนา ๆ เป็นปึก ๆ ทุก ๆ เดือน ที่จะต้องลงลายมือชื่อทุกหน้า ก็เป็นอะไรที่ไม่มีใครอยากเสียเวลาทำ

คำถามคือ จะดีแค่ไหน ถ้าหาก เราสามารถที่จะลงลายมือชื่อในเอกสาร แบบอิเล็กทรอนิกส์ภายในองค์กรได้?  โดยมีคุณสมบัติดังนี้

  • สามารถยืนยันตัวตนผู้ลงลายมือชื่อได้ว่าเป็นตัวจริง (ไม่ใช่เอกสารที่ใครก็ได้เอาภาพลายเซ็นผู้บริหารไปแปะ โดยผู้บริหารหรือเจ้าของลายเซ็นอาจไม่ยินยอม)
  • ใช้เวลาในการลงลายมือชื่อเอกสารจำนวนมากภายในเวลาไม่นาน
  • สามารถใช้ระบบอัตโนมัติในการตรวจสอบลายเซ็นในเอกสารจำนวนมาก ๆ ได้ในเวลาหลักวินาที
  • เสียค่าใช้จ่ายในการบริหารจัดการน้อย (ไม่ต้องซื้อซอฟต์แวร์ราคาแพง ๆ มาใช้) และไม่เสียเงินตามจำนวนผู้เซ็นเอกสารที่มากขึ้น 
  • ใช้งานง่าย หลังจากการติดตั้งระบบต่าง ๆ และทำความเข้าใจเรียบร้อยแล้ว

หลายคนอาจจะยังไม่รู้ว่าประเทศไทย เรามี พ.ร.บ. ว่าด้วยธุรกรรมทางอิเล็กทรอนิกส์ พ.ศ. 2544 ที่แก้ไขเพิ่มเติม (ฉบับที่ 3) พ.ศ. 2562 สรุปเป็นภาษาเข้าใจง่าย ๆ ลายมือชื่ออิเล็กทรอนิกส์ “ตามกฏหมาย” แบ่งออกเป็น 2 ประเภทหลัก ๆ คือ

  1. มาตรา 9: ลายมือชื่อแบบ (ง่าย ๆ) ทั่วไป อันนี้รวมถึง การพิมพ์ชื่อตัวเองลงไปท้ายอีเมลหรือเอกสาร, การกดปุ่ม “ยอมรับ”, การติ๊กถูกลงไปกล่อง “ยินยอม…” หรือการ ใส่รูปลายเซ็นลงไปในเอกสาร พวกนี้ก็เสมือนกับว่า เราลงลายเซ็นไปแล้ว!
  2. มาตรา 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 ส่วนได้แก่

  1. สร้างกุญแจลับและ Internal Root CA ขององค์กร ที่คู่กัน
  2. สร้างกุญแจลับและ (Leaf) Certificate ของพนักงานแต่ละคน ที่คู่กัน
  3. วิธีการใส่ลายเซ็นดิจิทัลลงในเอกสาร PDF ของพนักงานแต่ละคน
  4. วิธีการตรวจสอบว่าลายเซ็นดิจิทัลนั้น ถูกเซ็นมาโดยเจ้าของลายเซ็นตัวจริง

มาเริ่มกันเลยดีกว่า

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/emailAddress=pentest@sth.sh" -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="p.morimoto@sth.sh"
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 ถูกเซ็นรับรองมาด้วยลายเซ็นดิจิทัลหรือเปล่านั้น สามารถอ้างอิงได้จากรูปด้านล่างนี้

  1. ในไฟล์เอกสาร (เอกสาร.pdf) จะมีส่วนของเนื้อหาไฟล์ PDF ปกติ และส่วนของลายเซ็นดิจิทัล รวมอยู่ในไฟล์เดียวกัน
  2. เมื่อโปรแกรม Adobe Reader จะทำการตรวจสอบ ขั้นแรกจะนำ คนรับรองของ “ใบรับรองของลายเซ็น” นั้นไปตรวจสอบก่อนว่า ถูกรับรองมาโดยคนที่น่าเชื่อถือใช่ไหม (เป็น CA ที่ถูกติดตั้งเป็นค่าเริ่มต้น หรือใส่ไปเพิ่มเติมในโปรแกรมหรือในคอมพิวเตอร์เครื่องนั้น) 
  3. ถ้าใช่ก็จะนำ “กุญแจสาธารณะ” ของ “ใบรับรองของลายเซ็น” นั้นไปใช้ถอดรหัสค่า Hash (SHA-256) ที่ถูกเข้ารหัสด้วยกุญแจลับที่คู่กันแต่ไม่ได้ฝังมา และเซ็นเก็บไว้ว่าค่า Hash ที่จะถูกถอดรหัสนี้แหละเป็นของเอกสารจริง (เพราะคนที่สร้างมามีกุญแจลับ ของใบรับรองของลายเซ็น)
  4. จากนั้นคำนวณค่า Hash เดียวกันจาก เนื้อหาเอกสาร PDF ปกติ
  5. สุดท้ายนั้นค่า 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": "pentest@sth.sh",
        "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 ดังกล่าวนั้นเอง