# OpenSSL证书生成完整指南

## 前提条件

确保已安装OpenSSL：
- Windows：从 https://slproweb.com/products/Win32OpenSSL.html 下载安装
- 或使用Git Bash自带的OpenSSL

## 证书生成步骤

### 第一步：创建证书目录

```powershell
# 创建证书存放目录
mkdir E:\certs
cd E:\certs
```

### 第二步：生成CA（证书颁发机构）

CA是用来签发服务器和客户端证书的根证书。

#### 2.1 生成CA私钥
```bash
openssl genrsa -out ca-key.pem 4096
```
**说明：** 生成4096位的RSA私钥（不加密）

#### 2.2 生成CA证书
```bash
openssl req -new -x509 -days 3650 -key ca-key.pem -out ca-cert.pem -subj "/C=CN/ST=Beijing/L=Beijing/O=Myself/OU=IT/CN=MyCA"
```
**说明：**
- `-days 3650`：证书有效期10年
- `-subj`：证书主题信息（可以修改）
  - `C`：国家代码（CN=中国）
  - `ST`：省份
  - `L`：城市
  - `O`：组织名称
  - `OU`：部门
  - `CN`：通用名称（CA名称）

### 第三步：生成服务器证书

#### 3.1 生成服务器私钥（带密码）
```bash
openssl genrsa -aes256 -passout pass:15AnnUBW97opUIMA10 -out server-key.pem 2048
```
**说明：**
- `-aes256`：使用AES256加密私钥
- `-passout pass:15AnnUBW97opUIMA10`：私钥密码（请修改为自己的密码）
- `2048`：密钥长度

#### 3.2 生成服务器证书签名请求（CSR）
```bash
openssl req -new -key server-key.pem -passin pass:15AnnUBW97opUIMA10 -out server-csr.pem -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=IT/CN=localhost"
```
**说明：**
- `CN=localhost`：服务器地址（如果用IP访问，改为IP地址）

#### 3.3 用CA签发服务器证书
```bash
openssl x509 -req -days 3650 -in server-csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem
```
**说明：** 使用CA证书和CA私钥签发服务器证书

### 第四步：生成客户端证书

#### 4.1 生成客户端私钥（带密码）
```bash
openssl genrsa -aes256 -passout pass:1Annubw97opUIMA10 -out client-key.pem 2048
```
**说明：** 密码请修改为自己的密码

#### 4.2 生成客户端证书签名请求（CSR）
```bash
openssl req -new -key client-key.pem -passin pass:1Annubw97opUIMA10 -out client-csr.pem -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=IT/CN=MyClient"
```

#### 4.3 用CA签发客户端证书
```bash
openssl x509 -req -days 3650 -in client-csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem
```

### 第五步：验证证书

#### 5.1 查看CA证书
```bash
openssl x509 -in ca-cert.pem -text -noout
```

#### 5.2 查看服务器证书
```bash
openssl x509 -in server-cert.pem -text -noout
```

#### 5.3 验证证书链
```bash
# 验证服务器证书
openssl verify -CAfile ca-cert.pem server-cert.pem

# 验证客户端证书
openssl verify -CAfile ca-cert.pem client-cert.pem
```
**应该输出：** `server-cert.pem: OK` 和 `client-cert.pem: OK`

## 完整的PowerShell脚本

将以下内容保存为 `generate-certs.ps1`：

```powershell
# 证书生成脚本
$certDir = "E:\certs"
New-Item -ItemType Directory -Force -Path $certDir
Set-Location $certDir

Write-Host "==== 1. 生成CA证书 ====" -ForegroundColor Green

# 生成CA私钥
openssl genrsa -out ca-key.pem 4096

# 生成CA证书（10年有效期）
openssl req -new -x509 -days 3650 -key ca-key.pem -out ca-cert.pem `
    -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=IT/CN=MyCA"

Write-Host "==== 2. 生成服务器证书 ====" -ForegroundColor Green

# 生成服务器私钥（密码：MyServerPass123）
openssl genrsa -aes256 -passout pass:MyServerPass123 -out server-key.pem 2048

# 生成服务器CSR
openssl req -new -key server-key.pem -passin pass:MyServerPass123 -out server-csr.pem `
    -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=IT/CN=localhost"

# 签发服务器证书
openssl x509 -req -days 3650 -in server-csr.pem `
    -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem

