收到 TWCA 換證通知後怎麼自己換:找原金鑰、合併新憑證、裝上伺服器、確認換好

本文整理收到 TWCA 換證通知後,把新憑證換上去的步驟,寫給單位裡沒有專職 IT 的人。通知信附件的 zip 裡只有新憑證,沒有金鑰。開始前要先找到兩樣東西:當初申請時產生的原金鑰,以及能登入放網站那台伺服器的人,缺了其中一樣就裝不上去。

TWCA 10 月 31 日的公告說原中繼憑證要在 11 月 6 日 00:00 前廢止,沒寫時區。11 月 5 日的公告接著寫,預計自 11 月 6 日零時起,廢止序號未符合亂數規範要求的網站憑證,同樣沒寫時區與受影響名單。依 RFC 5280 的路徑驗證規則,憑證被撤銷就驗不過,標準裡沒有寬限期,也沒有向簽發者申請延期的步驟。過了期限還沒換的網站,補救方式和期限前一樣,就是照這篇把新憑證換上去。至於各家瀏覽器多快查到撤銷、警告長什麼樣,公告沒寫,本文也沒測。換證的原因,TWCA 自己的說法是為了讓憑證序號的亂數符合 CA/Browser Forum 規範,並稱不是網站遭入侵或私鑰外洩引發;序號問題與 Bugzilla 紀錄另見〈去年中華電信,今年 TWCA:中繼憑證 11 月 6 日廢止前該檢查什麼〉。本文資料查核至 2026 年 11 月 5 日 04:26(台北時間),19:30 補查。

更新(2026-11-05 20:15):補上 TWCA 11 月 5 日公告的網站憑證廢止時程與更新進度,以及金管會的金融業進度。安裝步驟改為連到各家官方文件。資料查核 Claude,精簡 Claude Fable,Codex(gpt-6-astra)二審,Grok 調語氣。

通知信在講什麼

網站用 HTTPS 時,伺服器會送一疊憑證給瀏覽器:第一張是站台憑證,後面接簽發它的中繼,一路接到瀏覽器內建信任的根憑證。這一疊就是「憑證鏈」,網址列的鎖頭是這條鏈驗證通過的結果。鏈沒接齊,有的瀏覽器會對同一張憑證報警告,見 nginx〈Configuring HTTPS servers〉的 SSL certificate chains 一節。

TWCA 這次換的是中間那幾張。部署頁列出的新鏈,由上往下是 TWCA Global Root CA(根憑證)、TWCA CYBER Root CA、TWCA CYBER Root CA G3 Cross Cert、TWCA SSL Certification Authority 或 TWCA EVSSL Certification Authority(依申請類型二選一),最後是你的站台憑證。中繼換了,站台憑證也重簽了一張,這就是 zip 裡的東西。UserGuide 寫:「zip 檔中只有『重新簽發新憑證』,沒有金鑰,不能直接安裝到伺服器。」

為什麼一定要原本的金鑰?憑證裡放的是公鑰,伺服器要拿成對的私鑰才能證明自己是憑證上那個網站。依 UserGuide,TWCA 這次用原本的憑證申請檔(CSR)重簽,所以新憑證對應的還是當初那把私鑰;私鑰在你這邊的哪裡,TWCA 的文件答不了,下一節講怎麼找。

部署頁另外提醒兩件事。有把憑證鏈寫進 App 或主機的,要提早部署新鏈,機制見 Android〈Network security configuration〉。新鏈不再支援 clientAuth,也就是伺服器反過來跟瀏覽器要憑證,有用到的要另外向 TWCA 申請 AP 憑證,說明見 Tomcat〈SSL/TLS Configuration How-To〉。不確定自家有沒有,問當初做 App 或系統的人。

先找三樣東西:伺服器、登入帳號、原本的金鑰

伺服器在哪裡

憑證要裝在對外收 HTTPS 的那台機器上,收通知信的個人電腦只是跑工具的地方。那台機器可能在自家機房、主機代管商、雲端帳號裡,或是外包廠商架的。通知信寄給原申請人,zip 檔名是統一編號,先問當初是誰申請的;再看網站每月付費給誰。網域 DNS 指向誰的機器也是線索,沒有網域後台帳號就跳過。Tomcat 這類程式若排在 Apache 或 IIS 後面,處理 SSL 的是前面那台,Tomcat 文件有寫。網站前面若有 CDN 或負載平衡器終止 TLS,瀏覽器看到的是它的憑證。受影響的 TWCA 憑證可能在這一層、在後面的來源站,或兩邊都有。這兩段連線差在哪裡,見 Cloudflare〈SSL/TLS concepts〉。不確定有沒有這一層就先往下做,「伺服器是哪一種」那節有時看得出來。

