在 AWS 使用 openssl 產生 CA 憑證,並與 IoT Core 交互(一)

春麗 S.T.E.M.
22 min readFeb 17, 2024

--

目錄
1. OpenSSL
2. Linux、MAC
2-1 private key
2-2 Certificate
3. 延續 MAC 指令碼
3-1 自簽根憑證
3-2 總複習
4. Troubleshooting

⦿ OpenSSL
⦿ Linux、MAC
⦿ private key
⦿ Certificate
⦿ 延續 MAC 指令碼
⦿ 自簽根憑證
⦿ 總複習
⦿ Troubleshooting

OpenSSL

在 SSL/TLS 協定中,我們常用 OpenSSL 套件來實作加密功能,OpenSSL 是一個用 C 語言寫成的開放原始碼函式庫套件,在 MAC 中,打開你的 Terminal 輸入 which openssl 得到如下:

這表示你的電腦中有 openssl 套件。

密碼學系列文章中,我們已經了解到 HTTPS 的網路溝通流程為,TCP 交握 => 驗證簽名、確認公鑰(PKI) => 以 RSA 交換 AES 密鑰(密鑰交換) => 加密檔案並傳輸

首篇文章中也告訴大家若要使用 8883 通訊埠跟 AWS 做安全的 MQTT 溝通時,可以使用 AWS 預先產生的 X.509,這樣 Device 在沒有網路的狀態下也可以佈建憑證,預先產生的憑證加速了生產流程,而 AWS 預先產生的憑證包括了 root CAdevice certificate 以及 private key,雖然 AWS 也幫你準備好了 Public Key,但通常 Device 不需要它。

因為我們知道公鑰的作用是拿來驗證簽名,然而 AWS 給你的憑證中就包含你的公鑰,在網路溝通時,對方以 root CA 中的公鑰,驗證你憑證中的簽名,確認你憑證中的公鑰是屬於你的即可。

要注意的是!AWS 會提醒你這些憑證只能下載一次,而你在 AWS 產生時,若沒有點擊下載的動作,也是沒辦法進到下一步的。

那麼,使用 OpenSSL 套件產生的憑證就包含了兩個重要項,第一個是 certificate,第二個是 private key,下面我們來看看實際的指令碼例子。

回目錄

繼續閱讀|回目錄

Linux、MAC

首先,你會產生 private key,接著再利用 private key 產生憑證(因憑證包含了由 private key 產生的簽名),那麼,我們先來看看在 Rocky Linux 中的指令:

openssl req -newkey rsa:2048 \
-nodes -sha256 \
-x509 -days 36500 \
-keyout serverX.linux.class.key \
-out serverX.linux.class.crt \
-addext "subjectAltName = DNS:serverX.linux.class"

再來是 MAC 中的指令:

$ openssl genrsa -out sampleCACertificate.key 2048
$ openssl req -x509 -new -nodes -key sampleCACertificate.key -sha256 -days 365 -out sampleCACertificate.pem

private key

兩者皆使用 openssl 來產生 X.509 憑證,先看到 MAC 的指令,使用 openssl genrsa -out sampleCACertificate.key 2048 指令產生一個 RSA 2048 bits 算法的 private key,這個 private key 名稱叫做 sampleCACertificate.key

在 Linux 中,同樣有個 openssl 的 req(request,請求),並且 -newkey rsa:2048 也同樣是以 RSA 2048 bits 算法產生的 private key,這個 private key 名稱即是 -keyout 後面那串 serverX.linux.class.key

由於我們知道的憑證包含兩個重要項,第一個是 Public Key,第二個是簽名,而簽名是如何得來的呢?將 Public Key 經過 hashing 後以 private key 加密。

如此一來,接收你憑證的對方就可以用公鑰解開簽名,得到你 Public Key 的雜湊值,再將你憑證中的 Public Key 做雜湊,比對兩個雜湊值,來確認這個 Public Key 就是你的。

這裡產生的憑證也需要相同作法,而若憑證裡的 Public Key,跟憑證裡簽名使用的 private key 是密鑰對,那麼,這個憑證就叫做自簽根憑證,這邊例子就是自簽根憑證。

我們先把幾個簡單的指令看完,再看憑證的指令,-node 表示你用來簽名的 private key,不要使用 passphrase 來加密,若使用了 passphrase 來加密,則比較像是踩坑大全文章中的 P.12 憑證,而不是 X.509 了。

