Skip to content

Commit

Permalink
Self-signed certificate usage
Browse files Browse the repository at this point in the history
  • Loading branch information
ssrlive committed Apr 6, 2024
1 parent 0c23da1 commit a6d9f28
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 18 deletions.
1 change: 1 addition & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ jobs:
- name: Prepare
shell: bash
run: |
rustc --version
rustup target add ${{ matrix.target }}
- name: Build
Expand Down
65 changes: 65 additions & 0 deletions install/selfsign.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/bin/bash

# 自簽名證書的生成和用法
# 1. 下載本腳本
# wget https://raw.githubusercontent.com/shadowsocksr-live/overtls/master/install/selfsign.sh
# 2. 添加可執行權限
# chmod +x selfsign.sh
# 3. 執行腳本, 這裡的 9 個參數依次是: 國家, 省份, 城市, 組織, CA的通用名, 服務器的通用名, 你電郵地址, 胡謅的網址, 你VPS的IP
# ./selfsign.sh CN JiangSu ChangZhou MyGreatOrg Root_CA Server1 [email protected] example.com 123.45.67.89
# 4. 現在你將得到以下文件:
# ca.crt ca.key server.crt server.csr server.key serverca.txt
# 5. 將 server.crt 和 server.key 用於 overtls 服務器, 並在配置文件中使用它們。
# server.crt: 服務器證書
# server.key: 服務器私鑰
# 6. 將 ca.crt 文件用於客戶端, 用它的全路徑 填寫配置文件中的 cafile 參數的值。
# ca.crt: 根證書
# 7. 注意:
# - 這時候 overtls 不用 nginx 幫忙了,客戶端直接連接 overtls 服務端的監聽端口。
# 當然你最好還是裝一個 nginx 監聽在 80 端口,當 GFW 的探測流量到達時,overtls 能作出體面的回應。
# - 由於自簽名證書不被公認,所以 GFW 可能會在一段時間後封了你的服務器,請謹慎使用。
# - 客戶端的配置文件中的 cafile 參數的值,應該是 ca.crt 的全路徑, 例如 /etc/over-tls/ca.crt。
# - 客戶端的配置文件中的 cafile 參數的值,也可以是證書的內容,當然它非常的長,因此不推薦這麼用,
# 它形如這樣 “-----BEGIN CERTIFICATE-----\nMIIFfTCC...\n-----END CERTIFICATE-----”。
# - 這種自簽名證書翻牆的方式,只是讓你在沒有 `域名` 時的臨時解決方案,不要長期使用,否則說不定哪天就被 GFW 封了。
#

# 關鍵信息
COUNTRY=$1
STATE=$2
LOCALITY=$3
ORGANIZATION=$4
ORGANIZATIONAL_UNIT=$4
COMMON_NAME_CA=$5
COMMON_NAME_SERVER=$6
EMAIL_ADDRESS=$7
DNS_1=$8
IP_1=${9}

# 生成根證書的私鑰
openssl genrsa -out ca.key 4096

# 生成根證書
openssl req -outform PEM -new -x509 -sha256 -key ca.key -extensions v3_ca -out ca.crt -subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORGANIZATION/OU=$ORGANIZATIONAL_UNIT/CN=$COMMON_NAME_CA/emailAddress=$EMAIL_ADDRESS"

# 生成自簽名證書的私鑰
openssl genrsa -out server.key 4096

# 生成自簽名證書的 CSR
openssl req -new -sha256 -key server.key -out server.csr -subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORGANIZATION/OU=$ORGANIZATIONAL_UNIT/CN=$COMMON_NAME_SERVER/emailAddress=$EMAIL_ADDRESS"

# 生成 serverca.txt 文件
cat << EOF > serverca.txt
subjectAltName = @${ORGANIZATION}
extendedKeyUsage = serverAuth
[${ORGANIZATION}]
DNS.1 = $DNS_1
IP.1 = $IP_1
EOF

# 生成自簽名證書
openssl x509 -req -CA ca.crt -CAkey ca.key -in server.csr -out server.crt -extfile serverca.txt -sha256 -set_serial 0x1111