誰能登入

TWCA 的工具在你自己的電腦上跑,合併出新檔;把新檔裝上去要有人能登入伺服器:Windows 要遠端桌面或 IIS 管理員的權限,Linux 要有 SSH 帳號加上改設定、重啟服務的權限。單位裡沒人有這些,先找當初的管理員、外包廠商或代管商。若由外包維護,先確認對方是否仍有管理權限。這一步沒解,憑證檔準備得再齊也裝不上。先告訴主管,再決定要不要繼續準備檔案。

原本的金鑰

UserGuide 接受三種檔案,手上有哪一種就用哪一種:

  • .key(有時是 .pem):當初產生 CSR 時一起產生的金鑰檔。
  • .pfx 或 .p12:IIS、Windows 常見,檔案裡必須含原本的金鑰。
  • .jks 或 .keystore:Java、Tomcat 的金鑰庫,同樣必須含原本的金鑰。

去哪裡找,看伺服器種類:

  • Nginx:請能登入的人在伺服器上(不是收信的電腦上)打 grep -r ssl_certificate_key /etc/nginx/,那一行指著的檔就是私鑰。
  • Apache:設定裡 SSLCertificateKeyFile 指著的檔就是私鑰。
  • IIS:私鑰在 Windows 憑證存放區裡,沒有獨立檔案,要匯出含私鑰的 PFX 並設密碼,步驟見 Microsoft〈Export a certificate with its private key〉(本文沒有 Windows 環境,未實測);沒人做過就把這份文件交給代管商一起做。
  • Tomcat:server.xml 裡 certificateKeystoreFile 指著的 JKS 或 PKCS12 檔。

幾種常見狀況:

  • 手上只有 .cer 或 .crt:那是憑證檔,沒有私鑰,UserGuide 的錯誤訊息「檔案中找不到私鑰」就是指這個。
  • 密碼忘了:UserGuide 要求用 PFX、JKS 的人準備舊檔密碼,.key 當初沒設就不用。密碼遺失,UserGuide 說請洽系統管理員,也就是前面找的那些人;OpenSSL 文件裡沒有把忘掉的密碼算回來的步驟。
  • 還沒找到、也不確定是不是已經遺失(包括密碼問不到人):先問管理員或維護廠商,確認新憑證正常運作前,舊檔一律不要刪。
  • 確定原金鑰遺失:UserGuide 說本次沿用原金鑰,沒有原金鑰就用不了新憑證,請聯絡 TWCA 客服,改以新金鑰產生的 CSR 重新申請,要時間,越早確認越好。

伺服器是哪一種

看原本的檔案類型大致猜得到。UserGuide 把 PFX 對應到 IIS、Windows Server、Exchange 與 F5、FortiGate 等設備,JKS 對應到 Tomcat、WebLogic、WebSphere、JBoss 等 Java 系統,PEM 對應到 Nginx 與 Apache 2.4.8 以上。要從外面看,在自己的電腦打開終端機跑下面這行(www.example.test 換成自己的網址),看回應裡有沒有寫伺服器種類:

curl -sI https://www.example.test/ | grep -i '^server:'

實測(curl 8.7.1):TWCA 官網回 Server: Apache,數發部網站回 server: cloudflare,中華郵政網站沒有回這個欄位。cloudflare 這類值代表前面有 CDN,看不出後面的伺服器;沒有這個欄位也可能是連線本身出錯,-s 會把錯誤訊息藏起來。看不出來就回頭問人。

路線 A:Windows 電腦加 TWCA 置換工具

這條路是 TWCA 提供的,以下依 UserGuide 整理。本文沒有 Windows 環境,工具本身沒有實測。

準備三樣:通知信的 zip(整包存到電腦,不用解壓縮)、舊的金鑰或憑證檔(上面三種擇一)、舊檔密碼。CertReplaceTool.zip 和 UserGuide 從部署頁下載,和通知信的 zip 是兩個不同的檔。CertReplaceTool.zip 完整解壓縮到任一資料夾,雙擊 CertReplaceTool.exe。出現「Windows 已保護您的電腦」時,UserGuide 說點「其他資訊」再「仍要執行」。這是 Microsoft SmartScreen 的提示,由來見〈SmartScreen reputation〉。執行前先確認 exe 是從 TWCA 部署頁下載的。UserGuide 表示工具完全在本機執行,不會上傳任何檔案或密碼,這是 UserGuide 的聲明,本文沒有驗證。