Write-Host "==== 3. 生成客户端证书 ====" -ForegroundColor Green

# 生成客户端私钥（密码：MyClientPass123）
openssl genrsa -aes256 -passout pass:MyClientPass123 -out client-key.pem 2048

# 生成客户端CSR
openssl req -new -key client-key.pem -passin pass:MyClientPass123 -out client-csr.pem `
    -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/OU=IT/CN=MyClient"

# 签发客户端证书
openssl x509 -req -days 3650 -in client-csr.pem `
    -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem

Write-Host "==== 4. 验证证书 ====" -ForegroundColor Green

openssl verify -CAfile ca-cert.pem server-cert.pem
openssl verify -CAfile ca-cert.pem client-cert.pem

Write-Host "`n==== 证书生成完成！ ====" -ForegroundColor Green
Write-Host "文件列表：" -ForegroundColor Yellow
Get-ChildItem -Filter *.pem | Format-Table Name, Length, LastWriteTime

Write-Host "`n接下来：" -ForegroundColor Cyan
Write-Host "1. 查看 ca-cert.pem（CA证书）"
Write-Host "2. 查看 server-cert.pem 和 server-key.pem（服务器证书和私钥）"
Write-Host "3. 查看 client-cert.pem 和 client-key.pem（客户端证书和私钥）"
Write-Host "4. 将证书内容替换到源代码中"
```

## 执行脚本

```powershell
# 执行生成脚本
powershell -ExecutionPolicy Bypass -File generate-certs.ps1
```

## 生成的文件说明

执行完成后，`E:\certs\` 目录下会有：

| 文件名 | 说明 | 用途 |
|--------|------|------|
| `ca-key.pem` | CA私钥 | 签发证书用（保密） |
| `ca-cert.pem` | CA证书 | 验证其他证书（公开） |
| `server-key.pem` | 服务器私钥 | 服务器解密用（保密，密码：MyServerPass123） |
| `server-cert.pem` | 服务器证书 | 服务器身份证明（公开） |
| `server-csr.pem` | 服务器CSR | 证书请求文件（可删除） |
| `client-key.pem` | 客户端私钥 | 客户端解密用（保密，密码：MyClientPass123） |
| `client-cert.pem` | 客户端证书 | 客户端身份证明（公开） |
| `client-csr.pem` | 客户端CSR | 证书请求文件（可删除） |
| `ca-cert.srl` | 序列号文件 | CA签发证书的序列号（保留） |

## 将证书嵌入到源代码

### 方法1：查看证书内容（复制到代码）

```powershell
# 查看CA证书
Get-Content E:\certs\ca-cert.pem

# 查看服务器证书
Get-Content E:\certs\server-cert.pem

# 查看服务器私钥
Get-Content E:\certs\server-key.pem

# 查看客户端证书
Get-Content E:\certs\client-cert.pem

# 查看客户端私钥
Get-Content E:\certs\client-key.pem
```

### 方法2：自动生成C++代码（推荐）

创建 `convert-to-cpp.ps1` 脚本：

```powershell
$certDir = "E:\certs"
$outputFile = "$certDir\certificates.cpp"

$serverCert = Get-Content "$certDir\server-cert.pem" -Raw
$serverKey = Get-Content "$certDir\server-key.pem" -Raw
$clientCert = Get-Content "$certDir\client-cert.pem" -Raw
$clientKey = Get-Content "$certDir\client-key.pem" -Raw
$caCert = Get-Content "$certDir\ca-cert.pem" -Raw

$cppCode = @"
// 自动生成的证书代码
// 生成时间: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")

// 服务器证书
static const char* g_s_lpszPemCert =
"$($serverCert -replace "`r`n", "\n" -replace "\n", "\n`t`"" -replace "`"$", "`";")

// 服务器私钥（密码：MyServerPass123）
static const char* g_s_lpszPemKey =
"$($serverKey -replace "`r`n", "\n" -replace "\n", "\n`t`"" -replace "`"$", "`";")

// 客户端证书
static const char* g_c_lpszPemCert =
"$($clientCert -replace "`r`n", "\n" -replace "\n", "\n`t`"" -replace "`"$", "`";")

// 客户端私钥（密码：MyClientPass123）
static const char* g_c_lpszPemKey =
"$($clientKey -replace "`r`n", "\n" -replace "\n", "\n`t`"" -replace "`"$", "`";")

