# SSL 與 CA

SSL 的全名是 Secure Sockets Layer，即安全通訊端層，簡而言之，這是一種標準的技術，用於保持網際網路連線安全以及防止在兩個系統之間發送的所有敏感資料被罪犯讀取及修改任何傳輸的資訊，包括潛在的個人詳細資料。兩個系統可以是伺服器與用戶端 (例如購物網站與瀏覽器)，或者伺服器至伺服器 (例如，含有個人身份資訊或含有薪資資訊的應用程式)。  
  
憑證伺服器 - Certificate Authority (CA)，這個伺服器可以用來建立SSL加密連線所需的 Server 及 Root 憑證檔。  
  
對於商用型網站的加密連線，通常會使用 Verisign 或其他第三方認證機構，來簽署需要的憑證檔，但這些需要定期付費，如果不想付費給這些機構做簽署，可以自己架設伺服器來建立及發行所需的憑證檔。  
  
CA 可以使用 Linux 或 Windows 來架設，此篇將以 Linux 為案例，Windows 用戶可以安裝 Windows 元件：Certificate Service。

# Resources

#### Certification Authority

數位憑證認證機構（英語：Certificate Authority，縮寫為CA），也稱為電子商務認證中心、電子商務認證授權機構，是負責發放和管理數位憑證的權威機構，並作為電子商務交易中受信任的第三方，承擔公鑰體系中公鑰的合法性檢驗的責任。