畫面由上而下五個步驟:

  1. 選通知信的 zip。畫面會顯示統一編號(zip 檔名)、公司名稱、網域、有效期間與簽發 CA,確認是自家網站,不對就停下來聯絡 SSLCC@twca.com.tw。
  2. 三擇一選舊檔,輸入舊檔密碼,.key 沒密碼可留空;JKS 內的私鑰另有密碼時,轉換中會再跳窗問。輸出 PEM 時工具會檢查金鑰與新憑證是否成對。
  3. 根憑證。UserGuide 說系統管理員要求「完整憑證鏈(含根憑證)」時才選,選錯可按「清除」;沒人要求就不用選,伺服器一般不必送根憑證,瀏覽器的信任庫裡就有。
  4. 輸出格式與新檔密碼。原本用 PFX 就選 PFX,JKS 就選 JKS,Nginx 和 Apache 選 PEM。PEM 是站台憑證加中繼的單一檔(fullchain),不含金鑰,不需要密碼。PFX 與 JKS 的新檔密碼至少 6 個字元,輸入兩次,可按「同舊檔密碼」,安裝時會用到。PFX 的加密方式由工具決定:舊檔是 PFX 就沿用,舊檔是 .key 或 JKS 則「使用與 Windows 預設相同且相容舊版 Windows 的方式」。
  5. 存檔位置,預設和 zip 同一資料夾。按「開始轉換」,工具會檢查金鑰與新憑證是否成對、憑證鏈是否完整,產生後重新讀取確認。成功畫面顯示新檔位置、憑證名稱、有效期間與憑證鏈,JKS 的別名(alias)要用畫面上顯示的名稱。

轉換完成後,舊的金鑰、PFX、JKS 保留,確認新憑證正常前不要刪。新檔和密碼交給裝伺服器的人;含私鑰的 PFX 或 JKS 先講好交給誰、怎麼交,不要用公開群組或一般信件寄。

安裝方式 UserGuide 也有寫,四項都在伺服器上做,不是在跑工具的個人電腦上。若是別人登入,就把新檔、密碼和這四項一起交出去:

  • IIS:IIS 管理員的「伺服器憑證」匯入新 PFX,再到網站的「繫結」把 https 改用新憑證,匯入 PFX 的步驟見 Microsoft〈Import a Server Authentication Certificate〉,HTTPS 繫結的畫面見〈How to Set Up SSL on IIS〉。
  • Nginx:ssl_certificate 改為工具產生的 fullchain.pem,ssl_certificate_key 沿用原本的 .key 不用換,nginx -t 通過後 nginx -s reload,實測輸出見下面「Nginx」一節。
  • Apache 2.4.8 以上:SSLCertificateFile 改為「憑證 CN_fullchain.pem」,SSLCertificateKeyFile 不用換,原本若有 SSLCertificateChainFile 務必註解掉,這個指令 2.4.8 起已淘汰,見 Apache〈mod_ssl〉。
  • Tomcat:server.xml 裡的 keystore 指向新 JKS 或 PFX,更新密碼後重新啟動,alias 用成功畫面上的名稱,設定項見 Tomcat〈HTTP Connector〉。

路線 B:沒有 Windows,或想用指令自己做

macOS 內建 LibreSSL(/usr/bin/openssl),Linux 多半有 OpenSSL。下面的 openssl 指令在自己的電腦上打:打開終端機,進到一個新的空目錄。改 Nginx 或 Apache 是後面的事,要登入伺服器才做。這一節整理用 OpenSSL 比對金鑰、轉成 PEM、組憑證鏈與做 PFX,JKS 不在實測範圍,需要 JKS 就回路線 A 用 TWCA 的工具。標明「實測」的指令與輸出,是 2026 年 11 月 5 日 03:48 到 04:26 在 macOS(LibreSSL 3.3.6、Homebrew OpenSSL 4.1.0)與 Ubuntu(OpenSSL 3.0.13、nginx 1.24.0)跑出來的;站台憑證與金鑰是測試 CA 簽的模擬檔,TWCA 的中繼憑證是部署頁下載的真檔。

先準備:新的工作目錄與備份

正式動手前先做三件事,這是一般做法,沒有逐條實測:

  • 開一個新的空目錄放這次的檔案,不要在伺服器現用的憑證目錄裡改。
  • 現用的憑證檔、金鑰檔與設定檔各複製一份,記下原本路徑,出問題才換得回去。
  • 原金鑰只讀不寫:下面的指令都只讀取它,新產生的檔案一律用新檔名,不覆蓋原檔。

想先演練的,在另一個空目錄用這支腳本產生測試檔:new.crt、server.key,和一把配錯的 other.key。腳本會產生新金鑰,只能在演練目錄裡跑,不要在放原金鑰的目錄執行:

#!/bin/sh
# Practice files only: a test CA, a test site certificate and keys. Not for production.
set -eu
O="${OPENSSL:-openssl}"
$O req -x509 -newkey rsa:2048 -nodes -keyout root.key -out root.pem -days 30 -subj "/CN=Test Root" 2>/dev/null
$O req -newkey rsa:2048 -nodes -keyout int.key -out int.csr -subj "/CN=Test Intermediate" 2>/dev/null
printf 'basicConstraints=critical,CA:true\nkeyUsage=critical,keyCertSign,cRLSign\n' > ca.ext
$O x509 -req -in int.csr -CA root.pem -CAkey root.key -CAcreateserial -out int.pem -days 30 -extfile ca.ext 2>/dev/null
$O req -newkey rsa:2048 -nodes -keyout server.key -out server.csr -subj "/CN=www.example.test" 2>/dev/null
printf 'subjectAltName=DNS:www.example.test\nextendedKeyUsage=serverAuth\n' > leaf.ext
$O x509 -req -in server.csr -CA int.pem -CAkey int.key -CAcreateserial -out new.crt -days 30 -extfile leaf.ext 2>/dev/null
$O genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out other.key 2>/dev/null

實測時在 mktemp -d 開出的空目錄執行,跑完多了 new.crt、server.key、other.key、int.pem、root.pem 等檔案。演練時直接用這些檔名;正式操作時先把通知信的 zip 解開,new.crt 改成裡面新憑證的檔名,server.key 改成原金鑰的路徑。新憑證的檔名和它是 DER 還是 PEM,TWCA 的文件沒寫,用下一節確認。

把要串進憑證鏈的檔案都轉成 PEM

憑證檔有兩種常見編碼:PEM 是文字檔,開頭是 -----BEGIN CERTIFICATE-----;DER 是二進位檔。副檔名看不出差別:部署頁的五個 .cer 裡,TWCA CYBER Root CA.cer 是 DER,其他四個是 PEM;zip 裡那張新憑證是哪一種,TWCA 的文件沒寫(需驗證)。

工具版本不同反應也不同。實測時 OpenSSL 4.1.0 不指定格式也能讀這個 DER 檔,明確指定 -inform PEM 才讀不出來;LibreSSL 3.3.6 不加 -inform DER 就直接失敗:

unable to load certificate

所以「讀得出來」不等於「是 PEM」。要確認是不是 PEM,用 -inform PEM 明確指定去讀,讀得出來才是:

openssl x509 -inform PEM -in new.crt -noout -subject

讀不出來,就當 DER 轉一份 PEM,輸出到新檔名,原檔不動:

openssl x509 -inform DER -in TWCA_CYBER_Root_CA.cer -out TWCA_CYBER_Root_CA.pem

這條在 LibreSSL 3.3.6 與 OpenSSL 4.1.0 實測都轉得出來,轉完再用 -inform PEM 讀一次確認。所有要串進憑證鏈的檔案,包括 zip 裡的新憑證,都先確認是 PEM 再用。

確認原金鑰和新憑證成對

把憑證裡的公鑰和金鑰算出的公鑰各做一次雜湊,比對兩行:

openssl x509 -in new.crt -noout -pubkey | openssl sha256
openssl pkey -in server.key -pubout | openssl sha256

實測輸出(OpenSSL 4.1.0),兩行相同:

SHA2-256(stdin)= 6de5d1f3996c5975abe0fbc2a51080aa3482bb870ceb02ca95cbad48618bd127
SHA2-256(stdin)= 6de5d1f3996c5975abe0fbc2a51080aa3482bb870ceb02ca95cbad48618bd127

拿配錯的 other.key 算,第二行變成別的值:

SHA2-256(stdin)= 9fbae34166da61daeeedb1cc43b9b201811acce5c5052570efff6bd7028c94d5

LibreSSL 3.3.6 只印雜湊、不印前綴,兩行同樣是:

6de5d1f3996c5975abe0fbc2a51080aa3482bb870ceb02ca95cbad48618bd127

兩行相同之前,先確認兩條指令都沒有印錯誤訊息:檔案讀不到時,openssl 會印錯誤,後面的 sha256 卻照樣對空內容算出一個值,兩邊還會一樣。實測(OpenSSL 4.1.0,兩個檔都不存在):

Could not open file or uri for loading certificate from missing.crt: No such file or directory
SHA2-256(stdin)= e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Could not open file or uri for loading private key of key from missing.key: No such file or directory
SHA2-256(stdin)= e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

e3b0c442 開頭的值是空內容的雜湊,看到它就表示前一步失敗,兩行相同也不算成對。兩行不同,表示這把金鑰和 zip 裡的憑證對不上,可能是別的網站的金鑰,或 zip 不是這次通知信的附件。.key 有密碼時,openssl pkey 會停下來問,輸入時畫面不顯示字是正常的,打完按 Enter,後面問 PFX 密碼時也一樣。

