传输层安全

  • 安全通信
  • 避免窃听
  • 确认另一端连接者的身份

名词解释

CA (Certificate Authority) 证书授权中心,是数字证书颁发和管理的机构。
DN (Distinguished Name) 标识名,指定实体身份的字段。
CSR (Certificate Signing Request) 数字证书签名请求,其中包含了公钥和DN

证书机制

根证书:是 CA 机构颁发 SSL 证书的核心,是信任链的起始点。受信任的根证书是属于证书颁发机构(CA),而 CA 机构是验证和颁发 SSL 证书的组织机构。

证书链:由两个环节组成,信任锚证书环节 和 已签名证书环节。信任锚证书环节可以对中间证书签名;中间证书的所有者可以用自己的私钥对另一个证书签名,两者结合就构成证书链。
用户获取 SSL 证书之前,首先生成 证书签名请求 和 私钥,然后将生成的签名请求发送到证书颁发机构,再使用证书颁发机构的根证书的私钥签署用户的 SSL 证书,并将 SSL 证书发回给用户。

中间证书:证书颁发机构不会直接从根目录颁发 SSL 证书,一旦发生错误,颁发者或需求者需要撤销根证书,则使用根证书签名的每个证书都会被撤销信任。为了避免这种风险发生,CA 机构一般会引用中间根。CA 机构使用中间根的私钥来签署用户申请的 SSL 证书。这种中间根的形式可以重复多次,即使用中间根签署另一个中间证书。

根证书CA 和 中间根CA 的区别:
根证书CA是拥有一个或多个受信任的根证书颁发机构,即CA机构已经扎根在主要浏览器的信任库中,而中间根CA或子CA是颁发中间根的证书颁发机构,他们不一定在浏览器的信任库中有根证书,而是将他们的中间根链接到手信任的第三方根,被称为交叉签名。

链式根 和 单一根 之间的区别:
单一根是由CA拥有的,可直接颁发证书。链式根是SubCA用于颁发证书的内容,是一个中间证书,必须链接到第三方受信任的CA。
链式根需要复杂的安装方法,因为中间根需要加载到托管证书的每个服务器和应用程序。
链式根需要受到链接的 CA 支配,无法控制 root 用户,一旦root CA 停业,就会受到巨大的牵连。

证书格式

x509 证书常见扩展名:DERPEMCRTCER

  • .DER
    用于二进制 DER 编码证书。
  • .PEM
    用于不同类型的 x509v3 文件,以“-BEGIN”为前缀的 ASCII(或 Base64)数据。
  • .CRT
    用于证书,可被编码为二进制 DER 或 ASCII PEM,常见于类 Unix 系统。
  • .CER
    CRT 的替代形式(Microsoft Convention),Windows 环境下 .crt 可转为 .cer。
    证书中只包含公钥,没有私钥。
  • .KEY
    用于公钥和私钥 PKCS#8,可被编码为二进制 DER 或 ASCII PEM。
  • .PFX
    带私钥的证书(包含公钥和私钥)。
    由 Public Key Cryptography Standards #12,PKCS#12标准定义,包含了公钥和私钥的二进制格式的证书形式,以 pfx 或 p12 作为证书文件后缀名。

颁发实战

  1. 配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    [ca]
    default_ca=CA_default

    [CA_default]
    policy=policy_match
    new_certs_dir=newcerts
    database=index.txt
    default_md=default
    serial=serial.txt
    default_days=3650

    [policy_match]
    countryName=match
    stateOrProvinceName=match
    organizationName=match
    organizationalUnitName=optional
    commonName=supplied
    emailAddress=optional

    [policy_anything]
    countryName=optional
    stateOrProvinceName=optional
    localityName=optional
    organizationName=optional
    organizationalUnitName=optional
    commonName=supplied
    emailAddress=optional

    [test]
    countryName=CN
    stateOrProvinceName=GuangDong
    organizationName=BGI
    organizationalUnitName=MGIUS
    commonName=MGIUSDICOM
    emailAddress=jiangchuanbiao@genomics.cn

    [req]
    default_bits=1024
    default_keyfile=private_key.pem
    distinguished_name=req_distinguished_name
    attributtes=req_attributes

    [req_distinguished_name]
    countryName=Country Name (2 letter code)
    countryName_min=2
    countryName_max=2
    stateOrProvinceName=State or Province Name (full name)
    localityName=Locality Name (eg, city)
    organizationName=Organization Name (eg, company)
    organizationalUnitName=Organizational Unit Name (eg, section)
    commonName=Common Name (eg. YOUR name)
    commonName_max=64
    emailAddress=Email Address
    emailAddress_max=40

    [req_attributes]
    challengePassword=A challenge password
    challengePassword_min=4
    challengePassword_max=20
    unstructuredName=An optional company name
  2. 自签名

    1
    2
    3
    4
    5
    6
    7
    8
    # 1.生成私钥
    $ openssl genrsa -out server.key 2048

    # 2.生成 CSR (Certificate Signing Request)
    $ openssl req -subj "/C=CN/ST=GD/L=Shenzhen/O=Self/OU=ShuanglongTest/CN=Shuanglong/emailAddress=xjshuanglong@126.com" -new -key server.key -out server.csr

    # 3.生成自签名证书
    $ openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt
  3. 私有 CA 签名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 1.创建 CA 私钥
    $ openssl genrsa -out ca.key 2048

    # 2.生成 CA 的自签名证书
    $ openssl req -subj "/C=CN/ST=Tianjin/L=Tianjin/O=Mocha/OU=Mocha Software/CN=Server CA/emailAddress=test@mochasoft.com.cn" -new -x509 -days 3650 -key ca.key -out ca.crt

    # 3.生成需要颁发证书的私钥
    $ openssl genrsa -out server.key 2048

    # 4.生成要颁发证书的证书签名请求,证书签名请求当中的 Common Name 必须区别于 CA 的证书里面的 Common Name
    $ openssl req -subj "/C=CN/ST=Tianjin/L=Tianjin/O=Mocha/OU=Mocha Software/CN=test2.sslpoc.com/emailAddress=test@mochasoft.com.cn" -new -key server.key -out server.csr

    # 5.2 创建的 CA 证书给 4 生成的 签名请求 进行签名
    $ openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