- [政府憑證管理中心](https://gcp.nat.gov.tw/views/about/about_1.html)(Government Certification Authority，簡稱GCA)
- [台灣網路認證](https://www.twca.com.tw/) (TWCA)
- [中華電信通用憑證管理中心](https://publicca.hinet.net/index.htm) (PublicCA)

#### Let's Encrypt

- <span class="external">[How To Secure Apache with Let's Encrypt on Ubuntu 16.04](https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-16-04 "https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-16-04")</span>
- [SSL For Free 免費 SSL 憑證申請，使用 Let’s Encrypt 最簡單方法教學](https://free.com.tw/ssl-for-free/?utm_content=buffer8928e&utm_medium=social&utm_source=plus.google.com&utm_campaign=buffer "https://free.com.tw/ssl-for-free/?utm_content=buffer8928e&utm_medium=social&utm_source=plus.google.com&utm_campaign=buffer")
- [How to Use Let’s Encrypt to Install Free SSL Certificates on Your Linux VPS](https://dotlayer.com/how-to-use-lets-encrypt-to-install-free-ssl-certificates-on-your-linux-vps/ "https://dotlayer.com/how-to-use-lets-encrypt-to-install-free-ssl-certificates-on-your-linux-vps/")
- [Apache with Let’s Encrypt Certificates on CentOS 8](https://www.cyberciti.biz/faq/apache-with-lets-encrypt-certificates-on-centos-8/ "https://www.cyberciti.biz/faq/apache-with-lets-encrypt-certificates-on-centos-8/")
- [How to manage Let's Encrypt SSL/TLS certificates with certbot](https://www.howtoforge.com/how-to-manage-lets-encrypt-ssl-tls-certificates-with-certbot/ "https://www.howtoforge.com/how-to-manage-lets-encrypt-ssl-tls-certificates-with-certbot/")
- [certbot](https://certbot.eff.org/ "https://certbot.eff.org/")
- [How to issue Let’s Encrypt wildcard certificate with acme.sh and Cloudflare DNS](https://www.cyberciti.biz/faq/issue-lets-encrypt-wildcard-certificate-with-acme-sh-and-cloudflare-dns/)
- [How to forcefully renew Let’s Encrypt certificate](https://www.cyberciti.biz/faq/how-to-forcefully-renew-lets-encrypt-certificate/)
- [How to Check Let’s Encrypt SSL Certificate Expiration Date](https://www.linuxshelltips.com/check-lets-encrypt-ssl-certificate-expiration-date/)
- \[Nginx\] [Create a Web Server with NGINX and Secure it Using Certbot](https://linuxhandbook.com/ngnix-certbot/)

[Certbun](https://github.com/porkbundomains/certbun) - Certbot alternative

- [More On Installing And Configuring Certbun For Use With Apache](https://lowendbox.com/blog/more-on-installing-and-configuring-certbun-for-use-with-apache/)

#### Test SSL

這些工具可以檢測 SSL 網站的所有資訊

- [https://www.tecmint.com/testssl-sh-test-tls-ssl-encryption-in-linux-commandline/](https://www.tecmint.com/testssl-sh-test-tls-ssl-encryption-in-linux-commandline/)
- [https://github.com/drwetter/testssl.sh](https://github.com/drwetter/testssl.sh)
- [https://testssl.sh/](https://testssl.sh/)
- [https://www.ssllabs.com/ssltest/](https://www.ssllabs.com/ssltest/)
- [https://github.com/Matty9191/ssl-cert-check](https://github.com/Matty9191/ssl-cert-check)

#### Monitoring SSL

- [https://certificatemonitor.org](https://certificatemonitor.org)   
    Source code: [https://github.com/RaymiiOrg/certificate-expiry-monitor](https://github.com/RaymiiOrg/certificate-expiry-monitor)
- [https://alerts.httpscop.com](https://alerts.httpscop.com)

#### Certificates Tools

- [mkcert](https://github.com/FiloSottile/mkcert) - A simple tool for making locally-trusted development certificates. It requires no configuration. 
    - [How to Create Locally Trusted SSL Certificates with mkcert on Ubuntu 20.04](https://www.howtoforge.com/how-to-create-locally-trusted-ssl-certificates-with-mkcert-on-ubuntu/)
    - [mkcert: Create Trusted SSL Certificate for Local Development](https://www.tecmint.com/mkcert-create-ssl-certs-for-local-development/)
- [SSL Certificates Cheat-Sheet](https://github.com/xcad2k/cheat-sheets/blob/main/misc/ssl-certs.md)

##### ACME (Automated Certificate Management Environment)

[ACME](https://en.wikipedia.org/w/index.php?title=Automatic_Certificate_Management_Environment) 是一種通訊協定，由網際網路工程任務組（IETF）制定，目的是要自動化數位憑證的管理過程，包括憑證的申請、驗證、發行，以及之後的更新。由於數位憑證可以確保網站身份，並保護網站和用戶間的資訊交換，是網路安全非常重要的一環。傳統憑證申請和管理過程複雜且費時，ACME解決了這些麻煩，並使過程能夠自動化，因此也減少了管理成本，以及因憑證過期所產生的安全風險。

- [Step Certificates](https://github.com/smallstep/certificates)
- [Self-Host ACME Server](https://blog.sean-wright.com/self-host-acme-server/)
- [Run your own private CA &amp; ACME server using step-ca](https://smallstep.com/blog/private-acme-server/)

##### Certimate - 多憑證管理平台

Certimate 旨在为用户提供一个安全、简便的 SSL 证书管理解决方案。

做个人产品或者在小企业里负责运维的同学，会遇到要管理多个域名的情况，需要给域名申请证书。但是手动申请证书有以下缺点：

- 😱麻烦：申请证书并部署到服务的流程虽不复杂，但也挺麻烦的，犹其是你有多个域名需要维护的时候。
- 😭易忘：另外当前免费证书的有效期只有90天，这就要求你定期的操作，增加了工作量的同时，你也很容易忘掉续期，从而导致网站访问不了。

Certimate 就是为了解决上述问题而产生的，它具有以下特点：

- 支持私有部署：部署方法简单，只需下载二进制文件并执行即可完成安装。
- 数据安全：由于是私有部署，所有数据均存储在本地，不会保存在服务商的服务器上，确保数据的安全性。
- 操作方便：通过简单的配置即可轻松申请 SSL 证书，并将证书部署到用户指定的目标上，然后在证书即将过期时自动续期，无需人工干预。

URLs:

- [https://docs.certimate.me/](https://docs.certimate.me/)
- GitHub: [https://github.com/usual2970/certimate](https://github.com/usual2970/certimate)

# SSL 常用技巧

##### Check TLS/SSL certificate expiration date

from a website)

```shell
# NOTE: openssl requires at least 1.1.1
SITE_URL="www.cloudcoin.global" 
SITE_SSL_PORT="443" 
## note echo added ## 
echo | openssl s_client -servername ${SITE_URL} -connect ${SITE_URL}:${SITE_SSL_PORT} \
| openssl x509 -noout -dates
# Alternaively
openssl s_client -connect ${SITE_URL}:${SITE_SSL_PORT} -servername ${SITE_URL} 2> /dev/null | openssl x509 -noout -dates

```

output

```
depth=2 C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root
verify return:1
depth=1 C = US, O = "Cloudflare, Inc.", CN = Cloudflare Inc ECC CA-3
verify return:1
depth=0 C = US, ST = CA, L = San Francisco, O = "Cloudflare, Inc.", CN = cloudcoin.global
verify return:1
DONE
notBefore=Jun  5 00:00:00 2020 GMT
notAfter=Jun  5 12:00:00 2021 GMT
```

- **s\_client** : The s\_client command implements a generic SSL/TLS client which connects to a remote host using SSL/TLS.
- **-servername** $DOM : Set the TLS SNI (Server Name Indication) extension in the ClientHello message to the given value. *NOTE: openssl requires at lease 1.1.1*
- **-connect** $DOM:$PORT : This specifies the host ($DOM) and optional port ($PORT) to connect to.
- **x509** : Run certificate display and signing utility.
- **-noout** : Prevents output of the encoded version of the certificate.
- **-dates** : Prints out the start and expiry dates of a TLS or SSL certificate.

from a PEM encoded certificate file)

```shell
openssl x509 -enddate -noout -in /etc/nginx/ssl/www.cyberciti.biz.fullchain.cer

# find out if the TLS/SSL certificate expires within next 7 days (604800 seconds):
openssl x509 -enddate -noout -in my.pem -checkend 604800
```

output

```
notAfter=Dec 29 23:48:42 2020 GMT
```

Shell script to alert sysadmin

```shell
#!/bin/bash
# Purpose: Alert sysadmin/developer about the TLS/SSL cert expiry date in advance
# Author: Vivek Gite {https://www.cyberciti.biz/} under GPL v2.x+
# -------------------------------------------------------------------------------
PEM="/etc/nginx/ssl/letsencrypt/cyberciti.biz/cyberciti.biz.fullchain.cer"
 
# 7 days in seconds 
DAYS="604800" 
 
# Email settings 
_sub="$PEM will expire within $DAYS (7 days)."
_from="system-account@your-dommain"
_to="sysadmin@your-domain"
_openssl="/usr/bin/openssl"
$_openssl x509 -enddate -noout -in "$PEM"  -checkend "$DAYS" | grep -q 'Certificate will expire'
 
# Send email and push message to my mobile
if [ $? -eq 0 ]
then
	echo "${_sub}"
        mail -s "$_sub" -r "$_from" "$_to" <<< "Warning: The TLS/SSL certificate ($PEM) will expire soon on $HOSTNAME [$(date)]"
        # See https://www.cyberciti.biz/mobile-devices/android/how-to-push-send-message-to-ios-and-android-from-linux-cli/ #
        source ~/bin/cli_app.sh
        push_to_mobile "$0" "$_sub. See $_to email for detailed log. -- $HOSTNAME " >/dev/null
fi
```

With Python

- [How to prevent TLS certificates from expiring with Python (activestate.com)](https://www.activestate.com/blog/how-to-manage-tls-certificate-expiration-with-python/)

##### Get the Server certificate from the website

NOTE: openssl requires at least 1.1.1

```
echo -n | openssl s_client -showcerts -servername some.web.site -connect some.web.site:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > some-web-site.pem
```

> 除了使用 openssl 以外，也可以用 Firefox 或 Chrome 手動下載 Server 憑證檔。

##### 顯示憑證檔 \*.crt, \*.pem 的詳細資訊

憑證檔的內容是由兩字串 *-----BEGIN CERTIFICATE-----* 與 *-----END CERTIFICATE-----* 所包含的亂數組合，要解析其中的憑證資訊，可以使用 `openssl` 工具：

```shell
openssl x509 -text -noout -in my_CA.pem  
```

##### Check the TLS version  


```shell
nmap --script ssl-enum-ciphers -p 443 www.google.com

# -tls1 for TLSv1
# -tls1_1 for TLSv1.1
# -tls1_2 for TLSv1.2
openssl s_client -connect www.google.com:443 -tls1_3
```

##### Generate a CSR (Certificate Signing Request)

```shell
sudo apt install openssl  #[On Debian/Ubuntu]
sudo yum install openssl  #[On CentOS/RHEL]
sudo dnf install openssl  #[On Fedora]

openssl req -new -newkey rsa:2048 -nodes -keyout example.com.key -out example.com.csr
```

##### Show the Information of the certificate

```bash
openssl x509 -noout -text -in your.cer

# For the cert file that is generated by Windows
openssl x509 -noout -text -inform der -in win.cer
```

##### More commands

```bash
# Generating a Private Key
openssl genpkey -algorithm RSA -out private.key 

# Generating a Certificate Signing Request (CSR) 
openssl req -new -key private.key -out csr.csr

# Generating a Self-Signed Certificate
openssl req -new -x509 -key private.key -out certificate.crt -days 365

# Encrypting Files
openssl enc -aes256 -in sensitive.txt -out sensitive.enc

# Decrypting Files 
openssl enc -aes256 -d -in sensitive.enc -out sensitive.txt

# Converting Certificate Formats
openssl x509 -in certificate.crt -out certificate.pem

# Creating a Certificate Chain
cat intermediate.crt root.crt > chain.crt

# Signing a CSR with a CA
openssl x509 -req -in csr.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out certificate.crt -days 365

# Generating a Random Number
openssl rand -hex 16

# Checking CSR Details
openssl req -in csr.csr -noout -text

# Viewing Certificate Expiry
openssl x509 -enddate -noout -in certificate.crt

# Converting PFX to PEM
openssl pkcs12 -in certificate.pfx -clcerts -nokeys -out certificate.pem

# Creating a Password-Protected Private Key
openssl genpkey -algorithm RSA -aes256 -out private.key

# Testing SSLv2/v3 Protocol Support
openssl s_client -connect example[dot]com:443 -ssl2/-ssl3

# Extracting Public Key from Private Key
openssl rsa -in private.key -pubout -out public.key

# Encrypting and Decrypting Files with a Passphrase
# Encrypting File:
openssl enc -aes256 -salt -in sensitive.txt -out sensitive.enc
# Decrypting File:
openssl enc -aes256 -d -in sensitive.enc -out sensitive_decrypted.txt
```

# SSL/TLS Web Server

##### Generate Certificates

Method 1: 不需要 CA 的憑證

```shell
mkdir /etc/apache2/certs
cd /etc/apache2/certs
openssl genrsa -out myhomepbx.key 2048
openssl req -new -key myhomepbx.key -out myhomepbx.csr
openssl x509 -req -days 3650 -in myhomepbx.csr -signkey myhomepbx.key -out myhomepbx.crt
```

Method 2: 需要 CA 的憑證

```shell
# generate CA
# organizationName = HomePBX 
# commName = HomePBX CA
# Enter PEM pass phrase: set new password that is used to sign the certicficate.
cd /etc/ssl/homepbxCA
openssl req -new -x509 -extensions v3_ca -keyout ca.key -out ca.crt -days 3650 

# prerequisites
# Edit the openssl.homepbx.cnf as required
cp /etc/ssl/openssl.conf ./openssl.homepbx.cnf
touch index.txt
echo '01' > serial
mkdir newcerts

# generate Server certificates
# organizationName = HomePBX (it must be the same as CA, otherwise it cannot be signed by the CA)
# commName = FQDN of website or *
# Enter PEM pass phrase: It's not required, enter to skip it if wanted.
openssl req -config openssl.homepbx.cnf -new -nodes -keyout server.key -out server.csr
openssl ca -config openssl.homepbx.cnf -days 3650 -in server.csr -out server.crt

# generate PKCS12 for client authentication
# NOTE: you can create PKCS12 file by either server certificate or CA certificate.
# Enter Export Password: set new pasword that is used for importing the PKCS12
openssl pkcs12 -export -clcerts -in ca.crt -inkey ca.key -out homepbx_2021y.p12
# Alternatively
openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -out homepbx_2021y.p12
```

openssl.homepbx.cnf

```
...
[ CA_default ]

dir             = .             # Where everything is kept  <== Here
certs           = $dir/certs            # Where the issued certs are kept
crl_dir         = $dir/crl              # Where the issued crl are kept
database        = $dir/index.txt        # database index file.
#unique_subject = no                    # Set to 'no' to allow creation of
                                        # several certs with same subject.
new_certs_dir   = $dir/newcerts         # default place for new certs.

certificate     = $dir/ca.crt   # The CA certificate <== Here
serial          = $dir/serial           # The current serial number
crlnumber       = $dir/crlnumber        # the current crl number
                                        # must be commented out to leave a V1 CRL
crl             = $dir/crl.pem          # The current CRL
private_key     = $dir/ca.key# The private key  <== Here

x509_extensions = usr_cert              # The extensions to add to the cert
...
```