手上只有舊 PFX 的,不必把私鑰取出來。這次換發沿用原金鑰,舊 PFX 裡的憑證和新憑證的公鑰應該相同,比對這兩個就好:

openssl pkcs12 -in old.pfx -nokeys -clcerts | openssl x509 -noout -pubkey | openssl sha256
openssl x509 -in new.crt -noout -pubkey | openssl sha256

第一條會先問 PFX 密碼。實測時用同一把測試金鑰做了一個 old.pfx,以 -passin 帶入密碼,兩行都是下面這個值(這次演練重新產生了金鑰,所以和上面的雜湊不同):

SHA2-256(stdin)= ec23ca974da08575800ea508b1ca26bd7ee86b0c97b3b28a5af2ce696d0041e0

組 fullchain

先看新憑證是誰簽的,決定要接哪一張中繼:

openssl x509 -in new.crt -noout -issuer

印出 TWCA SSL Certification Authority 就接一般 SSL 那張,TWCA EVSSL Certification Authority 就接 EV 那張。後面的順序照已經換好新鏈的網站實際送出的內容排:2026 年 11 月 5 日 03:49 用 openssl s_client -showcerts 看 www.twca.com.tw、www.moda.gov.tw、www.post.gov.tw,三站都送 4 張。下面是 www.moda.gov.tw 的實測輸出(OpenSSL 4.1.0,只留 s: 與 i: 行):

 0 s:C=TW, ST=Taiwan, L=Taipei, O=Ministry of Digital Affairs, CN=*.moda.gov.tw
   i:C=TW, O=TAIWAN-CA, CN=TWCA SSL Certification Authority
 1 s:C=TW, O=TAIWAN-CA, CN=TWCA SSL Certification Authority
   i:C=TW, O=TAIWAN-CA, CN=TWCA CYBER Root CA G3
 2 s:C=TW, O=TAIWAN-CA, CN=TWCA CYBER Root CA G3
   i:C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA CYBER Root CA
 3 s:C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA CYBER Root CA
   i:C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA Global Root CA

第一張是站台憑證。三站都沒送 TWCA Global Root CA 本身,它在瀏覽器的信任庫裡,macOS 的系統根憑證庫就有。所以 fullchain 依序是站台憑證、SSL 或 EVSSL CA、G3 Cross Cert、CYBER Root CA 四張,全部先轉成 PEM。先從部署頁把要用的中繼下載到這個目錄,DER 的照上一節轉成 PEM。下面的檔名是部署頁檔名把空格換成底線、副檔名改成 .pem,實際檔名不同就用實際的,輸出用新檔名:

cat new.crt TWCA_SSL_Certification_Authority.pem TWCA_CYBER_Root_CA_G3_Cross_Cert.pem TWCA_CYBER_Root_CA.pem > fullchain-new.pem
openssl crl2pkcs7 -nocrl -certfile fullchain-new.pem | openssl pkcs7 -print_certs -noout

第二條會列出檔案裡每張憑證的 subject 與 issuer。實測時第一張是測試站台憑證,所以 issuer 是 Test Intermediate;正式操作時這裡應該是 TWCA SSL 或 EVSSL Certification Authority,四張依序由下一張簽發:

subject=CN=www.example.test
issuer=CN=Test Intermediate

subject=C=TW, O=TAIWAN-CA, CN=TWCA SSL Certification Authority
issuer=C=TW, O=TAIWAN-CA, CN=TWCA CYBER Root CA G3

subject=C=TW, O=TAIWAN-CA, CN=TWCA CYBER Root CA G3
issuer=C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA CYBER Root CA

subject=C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA CYBER Root CA
issuer=C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA Global Root CA

這份清單只說明檔案裡有哪幾張、順序如何,不代表驗證通過,驗證用 openssl verify。演練檔只有一張中繼,實測指令與輸出:

openssl verify -CAfile root.pem -untrusted int.pem new.crt
new.crt: OK

真的 TWCA 鏈也驗過:Global Root 當信任根,CYBER Root CA(PEM)和 G3 Cross Cert 當中繼,驗 SSL CA 那張,OpenSSL 4.1.0 與 LibreSSL 3.3.6 的實測輸出都是:

cat TWCA_CYBER_Root_CA.pem TWCA_CYBER_Root_CA_G3_Cross_Cert.cer > untrusted.pem
openssl verify -CAfile TWCA_Global_Root_CA.cer -untrusted untrusted.pem TWCA_SSL_Certification_Authority.cer
TWCA_SSL_Certification_Authority.cer: OK

驗自己的站台憑證時,把 SSL 或 EVSSL CA 也加進 untrusted.pem,最後一個參數換成新憑證,成功時預期會印 OK。本文手上沒有真的 TWCA 站台憑證,這一步未實測。