-days 後面的數字表示憑證的有效期限;-addext 後的 “subjectAltName = DNS:serverX.linux.class” 是 X.509 的擴充,將主題替代名稱對應到特定的 Domain 上。

Certificate

-sha256 表示使用什麼樣的雜湊演算法來產生憑證中的簽名,這項資訊也會放在你的憑證中;-x509 表示你要產生的憑證就是 X.509 格式的憑證。在 Linux 中,-out serverX.linux.class.crt即是產生名為 serverX.linux.class.crt 的憑證,憑證中的簽名當然是搭配 sha256 與 private key(serverX.linux.class.key) 產生的。

在 MAC 中,-key sampleCACertificate.key -sha256 -out sampleCACertificate.pem 這段指令表示用 sampleCACertificate.key 這個 private key 與 sha256 這個雜湊函式去產生名為 sampleCACertificate.pem 的這個 X.509。

回目錄

繼續閱讀|回目錄

延續 MAC 指令碼

當確實產生 private key,以及用 private key、sha256 雜湊產生簽名,最後生成憑證,會經歷下面步驟:

chunlicheng@MacBook-Air-M1 newcert % openssl req -x509 -new -nodes -key sampleCACertificate.key -sha256 -days 365 -out sampleCACertificate.pem

You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:TW
State or Province Name (full name) [Some-State]:Taiwan
Locality Name (eg, city) []:Taipei
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Charles Ltd
Organizational Unit Name (eg, section) []:MIS
Common Name (e.g. server FQDN or YOUR name) []:Charles
Email Address []:charles@gmail.com

像上圖這樣鍵入 TWTaiwanTaipei 等資訊,或者以 . 來留空,就可以順利生成憑證了,不過當你 cat private key 或是 Certificate 都會是看不懂的 base64,private key 的開頭與結尾會看到如下:

-----BEGIN PRIVATE KEY-----
-----END PRIVATE KEY-----

Certificate 的開頭與結尾會看到如下:

-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----

如果想要看到憑證的資訊就鍵入如下:

openssl x509 -noout -text -in sampleCACertificate.pem

======接著,會得到下面資訊======

Certificate:
Data:
Version: 3 (0x2)
Serial Number:
XX:XX
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=TW, ST=Taiwan, L=Taipei, O=Charles Ltd, OU=MIS, CN=Charles, emailAddress=charles@gmail.com
Validity
Not Before: Feb 16 07:24:52 2024 GMT
Not After : Feb 15 07:24:52 2025 GMT
Subject: C=TW, ST=Taiwan, L=Taipei, O=Charles Ltd, OU=MIS, CN=Charles, emailAddress=charles@gmail.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
XX:XX
XX:XX
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
XX:XX
X509v3 Authority Key Identifier:
XX:XX
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
XX:XX
XX:XX

這邊說明了簽名的演算法是 sha256WithRSAEncryption;頒發者(Issuer)就是剛才產生憑證鍵入的資訊;還有憑證有效日期,由於剛才是 365,所以是一年後這個憑證會失效;接著是 Public Key 的演算法,演算法是 RSA,以及簽名,如此憑證該有的都具備了。

自簽根憑證

但由於這是自簽根憑證,由它簽署的 Device Certificate 要拿到 AWS 使用還需經過一些步驟,首先,當然必須要安裝 AWS CLI 在你的電腦裡,關於 AWS CLI 的設定可以參考下面文章:

在確認你有 AWS CLI 後,鍵入如下:

$ aws iot get-registration-code

若尚未產生過,AWS 會花點時間產生這個 registration code,這個 registration code 不會過期的,除非你主動去將它刪除,接著,我們要使用這個 code 去產生 CSR(Certificate signing request,憑證簽署請求),鍵入如下:

$ openssl genrsa -out privateKeyVerification.key 2048
$ openssl req -new -key privateKeyVerification.key -out privateKeyVerification.csr

接著同樣設定,不過這次的 Common Name (e.g. server FQDN or YOUR name) []: 後面必須輸入剛才拿到的 registration code,完成後,我們現在得到兩組產生的東西如下:

現在,鍵入如下:

$ openssl x509 -req -in privateKeyVerification.csr -CA sampleCACertificate.pem -CAkey sampleCACertificate.key -CAcreateserial -out privateKeyVerification.crt -days 365 -sha256