# 查看文件
ls
12 changes: 12 additions & 0 deletions readme-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,15 @@ overtls -r client -c config.json
> 爲方便測試,提供了 `disable_tls` 選項以具備停用 `TLS` 的能力;就是說,若該項存在且爲 `true` 時,本軟件將 `明文(plain text)` 傳輸流量;出於安全考慮,正式場合請勿使用。
本示例展示的是最少條目的配置文件,完整的配置文件可以參考 [config.json](config.json)。
### 自簽證書使用
如果你確實沒有 `域名`, 可以使用 `openssl` 生成自簽證書 來臨時連接服務端,以便你能處理你的緊急事務。
```bash
wget https://raw.githubusercontent.com/shadowsocksr-live/overtls/master/install/selfsign.sh
cat selfsign.sh
chmod +x selfsign.sh
./selfsign.sh CN JiangSu ChangZhou MyGreatOrg Root_CA Server1 [email protected] example.com 123.45.67.89
```
> 注意:`GFW` 可能會因爲你使用了自簽證書而封鎖你的服務器。所以請不要長期用於正式場合。
14 changes: 14 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,17 @@ Note the `tunnel_path` configuration, please make sure to change it to your own
> For testing purposes, the `disable_tls` option is provided to have the ability to disable `TLS`; that is, if this option exists and is true, the software will transmit traffic in `plain text`; for security reasons, please do not use it on official occasions.
This example shows the configuration file of the least entry, the complete configuration file can refer to [config.json](config.json).
### Self-signed certificate usage
If you have not owned a `domain name`, you can use the `openssl` command to generate a self-signed certificate
for testing purposes.
```bash
wget https://raw.githubusercontent.com/shadowsocksr-live/overtls/master/install/selfsign.sh
cat selfsign.sh
chmod +x selfsign.sh
./selfsign.sh CN JiangSu ChangZhou MyGreatOrg Root_CA Server1 [email protected] example.com 123.45.67.89
```
> Note: The `GFW` maybe block your server since you are using a self-signed certificate.
> So please do not use it for long-term production purposes.
3 changes: 2 additions & 1 deletion src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@ pub(crate) async fn create_tls_ws_stream(
) -> Result<WsTlsStream> {
let client = config.client.as_ref().ok_or("client not exist")?;

let cert_store = retrieve_root_cert_store_for_client(&client.cafile)?;
let cert_content = client.cafile.as_ref().and_then(|cafile| crate::config::certificate_content(cafile));
let cert_store = retrieve_root_cert_store_for_client(&cert_content)?;
let domain = client.server_domain.as_ref().unwrap_or(&client.server_host);

let stream = create_tls_client_stream(cert_store, svr_addr, domain).await?;
Expand Down
13 changes: 12 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,17 @@ pub struct ManageClients {
pub api_update_interval_secs: Option<u64>,
}

pub(crate) fn certificate_content(cert: &str) -> Option<String> {
if PathBuf::from(cert).exists() {
match std::fs::read_to_string(cert) {
Ok(content) => Some(content),
Err(_) => None,
}
} else {
Some(cert.to_string())
}
}

#[derive(Clone, Serialize, Deserialize, Debug, Default)]
pub struct Client {
#[serde(skip_serializing_if = "Option::is_none")]
Expand All @@ -134,7 +145,7 @@ pub struct Client {
#[serde(skip_serializing_if = "Option::is_none")]
pub server_domain: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cafile: Option<PathBuf>,
pub cafile: Option<String>,
pub listen_host: String,
pub listen_port: u16,
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down
23 changes: 7 additions & 16 deletions src/tls.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
use crate::error::Result;
use rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName};
use std::{
fs::File,
io::BufReader,
net::SocketAddr,
path::{Path, PathBuf},
};
use std::{fs::File, io::BufReader, net::SocketAddr, path::Path};
use tokio::net::TcpStream;
use tokio_rustls::{
client::TlsStream,
Expand All @@ -17,19 +12,15 @@ use tokio_rustls::{
// https://github.com/rustls/tokio-rustls/blob/main/examples/client.rs
//

pub(crate) fn retrieve_root_cert_store_for_client(cafile: &Option<PathBuf>) -> Result<RootCertStore> {
pub(crate) fn retrieve_root_cert_store_for_client(ca_content: &Option<String>) -> Result<RootCertStore> {
let mut root_cert_store = RootCertStore::empty();
let mut done = false;
if let Some(cafile) = cafile {
if cafile.exists() {
let mut pem = BufReader::new(File::open(cafile)?);
for cert in rustls_pemfile::certs(&mut pem) {
root_cert_store.add(cert?)?;
}
done = true;
if let Some(ca_content) = ca_content {
let mut pem = std::io::Cursor::new(ca_content.as_bytes());
for cert in rustls_pemfile::certs(&mut pem) {
root_cert_store.add(cert?)?;
}
}
if !done {
if root_cert_store.is_empty() {
root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
}
Ok(root_cert_store)
Expand Down

1 comment on commit a6d9f28

@ssrlive
Copy link
Member Author

@ssrlive ssrlive commented on a6d9f28 Apr 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client config file looks like
image

Please sign in to comment.