Nginx

登入伺服器後先找現用的設定在哪一行,下面這行實測時是對測試設定檔跑的,路徑以印出來的為準:

grep -r ssl_certificate_key /etc/nginx/

把 fullchain-new.pem 複製到伺服器,更新憑證路徑,私鑰路徑維持指向原檔,下面的路徑只是例子:

ssl_certificate     /etc/nginx/ssl/fullchain-new.pem;
ssl_certificate_key /etc/nginx/ssl/server.key;

改完先 nginx -t。金鑰配錯時,nginx 1.24.0 實測會直接擋下來:

[emerg] ... SSL_CTX_use_PrivateKey(".../other.key") failed (SSL: error:05800074:x509 certificate routines::key values mismatch)
nginx: configuration file .../nginx.conf test failed

配對時:

nginx: the configuration file .../nginx.conf syntax is ok
nginx: configuration file .../nginx.conf test is successful

nginx -t 通過才 nginx -s reload,實測 reload 後 error log 只有一行 signal process started;沒過就不要 reload,改回備份的設定。nginx 文件提醒私鑰檔要限制權限,但 master process 得讀得到。

IIS:做一個 PFX

IIS 要的是含私鑰的 PFX。先把三張中繼串成一個檔,再把金鑰、新憑證和中繼包在一起,過程會問新檔密碼:

cat TWCA_SSL_Certification_Authority.pem TWCA_CYBER_Root_CA_G3_Cross_Cert.pem TWCA_CYBER_Root_CA.pem > intermediates.pem
openssl pkcs12 -export -inkey server.key -in new.crt -certfile intermediates.pem -out new.pfx

實測用演練檔跑(-certfile int.pem)。OpenSSL 4.1.0 預設的加密方式,用 openssl pkcs12 -in new.pfx -info -noout 看,實測輸出的前幾行:

MAC: sha256, Iteration 2048
MAC length: 32, salt length: 16
PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256

部分 Windows 版本匯入不了這種 PFX。Microsoft 的疑難排解文件寫,受影響的 Windows 與 Windows Server 不支援以 AES256-SHA256 加密的 PFX,匯入時會出現類似「The password you entered is incorrect」的訊息,因應方式是改用 TripleDES-SHA1,較新的版本兩種都支援;那頁沒有逐一列出受影響的版本,黑暗執行緒的部落格(個人技術 blog,2024 年 5 月 11 日)記錄的是 Windows Server 2012 R2 與 2016。先確認自家 Windows 的版本,匯入出現這個錯誤再改做 3DES 版本:

openssl pkcs12 -export -inkey server.key -in new.crt -certfile intermediates.pem -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -macalg sha1 -out new-legacy.pfx

用演練檔實測做得出來,-info 的前幾行:

MAC: sha1, Iteration 2048
MAC length: 20, salt length: 16
PKCS7 Encrypted data: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048

本文沒有 Windows 可測,兩種 PFX 都沒有實際匯入過;匯入與繫結照路線 A 的 IIS 那條。

反過來,只有含私鑰的舊 PFX、又要給 Nginx 用,才需要把金鑰取出來。-nodes 會輸出沒加密的私鑰,所以先限制權限,輸出到新檔名:

(umask 077; openssl pkcs12 -in old.pfx -nocerts -nodes -out old-key.pem)

實測(macOS、OpenSSL 4.1.0)產生的檔案權限是 -rw-------,只有自己能讀,算出的公鑰雜湊和原金鑰一樣。取出的金鑰放在限制存取的目錄,用完的副本刪掉;只是要比對成對,用上面「手上只有舊 PFX」那兩行就夠。

Apache 與 Tomcat

Apache 2.4.8 以上照路線 A 那條改,SSLCertificateFile 指向 fullchain-new.pem,改完先跑 apachectl configtest(見 Apache〈apachectl〉),通過才 reload。Apache 文件寫私鑰檔應只有 root 可讀,見〈SSLCertificateKeyFile〉。Tomcat 支援 PKCS12,使用前要依現場的 Tomcat 與 Java 版本核對 keystore 型別、密碼與 alias,見 Tomcat〈SSL/TLS Configuration How-To〉。server.xml 的 keystore 型別、密碼與 certificateKeyAlias 依〈HTTP Connector〉核對,新做的 PFX 不一定有原設定的 alias。Apache 與 Tomcat 本文都沒有跑過,keytool 做 JKS 也沒測。不確定就把新檔、密碼和 alias 交給維護的人,reload 或重啟的指令依各家文件。