現在,我們的資料夾中又多了兩樣東西,一個是 privateKeyVerification.crt,一個是 sampleCACertificate.srl,這個指令的意思是藉由 CSR自簽根憑證、自簽根憑證所使用的 private key 組合成欲經由 AWS 驗證的憑證,即privateKeyVerification.crt,srl 這個檔案是由指令的 -CAcreateserial 所產生出來的,記錄了 CA 簽署了多少憑證,產生後,後續的憑證可由 -CAserial 指定 srl 檔案來產生。

在做完前一步,我們可以到 AWS IoT Core 上傳 rootCA(sampleCACertificate.pem),以及用來驗證 rootCA 的憑證(privateKeyVerification.crt),如下:

在 AWS IoT Core 頁面中,我們可以了解到在本地使用 CLI 的指令,其實都可以到網頁上面去操作,由於 CLI 可以安排自動化操作,所以我們還是回到 CLI。

同樣地在 CLI 的下一步,就是向 aws 註冊這個憑證,我們輸入下面的指令:

$ aws iot register-ca-certificate --ca-certificate file:///location/sampleCACertificate.pem --verification-certificate file:///location/privateKeyVerification.crt

file:///location/sampleCACertificate.pem 與 file:///location/privateKeyVerification.crt 分別代表了 rootCA.pem(自簽根憑證)與欲讓 AWS 驗證 rootCA 憑證的憑證,在 MAC 中,file: 後面有三條 /,如果你忘記檔案放在哪裡,切換到檔案資料夾,鍵入 pwd 顯示當前資料夾的絕對路徑。

aws iot register-ca-certificate 這個指令表示你要向 AWS 註冊根憑證, — ca-certificate 這個指令後擺的就是 rootCA.pem; — verification-certificate 這個指令後擺的就是用來驗證 rootCA 的憑證。

若順利的話,會得到類似下面訊息:

{
"certificateArn": "arn:aws:iot:ap-southeast-2:124996249029:cacert/357ec7379509d799358bd8f173c8424616509cb64173d9d01d40475d84641b9d",
"certificateId": "357ec7379509d799358bd8f173c8424616509cb64173d9d01d40475d84641b9d"
}

在 AWS IoT Core 下,我們可以用 aws iot list-certificates 來查看裝置的憑證,用 aws iot list-ca-certificates 來查看 CA 的憑證。

$ aws iot list-ca-certificates



$ aws iot describe-ca-certificate --certificate-id <certificateId>

如果有順利出現你的 CA Certificate 就代表成功了!

不過,現在你的 CA 訊息中,還是 “status”: “INACTIVE”,我們再鍵入如下:

$ aws iot update-ca-certificate --certificate-id <certificateId> --new-status ACTIVE

status 就變成 ACTIVE 了!在 CA 憑證狀態是 ACTIVE 的情況,才會允許裝置註冊,不過我們還差一點,因為 CA 憑證中的自動註冊為停用的,這表示說由 CA 簽發的裝置憑證,在第一次連上 AWS 時並不會自動註冊,所以我們再鍵入如下:

$ aws iot update-ca-certificate --certificate-id <caCertificateId> --new-auto-registration-status ENABLE

最終結果如下:

總複習

現在,你可以用給 AWS 驗證過的 CA 憑證來簽署你的裝置憑證,我們再順過一次流程:

  1. 生成 CA 的 private key:
    openssl genrsa -out sampleCACertificate.key 2048
  2. 使用 CA 的 private key 產生自簽憑證:
    openssl req -x509 -new -nodes -key sampleCACertificate.key -sha256 -days 365 -out sampleCACertificate.pem
  3. 使用 AWS CLI 指令找出註冊碼:
    aws iot get-registration-code
  4. 產生用來驗證 CA 的 private key:
    openssl genrsa -out privateKeyVerification.key 2048
  5. 以這個 private key 產生 CSR:
    openssl req -new -key privateKeyVerification.key -out privateKeyVerification.csr
  6. 將 CSR、CA 憑證、CA private key 組合成新的 CRT 憑證:
    openssl x509 -req -in privateKeyVerification.csr -CA sampleCACertificate.pem -CAkey sampleCACertificate.key -CAcreateserial -out privateKeyVerification.crt -days 365 -sha256
  7. 將 CRT 憑證傳給 AWS IoT 來註冊你的 CA 憑證
    aws iot register-ca-certificate --ca-certificate file:///location/sampleCACertificate.pem --verification-certificate file:///location/privateKeyVerification.crt
  8. 將 CA 憑證狀態設置為作用中
    aws iot update-ca-certificate — certificate-id <certificateId> — new-status ACTIVE
  9. 將 CA 憑證的自動註冊憑證打開
    aws iot update-ca-certificate — certificate-id <caCertificateId> — new-auto-registration-status ENABLE