// CA证书（服务器和客户端共用）
static const char* g_s_lpszCAPemCert =
"$($caCert -replace "`r`n", "\n" -replace "\n", "\n`t`"" -replace "`"$", "`";")

static const char* g_c_lpszCAPemCert = g_s_lpszCAPemCert;

// 密钥密码
static const char* g_s_lpszKeyPassword = "MyServerPass123";
static const char* g_c_lpszKeyPassword = "MyClientPass123";
"@

$cppCode | Out-File -FilePath $outputFile -Encoding utf8
Write-Host "C++代码已生成: $outputFile" -ForegroundColor Green
```

执行：
```powershell
powershell -ExecutionPolicy Bypass -File convert-to-cpp.ps1
```

然后复制 `E:\certs\certificates.cpp` 的内容到你的源代码中。

## 修改源代码

### Server/main.cpp

找到证书定义部分（第7-87行），替换为新生成的证书：

```cpp
// 将新生成的证书内容替换这里
static const char* g_s_lpszPemCert = "...新的服务器证书...";
static const char* g_s_lpszPemKey = "...新的服务器私钥...";
static const char* g_s_lpszCAPemCert = "...新的CA证书...";
static const char* g_s_lpszKeyPassword = "MyServerPass123";  // 改为你的密码
```

### Client/main.cpp

找到证书定义部分（第7-99行），替换为新生成的证书：

```cpp
// 将新生成的证书内容替换这里
static const char* g_c_lpszPemCert = "...新的客户端证书...";
static const char* g_c_lpszPemKey = "...新的客户端私钥...";
static const char* g_c_lpszCAPemCert = "...新的CA证书...";
static const char* g_c_lpszKeyPassword = "MyClientPass123";  // 改为你的密码
```

## 重新编译

```powershell
cd "E:\开发\C_C++\hp-socket-6.0.4\hp-socket-6.0.7-src\Windows\Demo\TestEcho-SSL-Console"
& "D:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe" TestEcho-SSL-Console.sln /p:Configuration=Debug /p:Platform=x64
```

## 测试新证书

运行服务器和客户端，如果看到：
```
[服务器] SSL环境初始化成功
[客户端] SSL环境初始化成功
[客户端] OnHandShake - SSL握手完成！
```

说明新证书工作正常！

## 常见问题

### Q: 生成证书时需要输入密码吗？
A: 不需要。脚本中使用 `-passout pass:xxx` 自动指定密码。如果想手动输入，去掉 `-passout` 参数。

### Q: CN（通用名称）应该填什么？
A: 
- 服务器证书：填写服务器域名或IP（如 `localhost` 或 `192.168.1.100`）
- 客户端证书：填写客户端标识（任意，如 `MyClient` 或 `Client001`）
- CA证书：填写CA名称（任意，如 `MyCompanyCA`）

### Q: 私钥密码可以不设置吗？
A: 可以。去掉 `-aes256 -passout pass:xxx` 参数，并在代码中将密码改为 `nullptr`：
```cpp
static const char* g_s_lpszKeyPassword = nullptr;
```

### Q: 证书有效期到期怎么办？
A: 重新生成证书，或者生成时将 `-days 3650` 改为更大的值（如 `7300` = 20年）。

### Q: 如何批量生成多个客户端证书？
A: 修改脚本，用循环生成多个客户端证书，每个证书使用不同的CN（如 `Client001`, `Client002`）。

## 安全建议

⚠️ **生产环境注意事项：**

1. **不要将私钥硬编码在源代码中**
   - 使用配置文件或密钥管理系统
   - 使用 `SetupSSLContext()` 从文件加载

2. **保护CA私钥**
   - `ca-key.pem` 是最重要的文件
   - 应存放在安全的地方
   - 不要泄露给任何人

3. **使用强密码**
   - 不要使用 `123456` 这样的简单密码
   - 建议使用随机生成的复杂密码

4. **定期更新证书**
   - 建议每1-2年更新一次证书
   - 保持证书有效期在合理范围内

5. **证书分发**
   - 客户端证书应单独生成和分发
   - 不要多个客户端共用同一个证书

---
**完成后，你将拥有自己的证书体系，可以用于生产环境！**