確認換好了

  • 瀏覽器開網站,點網址列的鎖頭,看有效期間是不是新憑證的,這是 UserGuide 給的檢查;沒有鎖頭就跳過,改做下面幾項。
  • 到 TWCA 的 SSL 憑證檢測頁輸入網站名稱查一次,部署頁有連結。
  • 從外面驗證伺服器送出的鏈,並確認網站名稱對得上:-servername 只告訴伺服器要哪個網站,-verify_hostname 才檢查憑證上的名稱。下面是對 www.moda.gov.tw 的實測指令與輸出,查自己的網站時把三處網址換成自己的網域:
openssl s_client -connect www.moda.gov.tw:443 -servername www.moda.gov.tw -verify_hostname www.moda.gov.tw </dev/null

實測(OpenSSL 4.1.0,2026 年 11 月 5 日 04:26)輸出的最後是:

Verification: OK
Verify return code: 0 (ok)

故意把 -verify_hostname 換成別的名稱,同一個站回的是:

Verify return code: 62 (hostname mismatch)

LibreSSL 3.3.6 對同一站也回 Verify return code: 0 (ok)。這幾條指令都沒有檢查撤銷狀態。

  • 確認上線的是新憑證:把網站送出的第一張憑證和 zip 裡的新憑證各印出序號比對,www.moda.gov.tw 換成自己的網域,new.crt 換成 zip 裡的新憑證:
openssl s_client -connect www.moda.gov.tw:443 -servername www.moda.gov.tw </dev/null 2>/dev/null | openssl x509 -noout -serial -enddate -issuer
openssl x509 -in new.crt -noout -serial -enddate -issuer

數發部網站的實測輸出:

serial=47EA00000009B606E581A8DE645A11FE
notAfter=Dec 16 15:59:59 2026 GMT
issuer=C=TW, O=TAIWAN-CA, CN=TWCA SSL Certification Authority

兩條印出的 serial 相同,才表示新憑證真的上線了。Ubuntu 的 nginx 演練裡,網站送出的 serial 和 new.crt 實測一致。

  • 演練環境(127.0.0.1:8443,以 -CAfile root.pem 指定測試根)裡,只放站台憑證、沒放中繼時回 Verify return code: 21 (unable to verify the first certificate),放了 fullchain 回 0 (ok):
 0 s:CN = www.example.test
Verify return code: 21 (unable to verify the first certificate)
 0 s:CN = www.example.test
   i:CN = Test Intermediate
 1 s:CN = Test Intermediate
   i:CN = Test Root
Verify return code: 0 (ok)
  • 網站前面有 CDN 或負載平衡器、由它終止 TLS 的,瀏覽器和 s_client 看到的都是前端那張憑證。實測時數發部網站回應標頭的 Server 是 cloudflare,就是這種情況。前端連到來源站若另有 HTTPS,來源站用的是不是受影響的憑證要另外查,從外面確認不了兩段。
  • App 有綁憑證鏈的,用新版 App 連一次;系統用到 clientAuth 的,照部署頁找 TWCA 問 AP 憑證。這兩種本文沒有測。

出錯的時候

錯誤訊息出現的地方有三個:TWCA 工具的畫面、伺服器自己的記錄、瀏覽器顯示給訪客看的頁面,三處的字不一樣,打客服前先弄清楚錯誤出現在哪裡。

工具畫面的訊息,UserGuide 第 5 節有對照:

  • 「舊金鑰與 zip 檔內的新憑證不相符」:選到別的網站的金鑰或舊檔,或 zip 不是這次通知信的附件。確認網域相同,或改用伺服器上目前使用中的 PFX、JKS。
  • 「舊檔密碼錯誤」:確認大小寫、全形半形,密碼遺失照「原本的金鑰」那節處理,舊檔不要刪。
  • 「此金鑰檔有密碼保護」:在「舊檔密碼」輸入 .key 的密碼。
  • 「檔案中找不到私鑰」:選到憑證檔(.cer、.crt),沒選到金鑰檔。
  • 「舊檔中沒有私鑰」:這個 PFX 或 JKS 只有憑證,改選伺服器上正在使用、含金鑰的那一份。
  • 「zip 檔內找不到任何憑證檔」:確認選的是通知信的原始附件。
  • 「根憑證與此憑證鏈不符」:步驟 3 選錯檔。

