前篇文章我們學會了用老牌的 MakeCert 建立自簽憑證 (self-signed certificates),對於大部分數位憑證的需求已經綽綽有餘,確實簡單易用。但是 MakeCert 在使用上有許多限制,例如他沒辦法簡單的「複製」(Clone) 現有已經過期的憑證 (每次都要輸入完整的參數重建)、無法設定 金鑰使用方法 (keyUsage)、無法建立 Subject Alternative Name (SAN) 多域名憑證等等。這篇文章我將介紹如何利用 Windows 內建的 New-SelfSignedCertificate Cmdlet 來建立自簽憑證。
文章開始前,我先示範一個使用自簽憑證的常見問題。
我們用瀏覽器測試一個 TLS/SSL 網站的時候,即便憑證已經成功加入到 "My" 憑證儲存區,網站伺服器也正確綁定伺服器憑證,但是你的瀏覽器就是會出現憑證無效的警告 ( NET::ERR_CERT_AUTHORITY_INVALID ),如下圖示:
如果你點擊 Google Chrome 的「瞭解詳情」就可以得到相對完整的說明。
如果從錯誤訊息來看 "NET::ERR_CERT_AUTHORITY_INVALID",很明顯這個憑證的問題出在 "CERT AUTHORITY" (CA) 無效,也就是 憑證授權單位無效 的意思。
我們前篇文章就有提到過,自簽憑證是一張由自己這張憑證所簽署的憑證,但在 PKI 架構下,所有憑證都必須經由「信任的根憑證」簽署過的憑證,才是有效憑證。所以「自簽憑證」預設永遠無法成為一張合法有效的憑證。
這時你可能會想,我如果把自簽憑證安裝到「受信任的根憑證授權單位」(Trusted Root CA) 不就好了?但是 IIS 下的網站站台在繫結 SSL 憑證的時候,預設只能選擇到註冊到 "My" 憑證儲存區下的憑證。畢竟「受信任的根憑證授權單位」的用途,主要就是用來做簽署其他憑證的用途,並不是拿來做伺服器驗證之用!
不過這個問題很好解決,你只要先將憑證安裝到 "My" 憑證儲存區下,然後匯出這張憑證的公開金鑰 ( 不需要匯出私密金鑰 ),再將該公開金鑰匯入到「受信任的根憑證授權單位」即可。我們馬上來試試如何操作:
1. 我先在本機 IIS 建立一個站台,網站名稱為 www.fabrikam.com
2. 建立一個名為 www.fabrikam.com 的憑證
MakeCert -n "CN=www.fabrikam.com" -ss My -r -pe -sr localmachine -a SHA256 -len 2048
請注意:Google Chrome 並不支援憑證使用 SHA1 這個簽章雜湊演算法。,所以我們要設定為 SHA256 才是合法有效的憑證,這部分在 IE 或 Edge 無此問題。
3. 此時你如果直接去看憑證資訊,就會看到這是一張無效的憑證,而且訊息很清楚的寫著【這個 CA 根憑證不受信任。如果你要啟用信任,請將這個憑證安裝到信任根憑證授權單位存放區。】
4. 我們先將該憑證匯出,並直接匯入受信任的根憑證授權單位。
你不需要匯出 私密金鑰 (Private Key):
你可以選擇 DER 編碼二位元 X.509 (.CER) 這項來當成公開金鑰的檔案格式
然後把金鑰儲存到任意資料夾。
最後匯入剛剛匯出的憑證到受信任的根憑證授權單位
此時請你驗證一下原本在「個人」( My ) 憑證儲存區下的憑證,是不是已經變成一張合法、有效的憑證。
請注意:確認你的憑證合法有效非常重要,並不是「自簽憑證」就不能享有「合法憑證」的權利。畢竟在瀏覽器下有許多 HTML5 功能,在沒有合法憑證的網站是完全無法運作的!
5. 接著就來設定 IIS 站台綁定這張憑證,並且開啟瀏覽器測試 HTTPS 連線。
這時你會發現,只有 Internet Explorer 與 Microsoft Edge 瀏覽器可以正常瀏覽網站,但是 Google Chrome 與 Firefox 怎樣都無法正常瀏覽網站!
先來談談 Firefox 瀏覽器
你點擊「更多資訊」會連到 排除在安全性網站上 "SEC_ERROR_UNKNOW_ISSUER" 的錯誤代碼 文件。
Firefox 真的很特別,在所有我用過的瀏覽器中,只有 Firefox 擁有自己的憑證管理員,擁有自己的 CA 憑證清單,所以即便在 Windows 作業系統下,Firefox 也不會去管 Windows 憑證管理員 中到底安裝了哪些 CA 根憑證,你必須在這邊手動匯入才行。不過,你建立的自簽憑證由於並沒有加上必要的擴充屬性 (extended attributes),所以 Firefox 為了安全考量,我們剛剛建立的憑證是無法匯入的。在我的前篇文章有提過,你在用 MakeCert 建立憑證時,要加入 -cy authority 參數,才能產生一個「合法」的 CA 憑證。但就算你用建立了一個可以匯入 CA 憑證的版本,Firefox 還是無法識別你的網站為有效憑證的,建議就直接「新增例外網站」來解決這個問題即可。
現在來談談 Google Chrome 瀏覽器
由於我們現在的憑證是合法有效的,所以這次出現的錯誤訊息不一樣了,這次是 NET::ERR_CERT_COMMON_NAME_INVALID 錯誤,意思是說 這張憑證的主體名稱無效 的意思。但這次要查問題就沒那麼簡單了,我花了好長一段時間才真正理解這個憑證問題的發生原因。
在古老的 2000 年推出了這麼一份 RFC 2818 - HTTP Over TLS 規格文件,明確規範 HTTP 要走 TLS 安全通訊的方法。規格中指出,要驗證一個使用 TLS/SSL 安全加密連線的網站伺服器憑證有兩種方法,第一種是從憑證的擴充屬性中取得 subjectAlternativeName (subjectAltName) (SAN) 屬性的設定;如果沒有這個擴充屬性的話,就會直接去找憑證中一定會有的 commonName (CN) 屬性,這裡的 CN 屬性就是所謂的 主體 名稱 (如下圖示)。
不過在 RFC 2818 也提到了,透過 commonName (CN) 的驗證方式已經 棄用 (deprecated)。沒錯,在 18 年前的規格中就說好不要再用了,所以 Google Chrome 決定從 Chrome 58 這個版本開始正式取消 commonName (CN) 的驗證方式,也因此我們用 MakeCert 所建立的自簽憑證因為無法加入 subjectAltName (SAN) 擴充屬性,所以永遠於法建立出一張可以給 Google Chrome 瀏覽器合法使用的伺服器憑證!
鋪陳了這麼久,終於要進入本篇文章的重點了!XD
我們可以利用 New-SelfSignedCertificate Cmdlet 來建立一個含有 subjectAltName (SAN) 擴充屬性的自簽憑證。例如我們直接從官網文件中看到的第一個範例,就非常簡單易用,直接可以產生一個含有 SAN 擴充屬性的憑證,並自動註冊到 "本機電腦" 的 "My" 憑證儲存區中。另一方面,我個人認為透過 PowerShell 來建立自簽憑證,最大的好處就是命令很清楚,不像 MakeCert 的參數那樣艱澀難懂。
現在,我們就重新再走一次憑證建立與設定的過程:
1. 先移除先前建立的 www.fabrikam.com 憑證,包含受信任的根憑證授權單位下的憑證。
2. 執行以下 PowerShell 命令,建立一個 SAN 憑證,加入 -DnsName 參數即可,而且可以一次設定多組網域名稱。這裡由於沒有特別指定 commonName (CN) 名稱,預設會直接用 -DnsName 參數的第一個項目當成憑證的主體名稱 ( a.k.a. commonName )。這裡的 -CertStoreLocation 參數是指憑證儲存區的路徑。
New-SelfSignedCertificate -DnsName "www.fabrikam.com", "www.contoso.com" -CertStoreLocation "cert:\LocalMachine\My"
# 你也可以加上 -FriendlyName 參數,指定一個 易記名稱 (Friendly Name),方便之後在 IIS 繫結憑證時可以容易識別哪一張憑證
New-SelfSignedCertificate -DnsName "www.fabrikam.com", "www.contoso.com" -CertStoreLocation "cert:\LocalMachine\My" -FriendlyName MySSL
請注意:如果要建立憑證在 "本機電腦",請記得 以系統管理員身分執行 Windows PowerShell 才行。
3. 匯出 www.fabrikam.com 憑證
4. 匯入 www.fabrikam.com 憑證到受信任的根憑證授權單位
5. 重新綁定 IIS 站台的 SSL 憑證
6. 回到 Google Chrome 重新整理網頁,照理說就可以看到 HTTPS 綠色安全的圖示了!
如果你測試用的自簽憑證到期了,透過 New-SelfSignedCertificate Cmdlet 的 -CloneCert 參數可以很方便的快速複製原本的憑證,所有憑證的參數與設定都會沿用,只有憑證的起訖時間會重設,所以重新產生憑證非常方便!也因為是重新產生憑證,所以憑證內的 公開金鑰 (Public Key) 也會是新的!
# 先進入 cert:\LocalMachine\My 憑證目錄
cd "cert:\LocalMachine\My"
# 列出所有憑證,找到憑證的憑證指紋 (Thumbprint)
dir
# 取得憑證 ( 底下 059...688 這個為實際查到的憑證指紋 )
$cert = dir -Path 059A8EEF4EECCBB24FD25C65E86A15212F8FD688
# 重新產生全新的憑證
New-SelfSignedCertificate -CloneCert $OldCert
以下則是一個相對複雜一點的命令:
New-SelfSignedCertificate -Type Custom -Subject "CN=Patti Fuller,OU=UserAccounts,DC=corp,DC=contoso,DC=com" -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.2","2.5.29.17={text}upn=pattifuller@contoso.com") -KeyUsage DigitalSignature -KeyAlgorithm RSA -KeyLength 2048 -CertStoreLocation "Cert:\CurrentUser\My"
1. 指定 -Type 可以用來指定憑證預設的 EKU (Extended Key Usage),合法的選項如下:
- SSLServerAuthentication (default)
- 不設定 -Type 預設就會選擇 伺服器驗證 (serverAuth) 與 用戶端驗證 (clientAuth)
- CodeSigningCert
- Custom
- 代表你想叫建立一個自定的 EKU 類別
- 設定為 Custom 必須搭配 -TextExtension 指定 EKU 的 OID
- DocumentEncryptionCert
- DocumentEncryptionCertLegacyCsp
2. 指定 -Subject 參數可以幫你設定憑證的主體資訊 (Subject),也就是我們在建立 CSR 的時候輸入的那些資訊。
3. 指定 -KeyUsage 參數可以明確宣告這張憑證的金鑰使用方法 (Key Usage),預設為 None 不指定 (也就是什麼使用方法都可以的意思)。合法的選項如下:
- CertSign
- CRLSign
- DataEncipherment
- DecipherOnly
- DigitalSignature
- EncipherOnly
- KeyAgreement
- KeyEncipherment
- None (default)
- NonRepudiation
4. 指定 -KeyAlgorithm 參數可以設定建立 非同步金鑰 (asymmetric keys) 時要採用哪種加密演算法,你可以選擇 RSA 或 ECDSA。選擇 ECDSA 還必須透過 certutil -displayEccCurve 命令查詢出目前可用的 curvename。
5. 指定 -KeyLength 參數可以設定金鑰長度,常見設定為 2048 或 4096
相關連結