以上為使用自己的 CA 憑證的註冊流程,要知道的是 private key 跟 Public Key 是密鑰對,憑證包括 Public Key 以及 private key 產生的簽名,所以產生憑證的流程的第一步就是產生 private key。

接著,由於自產出的憑證是未經 AWS 驗證的,所以必須要再產出用來驗證的 private key 與 CSR,這個 CSR 就是驗證請求,需要將之與 CA private key、CA 憑證產生一個 CRT 憑證,將 CRT 憑證、CA 憑證給 AWS 驗證,最終得到你的 CA 憑證。

完成了!

回目錄

繼續閱讀|回目錄

Troubleshooting

An error occurred (CertificateValidationException) when calling the RegisterCACertificate operation: CA certificate is not valid. The CA certificate does not have the basicConstraints extension as true

如果很不幸地,在向 AWS 驗證 CA 憑證時,出現上述訊息,我們可以依照下面的解決方法:

  1. 生成 rootCA 的 private key
    openssl genrsa -out rootCA.key 2048
  2. 鍵入 vi rootCA_openssl.conf,來建立 rootCA_openssl.conf 這個檔案,貼上下面訊息
    [ req ]
    distinguished_name = req_distinguished_name
    extensions = v3_ca
    req_extensions = v3_ca
    [ v3_ca ]
    basicConstraints = CA:TRUE
    [ req_distinguished_name ]
    countryName = Country Name (2 letter code)
    countryName_default = TW
    countryName_min = 2
    countryName_max = 2
    organizationName = Organization Name (eg, company)
    organizationName_default = Deeply Inc.
    接著,按下 ESC,輸入 wq 儲存離開。
  3. 使用 private key 來建立 rootCA 的 CSR,並採用剛才建立的 conf 規則
    openssl req -new -sha256 -key rootCA.key -nodes -out rootCA.csr -config rootCA_openssl.conf
    其中的重點為 conf 中設定了 basicConstraints = CA:TRUE
  4. 使用 conf 規則,將 CSR、rootCA private key、rootCA 憑證兜在一起:
    openssl x509 -req -days 3650 -extfile rootCA_openssl.conf -extensions v3_ca -in rootCA.csr -signkey rootCA.key -out rootCA.pem
  5. 使用 AWS CLI 指令找出註冊碼:
    aws iot get-registration-code
  6. 產生用來驗證 CA 的 private key:
    openssl genrsa -out verificationCert.key 2048
  7. 以這個 private key 產生 CSR:
    openssl req -new -key verificationCert.key -out verificationCert.csr
  8. 將 CSR、CA 憑證、CA private key 組合成新的 CRT 憑證:
    openssl x509 -req -in verificationCert.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out verificationCert.crt -days 500 -sha256
  9. 將 CRT 憑證傳給 AWS IoT 來註冊你的 CA 憑證
    aws iot register-ca-certificate --ca-certificate file:///location/Desktop/newcert/rootCA.pem --verification-certificate file:///location/Desktop/newcert/verificationCert.crt
  10. 後面相同。

呼——!終於完成了,要使用自簽 CA 憑證讓 AWS 驗證,再以自簽 CA 憑證去簽發裝置憑證真是不容易,或者說要在網路溝通時,使用 SSL/TLS 做安全資料傳輸不容易,所以有些時候我們會使用 Let’s Encrypt 服務來幫忙,像是在 Home Assistant 系列文章中,就有使用 Let’s Encrypt,參考如下:

這次就分享到這,感謝您的閱讀。

回目錄

繼續閱讀|回目錄

Reference:

--

--

春麗 S.T.E.M.
春麗 S.T.E.M.

Written by 春麗 S.T.E.M.

Do not go gentle into that good night, Old age should burn and rave at close of day; Rage, rage, against the dying of the light.

No responses yet