伺服器端的訊息:

  • Nginx key values mismatch:金鑰與 ssl_certificate 檔裡第一張憑證不成對。可能是金鑰配錯(回到「確認原金鑰和新憑證成對」比一次),也可能是 fullchain 的順序排錯,第一張必須是站台憑證。
  • Verify return code: 21:本次測試裡出現這個碼,是因為伺服器只送了站台憑證、沒送中繼,常見情況是 ssl_certificate 還指著舊的單張憑證,或 fullchain 沒組好。其他情況也可能出現同一個碼,要配合完整訊息判斷。
  • Nginx 其他 [emerg]:nginx -t 會印出是哪一個檔,記錄檔位置見 nginx〈error_log〉;Apache 的記錄位置見〈Log Files〉。
  • Tomcat 啟動時若出現 keystore 密碼或 alias 錯誤,核對 server.xml 的 keystore 設定,見 Tomcat〈SSL/TLS Configuration How-To〉。IIS 說憑證沒有私鑰,要匯入的是含私鑰的 PFX,見 Microsoft〈IIS 憑證疑難排解〉。

要給客服或幫忙的人:網域、zip 檔名、伺服器種類與版本、做到哪一步、錯誤訊息的原文、記錄檔裡那幾行;不要附上私鑰、密碼或含私鑰的檔案,SSL Labs 的部署指南要私鑰少給人碰。客服收不收檔案、會不會代裝,TWCA 的文件沒寫,這篇也不猜,打電話時直接問。

打客服前寫在同一頁

  • 網域與 zip 檔名(統一編號)。
  • 網站放在哪、誰能登入、外包廠商或代管商的聯絡方式。
  • 原本的金鑰是哪一種檔案、放在哪、有沒有密碼。
  • 伺服器或設備的種類與版本。
  • 做到哪一步、哪一處出現什麼錯誤訊息(原文)。
  • 有沒有 App 綁憑證鏈、有沒有用到用戶端驗證(也就是前面的 clientAuth)。

聯絡 (02)2370-8886 分機 9 或 SSLCC@twca.com.tw 時,已知的直接說,還沒確認的註明還沒確認。

還沒釐清的事

  • 11 月 6 日 00:00 的時區、要廢止的舊中繼名單與指紋,公告仍沒寫。
  • zip 裡新憑證的檔案格式(DER 或 PEM)與檔名,TWCA 文件沒有公開說明,可以用「把要串進憑證鏈的檔案都轉成 PEM」那節的方法確認。
  • 在 macOS 或 Linux 執行置換工具的方式,部署頁與 UserGuide 都沒提。
  • 還有多少張沒換:TWCA 11 月 5 日公告說,截至當天 10:30,政府、金融及其他產業已有超過 85% 的客戶網站完成更新;金管會說金融機構約有 4,190 筆憑證,當天 14:30 約 95% 完成;數發部的政府端數字仍停在 11 月 2 日晚間的 926 張。民間企業沒有單獨的數字。
  • 要廢止的是哪些序號、自己那張在不在裡面,TWCA 11 月 5 日公告沒寫。
  • CA 憑證序號事件的完整報告,TWCA 在 Bugzilla 2087236 Comment 3 承諾於 11 月 12 日 19:00 UTC 前提交。

補充筆記

  • 通知信的 zip 只有新憑證,要配上當初產生 CSR 的原金鑰,還要有人能登入伺服器,缺一樣都裝不上。
  • 原金鑰的位置看伺服器種類:Nginx 看 ssl_certificate_key,Apache 看 SSLCertificateKeyFile,IIS 從憑證存放區匯出含私鑰的 PFX,Tomcat 看 server.xml 的 keystore。
  • 比對公鑰雜湊可確認金鑰和新憑證是否成對,但兩條指令都要沒有錯誤訊息,e3b0c442 開頭是空內容的雜湊;fullchain 依序接站台憑證、SSL 或 EVSSL CA、G3 Cross Cert、CYBER Root CA,全部先轉成 PEM。
  • 動手前先備份現用檔案,新檔一律用新檔名;Nginx 配錯金鑰會在 nginx -t 報 key values mismatch,通過才 reload。Apache、IIS、Tomcat 的安裝本文沒有實測,照 UserGuide 的四條與各家官方文件做。
  • 確認時用 -verify_hostname 檢查名稱,並比對網站送出的 serial 和新憑證相同;給 IIS 的 PFX 預設是 AES,部分 Windows 版本要 3DES,本文沒有在 Windows 上測。
  • 錯誤訊息分工具畫面、伺服器記錄、瀏覽器頁面三處;給客服的資料裡永遠不含私鑰與密碼。

延伸閱讀

想法與技術判斷出自 Sheng,和 Claude 一起起草 · 起草 Claude Fable,問題整理與官方文件查詢 Grok,Codex(gpt-6-astra)二審,Claude 補測與修訂,Claude Fable 精簡,Grok 調語氣;標明實測的指令在 macOS(LibreSSL 3.3.6、OpenSSL 4.1.0)與 Ubuntu(OpenSSL 3.0.13、nginx 1.24.0)執行,資料查核至 2026-11-05 04:26;19:30 補查 TWCA 公告與換證進度,指令沒有重跑。