编程模式

  • 建立 SSL 上下文环境后使用 BIO 进行通信
  • 基于已建立的 Socket 连接创建 SSL 上下文环境

接口调用步骤: 参考 https://www.cnblogs.com/LittleHann/p/3741907.html
服务端步骤

客户端步骤

经验总结

  1. 类封装思想
    参考自 DCMTK,环境上下文与连接分开封装:
    DcmTLSTransportLayer 用于 SSL 上下文环境初始化、加载秘钥、加载证书、设置验证类型、设置加密套件;
    DcmTLSConnection 用于 SSL 连接握手、重协商、请求认证、读写数据、关闭连接。

    思考结果:为确保 SSL 上下文环境只初始化一次,要么使全局/静态用标志位,要么干脆将上下文换件封装成静态方法,可与 SSL 通信环境同处一个类,也可分开各自为政。

  2. 命令行卡死 (Windows + GitBash)
    执行命令 openssl genrsa -des3 -out test.key 2048 后,进程假死,无法执行后续操作,只有结束当前进程。
    在 windows 命令行中执行,会提示输入密码。
    此时可通过传入参数传递密码,而不是通过标准输入传入密码。
    openssl genrsa -des3 -passout pass:mima -out test.key 2048
    验证密码正确性:openssl rsa -in test.key -check,根据提示输入密码短语。
    注:使用 CMD,GitBash 似乎无效即使加入 -passout pass:mima

  3. GitBash 执行 DCMTK 测试程序时出现卡死
    通过任务管理器杀死 DCMTK 测试程序,GitBash 恢复命令行模式,即可继续操作。

  4. Conquest DICOM Server 添加 SSL 双向认证后,出现 SSL_read 阻塞现象,整个线程卡死且端口长时间占用无法释放。
    服务器采用 select + block socket 模型,通常情况下不会阻塞,抓包发现服务端发出的应答包丢失,客户端超时重发仍无法收到确认包的情况下发送 RST 报文,但服务端阻塞线程依然无法退出,线程僵死且处于半连接状态。
    初步确认为,OpenSSL 记录协议,需要读取到完整的记录才能解密,才认为 socket 读取完毕,否则一致阻塞。

  5. OpenSSL 自签名证书在 Chrome 下报告 Subject Alternative Name Missing 错误

    1
    2
    3
    4
    Certificate - Subject Alternative Name missing
    The certificate for this site does not contain a Subject Alternative Name extension containing a domain name or IP address.
    Certificate - missing
    This site is missing a valid, trusted certificate (net::ERR_CERT_COMMON_NAME_INVALID).

    处理方法:生成证书时加入参数 -sha256 -extfile v3.ext。
    v3.ext 内容如下: (DOMAIN 替换为域名)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    authorityKeyIdentifier=keyid,issuer
    basicConstraints=CA:FALSE
    keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
    subjectAltName = @alt_names

    [alt_names]
    DNS.1 = %%DOMAIN%%
    DNS.2 = %%DOMAIN%%
    IP.1 = %%IP%%
    IP.2 = %%IP%%
  6. OpenSSL 的扩展用途:

    1
    2
    3
    4
    5
    6
    Client Authentication  --- 1.3.6.1.5.5.7.3.2
    Server Authentication --- 1.3.6.1.5.5.7.3.1
    Secure Email ------------ 1.3.6.1.5.5.7.3.4
    Code Signing ------------ 1.3.6.1.5.5.7.3.3
    Timestamp Signing ------- 1.3.6.1.5.5.7.3.8
    // 更多参考:https://oidref.com/1.3.6.1.5.5.7.3.2
  7. 关于本地调试遇到的问题:
    net::ERR_CERT_COMMON_NAME_INVALID
    net::ERR_CERT_DATE_INVALID
    处理方法:COMMON_NAME 代表证书中的服务器域名,使用正确的域名(生成签名请求时指定 Common Name 或者在 extfile 中添加 Subject Alternative Name, 本地环境建议加入 localhost);DATE INVALID 是指证书过期了,openssl x509 检查日期,注意,-days 参数值竟然可以是负数(时间往前推)。

  8. OpenSSL 查看代码签名文件信息
    windows 代码签名文件扩展名为 .cer,属于 DER 编码格式:
    openssl.exe x509 -inform DER -text -noout -in sign.cer

参考网址

基于 OpenSSL 自建 CA 和颁发 SSL 证书
google-chrome – Chrome:无效的自签名SSL证书 – “Subject Alternative Name Missing”
OpenSSL自签发配置有多域名或ip地址的证书
https wireshark抓包——要解密出原始数据光有ssl 证书还不行,还要有浏览器内的pre-master-secret(内存里)
RSA与 Diffie-Hellman密钥交换 的区别
SSL/TLS协议详解(下)——TLS握手协议

留言