# 连接加密支持文档

本文档仅描述了标准 TLS 协议与国标 TLCP 协议支持相关事项，对于虚谷自有 SSL 协议实现相关事项，请参阅《虚谷数据库通信协议》文档。

## 铜锁/Tongsuo

[铜锁/Tongsuo](https://github.com/Tongsuo-Project/Tongsuo.git)（原 BabaSSL）是由 Alipay 团队开发的开源基础密码库，其基于 OpenSSL 3 开发，提供了对中国商用密码算法的支持，以及国家标准加密通信协议的支持，同时也提供 OpenSSL 原有协议的支持。

### 编译环境

- 任意 make 实现
- [Perl 5](https://strawberryperl.com) with Text::Template module
- C compiler
- [NASM](https://www.nasm.us)（Windows）

**注意**：
- 推荐 StrawberryPerl，自带常用模块
- NASM 为 Windows 环境所需

### 源码编译

1. 使用本机架构（如：x64）对应的 **VS 开发者命令行** 执行后续命令
1. 拉取源码
    ```bat
    set TONGSUO_VERSION=8.3.1
    git clone --depth 1 -b %TONGSUO_VERSION% https://github.com/Tongsuo-Project/Tongsuo.git`
    cd Tongsuo && git switch -c %TONGSUO_VERSION%
    ```
1. 生成配置
    ```bat
    rem 若需要调试版本，可添加 --debug 参数
    perl Configure VC-WIN64A enable-ntls
    ```
1. 编译铜锁
    ```bat
    rem 生成的库文件位于项目根目录
    nmake
    ```
1. 安装铜锁（可选）
    ```bat
    rem 将铜锁安装至系统中
    nmake install
    ```

## 项目配置

数据库开发环境需进行以下配置（Windows Visual Studio）：

- 系统环境变量 `PATH` 中加入：`Tongsuo/apps` 目录
- VS 属性页-调试-环境：添加 `Tongsuo/apps` 目录
- VS 属性页-C/C++-常规-附加包含目录：添加 `Tongsuo/include` 目录
- VS 属性页-链接器-常规-附加库目录：添加 `Tongsuo` 库文件所在目录
- VS 属性页-链接器-输入-附加依赖项：添加 `Ws2_32.lib、Mswsock.lib、AdvApi32.lib、libcrypto.lib、libssl.lib`

## 脚本说明

脚本位于数据库源码项目 `script` 目录，用于生成所需文件：

| FILE                  | COMMENT                                 |
|-----------------------|-----------------------------------------|
| `keytool-generate.bat`| Java KeyTool 工具 Windows Batch 生成脚本 |
| `keytool-generate.sh` | Java KeyTool 工具 Linux Shell 生成脚本   |
| `tongsuo-generate.bat`| Tongsuo 工具 Windows Batch 生成脚本      |
| `tongsuo-generate.sh` | Tongsuo 工具 Linux Shell 生成脚本        |
| `openssl-generate.bat`| OpenSSL 工具 Windows Batch 生成脚本      |
| `openssl-generate.sh` | OpenSSL 工具 Linux Shell 生成脚本        |
| `openssl-revoke.bat`  | OpenSSL 工具 Windows Batch 吊销脚本      |
| `openssl-revoke.sh`   | OpenSSL 工具 Linux Shell 吊销脚本        |

**注意事项**

- KeyTool 不支持证书吊销相关功能，且不支持私钥导出
- 可通过命令 `openssl version -d` 找到默认 `openssl.cnf` 文件位置
- KeyTool 生成脚本执行前请：
    - 修改脚本中 `USER_HOME` 变量为您的用户目录
    - 修改脚本中 `JAVA_HOME` 变量为您的 JRE 目录
- OpenSSL 生成脚本执行前请：
    - 修改脚本中 `OPENSSL_CONF` 变量为需要使用的 `openssl.cnf` 文件路径
    - 修改脚本中 `WORK_DIR` 参数与 `openssl.cnf` 配置文件中 `dir` 参数一致
    - 修改脚本中 `-subj` 变量以下字段为您自身的信息
        - `/C` 为国家名称缩写
        - `/ST` 为州或省名称
        - `/L` 为城市名称
        - `/O` 为组织名称
        - `/OU` 为组织单位名称
        - `/CN` 为通用名称（通常为应用名称或应用域名）
- OpenSSL 吊销脚本执行前请：
    - 修改脚本中 `OPENSSL_CONF` 变量为需要使用的 `openssl.cnf` 文件路径
    - 修改脚本中 `WORK_DIR` 参数与 `openssl.cnf` 配置文件中 `dir` 参数一致
    - 修改 `REVOKE_FILE` 变量为需要吊销的证书路径
    - 修改 `CRL_FILE` 变量为 CA 证书吊销清单文件路径
- 参数 `-days` 指定了证书的有效时间（单位：天）

## 文件说明

上述脚本执行成功后，将生成以下目录结构：

### KeyTool

```
demoCA/                     脚本工作目录
├── cacert.pem              证书颁发机构证书文件
├── cakey.pem               证书颁发机构私钥文件(需要OpenSSL才能生成)
├── ca.p12                  证书颁发机构 PKCS12 文件
├── database.crt            数据库证书文件
├── database.csr            数据库证书签名请求文件
├── database.key            数据库私钥文件(需要OpenSSL才能生成)
├── database.p12            数据库 PKCS12 文件
├── driver.crt              驱动证书文件
├── driver.csr              驱动证书签名请求文件
├── driver.key              驱动私钥文件(需要OpenSSL才能生成)
└── driver.p12              驱动 PKCS12 文件
```

其中，以下文件为数据库与驱动所需要的文件：

- `cakey.pem`：此文件用户应妥善保管，可存放于数据库目录
- 数据库端
    - `cacert.pem`：证书颁发机构证书  
        存放路径、文件名对应于 `xugu.ini` 文件中 `tls_ca_file` 参数  
        默认为 `BIN/ssl/cacerts.pem`
    - `crl.pem`：证书颁发机构证书吊销清单  
        存放路径、文件名对应于 `xugu.ini` 文件中 `tls_crl_file` 参数  
        默认为 `BIN/ssl/crl.pem`
    - `database.crt`：数据库证书  
        存放路径、文件名对应于 `xugu.ini` 文件中 `tls_crt_file` 参数  
        默认为 `BIN/ssl/database.crt`
    - `database.key`：数据库私钥  
        存放路径、文件名对应于 `xugu.ini` 文件中 `tls_key_file` 参数  
        默认为 `BIN/ssl/database.key`
- 驱动端
    - `cacert.pem`：证书颁发机构证书
    - `crl.pem`：证书颁发机构证书吊销清单
    - `driver.crt`：驱动证书
    - `driver.key`：驱动私钥

### Tongsuo

```
demoCA/                     脚本工作目录
├── cacert-inter.pem        中间证书颁发机构证书文件
├── cacert-root.pem         根证书颁发机构证书文件
├── careq-inter.pem         中间证书颁发机构证书签名请求文件
├── careq-root.pem          根证书颁发机构证书签名请求文件
├── certs                   证书颁发机构签发证书目录
│   ├── database-enc.crt    数据库加密证书文件
│   ├── database-sign.crt   数据库签名证书文件
│   ├── driver-enc.crt      驱动加密证书文件
│   └── driver-sign.crt     驱动签名证书文件
├── index.txt               新 Tongsuo 证书索引文件
├── index.txt.attr          新 Tongsuo 证书索引属性文件
├── index.txt.attr.old      旧 Tongsuo 证书索引属性文件
├── index.txt.old           旧 Tongsuo 证书索引文件
├── newcerts                待签发的证书签名请求目录
│   ├── database-enc.csr    数据库加密证书签名请求文件
│   ├── database-sign.csr   数据库签名证书签名请求文件
│   ├── driver-enc.csr      驱动加密证书签名请求文件
│   └── driver-sign.csr     驱动签名证书签名请求文件
├── private                 私钥目录
│   ├── cakey-inter.pem     中间证书颁发机构私钥文件
│   ├── cakey-root.pem      根证书颁发机构私钥文件
│   ├── database-enc.key    数据库加密私钥文件
│   ├── database-sign.key   数据库签名私钥文件
│   ├── driver-enc.key      驱动加密私钥文件
│   └── driver-sign.key     驱动签名私钥文件
├── serial                  新证书序号文件
└── serial.old              旧证书序号文件
```

其中，以下文件为数据库与驱动所需要的文件：

- `cakey-*.pem`：此文件用户应妥善保管，可存放于数据库目录
- 数据库端
    - `database-sign.crt`：数据库签名证书  
        存放路径、文件名对应于 `xugu.ini` 文件中 `gmssl_sign_crt_file` 参数  
        默认为 `BIN/gmssl/database-sign.crt`
    - `database-sign.key`：数据库签名私钥  
        存放路径、文件名对应于 `xugu.ini` 文件中 `gmssl_sign_key_file` 参数  
        默认为 `BIN/gmssl/database-sign.key`
    - `database-enc.crt`：数据库加密证书  
        存放路径、文件名对应于 `xugu.ini` 文件中 `gmssl_enc_crt_file` 参数  
        默认为 `BIN/gmssl/database-enc.crt`
    - `database-enc.key`：数据库加密私钥  
        存放路径、文件名对应于 `xugu.ini` 文件中 `gmssl_enc_key_file` 参数  
        默认为 `BIN/gmssl/database-enc.key`
- 驱动端
    - `driver-sign.crt`：驱动签名证书
    - `driver-sign.crt`：驱动签名私钥
    - `driver-enc.crt`：驱动加密证书
    - `driver-enc.key`：驱动加密私钥

### OpenSSL

```
demoCA/                     脚本工作目录
├── cacert.pem              证书颁发机构证书文件
├── careq.pem               证书颁发机构证书签名请求文件
├── certs                   证书颁发机构签发证书目录
│   ├── database.crt        数据库证书文件
│   └── driver.crt          驱动证书文件
├── crl                     证书颁发机构吊销证书目录
├── crlnumber               新证书吊销列表文件序号文件
├── crlnumber.old           旧证书吊销列表文件序号文件
├── crl.pem                 证书颁发机构吊销证书清单文件（空白清单）
├── index.txt               新 OpenSSL 证书索引文件
├── index.txt.attr          新 OpenSSL 证书索引属性文件
├── index.txt.attr.old      旧 OpenSSL 证书索引属性文件
├── index.txt.old           旧 OpenSSL 证书索引文件
├── newcerts                待签发的证书签名请求目录
│   ├── database.csr        数据库证书签名请求文件
│   └── driver.csr          驱动证书签名请求文件
├── private                 私钥目录
│   ├── cakey.pem           证书颁发机构私钥文件
│   ├── database.key        数据库私钥文件
│   └── driver.key          驱动私钥文件
├── serial                  新证书序号文件
└── serial.old              旧证书序号文件
```

其中，以下文件为数据库与驱动所需要的文件：

- `cakey.pem`：此文件用户应妥善保管，可存放于数据库目录
- 数据库端
    - `cacert.pem`：证书颁发机构证书  
        存放路径、文件名对应于 `xugu.ini` 文件中 `tls_ca_file` 参数  
        默认为 `BIN/ssl/cacerts.pem`
    - `crl.pem`：证书颁发机构证书吊销清单  
        存放路径、文件名对应于 `xugu.ini` 文件中 `tls_crl_file` 参数  
        默认为 `BIN/ssl/crl.pem`
    - `database.crt`：数据库证书  
        存放路径、文件名对应于 `xugu.ini` 文件中 `tls_crt_file` 参数  
        默认为 `BIN/ssl/database.crt`
    - `database.key`：数据库私钥  
        存放路径、文件名对应于 `xugu.ini` 文件中 `tls_key_file` 参数  
        默认为 `BIN/ssl/database.key`
- 驱动端
    - `cacert.pem`：证书颁发机构证书
    - `crl.pem`：证书颁发机构证书吊销清单
    - `driver.crt`：驱动证书
    - `driver.key`：驱动私钥

## 驱动适配

1. 引入 SSL/TLS 库，并启用对端证书验证以及吊销验证  
    - C/C++ 可使用 Tongsuo 实现
    - Java 可封装 Tongsuo 实现
1. 初始化相关全局资源
    - TLS
        1. 加载 CA 证书至可信存储
        1. 加载 CA 证书吊销列表
        1. 加载 CA 签发的驱动证书
        1. 加载 CA 签发的驱动私钥
    - TLCP
        1. 加载 CA 签发的驱动签名证书
        1. 加载 CA 签发的驱动签名私钥
        1. 加载 CA 签发的驱动加密证书
        1. 加载 CA 签发的驱动加密私钥
1. 使用 socket 连接到数据库
1. 发送消息至数据库启用连接加密
    - TLS： `~tls~` 
    - TLCP： `gmssl` 
1. 接收 `ok` 消息代表连接加密已启用，其他情况均视为失败
1. 使用 SSL/TLS 库建立加密连接（请参见 SSL/TLS 库文档）
1. 使用构建的加密连接对象进行所有后续通信
