zoukankan      html  css  js  c++  java
  • OpenSSL(2)创建私有证书颁发机构

      如果想要建立自己的CA, OpenSSL已经包含了所有你需要的东西。所有的操作都通过纯命令行执行,虽然不那么友好,整个过程也比较长,但是这可以让你去思考每个细节。

      我建议自己创建一套私有的 CA主要是出于教学的目的,不过还有一些别的原因。OpenSSL的CA天然满足个人或者小团体的需求,例如在开发环境使用一套CA比到处使用自签名的证书好得多。同时还可以通过客户端证书来提供双向验证,这可以极大地提高敏感Web应用的安全性。

      运行私有CA最大的挑战不是设置问题,而是如何保证基础结构的安全。例如根密钥必须离线保存,因为所有的安全都依赖它。另一方面, CRL和OCSP响应程序证书必须定期进行更新,而这会要求根密钥保持联机。

    功能和限制

    我们会创建一个与公共CA类似的私有CA架构。会先有一个根CA,然后创建其他的二级CA。接着我们会通过CRL和OCSP服务提供证书吊销信息。为了让根CA的私钥可以离线保存, OCSP响应程序需要使用它们自己的身份。这并非是最简单的CA,但是相对来说比较安全。另外二级CA会在技术上进行限制,只能给允许的主机名签发证书

    完成设置之后,必须将根证书安全地分发给所有客户端。一旦根证书分发完毕,就可以开始签发客户端和服务器证书了。有一个限制是以这种方式设置的OCSP响应程序主要用来测试,因为只能承受比较小的负载。

    创建根 CA 

    创建全新的CA有几个步骤:配置、创建目录结构和初始化密钥文件,最后生成根密钥和证书。本节描述了整个过程和常见的CA操作。

    1)根CA配置

    创建CA之前,我们需要先准备一个配置文件告诉OpenSSL我们希望的配置。一般情况下并不需要配置文件,但是根CA的创建操作复杂,使用配置文件可以简便很多。 OpenSSL的配置文件很强大,在开始之前我建议你熟悉一下这些配置的功能(命令行上使用man config命令)。

    配置文件第一部分包括了CA的名称、基础URL和CA可分辨名称等基本信息。因为这些配置都很灵活,只需配置一次即可。

    [default]
    name = root-ca
    domain_suffix = example.com
    aia_url = http://$name.$domain_suffix/$name.crt
    crl_url = http://$name.$domain_suffix/$name.crl
    ocsp_url = http://ocsp.$name.$domain_suffix:9080
    default_ca = ca_default
    name_opt = utf8,esc_ctrl,multiline,lname,align
    [ca_dn]
    countryName = "GB"
    organizationName = "Example"
    commonName = "Root CA"

    第二部分直接控制了CA的操作。有关每个设置的完整信息,可以通过ca命令来获取它的文档(命令行上输入man ca)。大部分命令从字面意思就可以很容易理解,我们需要告诉OpenSSL存放文件的路径。因为根CA只用作二级CA的签发,所以我把有效期设置为10年。另外默认情况下使用SHA256作为签名算法。

    默认策略( policy_c_o_match)限制了这张CA签发的证书的国家名和组织名会与CA本身一样。对于公共CA来说很少会有这样的设置,但对于私有CA来说这种方式比较合适:

    [ca_default]
    home = .
    database = $home/db/index
    serial = $home/db/serial
    crlnumber = $home/db/crlnumber
    certificate = $home/$name.crt
    private_key = $home/private/$name.key
    RANDFILE = $home/private/random
    new_certs_dir = $home/certs
    unique_subject = no
    copy_extensions = none
    default_days = 3650
    default_crl_days = 365
    default_md = sha256
    policy = policy_c_o_match
    [policy_c_o_match]
    countryName = match
    stateOrProvinceName = optional
    organizationName = match
    organizationalUnitName = optional
    commonName = supplied
    emailAddress = optional

    第三部包含了req命令的配置, req命令只会在创建自签发根证书的时候用到一次。最重要的部分是扩展:基本限制( basicContraints)扩展表明这个证书是一张CA,密钥用法( keyUsage)扩展用来说明这个CA的用处:

    [req]
    default_bits = 4096
    encrypt_key = yes
    default_md = sha256
    utf8 = yes
    string_mask = utf8only
    prompt = no
    distinguished_name = ca_dn
    req_extensions = ca_ext
    [ca_ext]
    basicConstraints = critical,CA:true
    keyUsage = critical,keyCertSign,cRLSign
    subjectKeyIdentifier = hash

    配置的第四部分包括了根CA创建证书所需要的信息。因为基本限制( basicContraints)扩展的设置,所有的证书都将成为CA,但是我们需要把pathlen设置为0,表示这些CA无法再签发新的CA了。

    所有二级CA都会受到限制,也就是说他们签发的证书只能对一些域名的子集有效,并且会被限制使用场景。第一,扩展密钥用法( extendedKeyUsage)扩展限制了只能进行客户端验证( clientAuth)和服务器验证( serverAuth),也就是TLS的客户端和服务器验证。第二,名称限制( nameContraints)扩展限制了允许签发的域名只有example.com和example.org。理论上这样的设置让你可以签发二级CA给第三方,同时可以通过限制他们无法签发任意域名的主机名来保证安全。排除这两个IP段的要求来自CAB论坛的Baseline Requirements,该规范从技术上定义了对二级CA的限制。

    实际上,名称限制( nameContraints)并不完美,因为当前还有很多主流的平台无法识别名称限制扩展。如果你将这个扩展标记为关键扩展,就会导致很多平台拒绝识别你的证书。如果将其标记为关键扩展,那么很多平台就不会识别这个扩展,导致名称限制实际没有任何效果。

    [sub_ca_ext]
    authorityInfoAccess = @issuer_info
    authorityKeyIdentifier = keyid:always
    basicConstraints = critical,CA:true,pathlen:0
    crlDistributionPoints = @crl_info
    extendedKeyUsage = clientAuth,serverAuth
    keyUsage = critical,keyCertSign,cRLSign
    nameConstraints = @name_constraints
    subjectKeyIdentifier = hash
    [crl_info]
    URI.0 = $crl_url
    [issuer_info]
    caIssuers;URI.0 = $aia_url
    OCSP;URI.0 = $ocsp_url
    [name_constraints]
    permitted;DNS.0=example.com
    permitted;DNS.1=example.org
    excluded;IP.0=0.0.0.0/0.0.0.0
    excluded;IP.1=0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0

    最后两部分的配置表示有了这个扩展的证书可以对OCSP响应进行签名。为了能够运行OCSP响应程序,我们生成一个特别的证书,并且将OCSP的签名能力赋予这张证书。从扩展可以看出这张证书不是一个CA:

    [ocsp_ext]
    authorityKeyIdentifier = keyid:always
    basicConstraints = critical,CA:false
    extendedKeyUsage = OCSPSigning
    keyUsage = critical,digitalSignature
    subjectKeyIdentifier = hash

    2)根CA的目录结构

    下面我们会创建“根CA配置”中说到的目录结构,并且会初始化一些CA操作中会用到的文件。

    $ mkdir root-ca
    $ cd root-ca
    $ mkdir certs db private
    $ chmod 700 private
    $ touch db/index
    $ openssl rand -hex 16 > db/serial
    $ echo 1001 > db/crlnumber
    我们会用到以下这几个目录。
     certs/
    存放证书的地方;证书在签名之后会放置到这个目录下。
     db/
    这个目录用于证书数据库( index),一些包括下一张证书以及CRL数字的文件。 OpenSSL
    会创建额外需要的一些文件。
     private/
    这个目录会存放私钥,一个给CA使用,一个给OCSP响应程序使用。务必确保其他用户
    都不能访问这个目录(事实上,如果你真的很在意这个CA,那么这台存放根证书和密钥
    的服务器的用户账户必须尽可能少)。

    3)CA生成

    我们需要分两步来创建根CA。首先,我们生成密钥和CSR文件。当我们使用-config开关之后,所有需要的信息都会从配置文件中加载进来

    $ openssl req -new 
    -config root-ca.conf 
    -out root-ca.csr 
    -keyout private/root-ca.key

    第二步我们会创建自签名证书。 -extension开关指向了配置文件的ca_ext部分,这样可以激活根CA所需的扩展。

    $ openssl ca -selfsign 
    -config root-ca.conf 
    -in root-ca.csr 
    -out root-ca.crt 
    -extensions ca_ext

    4)数据库文件结构 

    db/index中的数据库是一个包含证书信息的明文文件,每行一个证书。我们刚刚创建根CA,现在这个文件只有一行信息

    V 240706115345Z 1001 unknown /C=GB/O=Example/CN=Root CA

    每一行包括以下6个以制表符分隔的值。

    (1) 状态标记[ V表示有效( valid), R表示已吊销( revoked), E表示已过期( expired)]
    (2) 过期时间(以YYMMDDHHMMSSZ格式表示)
    (3) 吊销日期,如果没有被吊销则为空
    (4) 序列号(十六进制)
    (5) 文件路径(如果不知道就显示unknown)
    (6) 可分辨名称

    5)CA操作

    使用ca命令的-gencrl开关给新CA生成CRL

    $ openssl ca -gencrl 
    -config root-ca.conf 
    -out root-ca.crl

    使用ca的的命令来签发证书。需要注意的是-extensions开关需要指向配置文件里面正确的部分(例如,你肯定不希望再生成另一个根CA)。

    $ openssl ca 
    -config root-ca.conf 
    -in sub-ca.csr 
    -out sub-ca.crt 
    -extensions sub_ca_ext

      如果要吊销证书,可以使用ca命令的-revoke开关,不过需要有一份你想吊销的证书的副本。不过因为所有的证书都存在certs/目录下,所以只需要知道序列号即可。如果知道证书的可分辨名称,就可以在数据库里面查到它的序列号了。
      为-crl_reason开关中的值选择一个正确的理由。该值可以是以下这些值之一: unspecified、keyCompromise 、 CACompromise 、 affiliationChanged 、 superseded 、 cessationOfOperation 、certificateHold和removeFromCRL。

    $ openssl ca 
    -config root-ca.conf 
    -revoke certs/1002.pem 
    -crl_reason keyCompromise

    6)创建用于OCSP签名的证书

    首先我们需要给OCSP响应程序创建一个私钥和CSR。这两个操作对所有的非CA证书都适用,所以不需要指定配置文件:

    $ openssl req -new 
    -newkey rsa:2048 
    -subj "/C=GB/O=Example/CN=OCSP Root Responder" 
    -keyout private/root-ocsp.key 
    -out root-ocsp.csr

    第二步需要使用根CA签发一张证书。 -extensions开关的值选择ocsp_ext,以确保设置了OCSP签名所需要的扩展。我将这个证书的生命周期减少为365天(原来默认是3650天)。这些OCSP证书是没有吊销信息的,所以无法吊销它们。因此你会希望尽可能减少它们的生命周期。 30天是一个比较好的选择,当然前提是你已经准备好频繁地创建新的OCSP证书。

    $ openssl ca 
    -config root-ca.conf 
    -in root-ocsp.csr 
    -out root-ocsp.crt 
    -extensions ocsp_ext 
    -days 30

    现在你已经有了OCSP响应程序所需要的一切东西,可以直接在根CA所在的服务器上进行测试。当然,如果在生产环境中使用,就必须将OCSP响应程序的密钥和证书放到别的地方

    $ openssl ocsp 
    -port 9080
    -index db/index 
    -rsigner root-ocsp.crt 
    -rkey private/root-ocsp.key 
    -CA root-ca.crt 
    -text

    可以使用下面的命令来测试OCSP响应程序:

    $ openssl ocsp 
    -issuer root-ca.crt 
    -CAfile root-ca.crt 
    -cert root-ocsp.crt 
    -url http://127.0.0.1:9080

    输出结果中的verify OK表示已经成功验证签名,而good表示这张证书还没有被吊销。

    Response verify OK
    root-ocsp.crt: good
    This Update: Jul 9 18:45:34 2014 GMT

    创建二级 CA

    创建二级CA的过程和根CA几乎完全一样。

    1)二级CA配置

    我们可以在前面根CA配置文件的基础上,进行一些适当的修改生成二级CA的配置。我们会把名称改为sub-ca并且使用另一个可分辨名称。我们将二级CA的OCSP响应程序放在另外一个端口,主要是因为ocsp命令不识别虚拟主机。如果为OCSP响应程序使用了适合的Web服务器,就可以完全避免使用特别的端口。该证书默认的生命周期是365天,我们会每隔30天生成全新的CRL。

    将copy_extensions更改为copy意味着在生成新证书的时候,如果我们的配置文件里面没有设置某些扩展,那么就会使用CSR文件里面的扩展字段。进行此更改之后,在准备CSR文件的时候就可以加入别的一些需要的字段,这些信息会在生成证书的时候加入到证书里面。这个特性有几分危险(因为允许其他人可以在一定程度上直接控制证书里面的内容),不过我认为在较小的环境中这么做是可以的。

    [default]
    name = sub-ca
    ocsp_url = http://ocsp.$name.$domain_suffix:9081
    [ca_dn]
    countryName = "GB"
    organizationName = "Example"
    commonName = "Sub CA"
    [ca_default]
    default_days = 365
    default_crl_days = 30
    copy_extensions = copy

    在配置文件的最后面,我们会增加两个新的配置,分别用于服务器和客户端证书的生成。唯一的区别就是keyUsage和extendedKeyUsage扩展。注意到我们把basicContraints扩展的值设置为false。之所以这么做,原因在于我们会复制CSR文件里面的扩展。如果在配置文件中没有显示设置这个扩展,那么就可能会用到CSR文件中的basicContraints了。

    [server_ext]
    authorityInfoAccess = @issuer_info
    authorityKeyIdentifier = keyid:always
    basicConstraints = critical,CA:false
    crlDistributionPoints = @crl_info
    extendedKeyUsage = clientAuth,serverAuth
    keyUsage = critical,digitalSignature,keyEncipherment
    subjectKeyIdentifier = hash
    [client_ext]
    authorityInfoAccess = @issuer_info
    authorityKeyIdentifier = keyid:always
    basicConstraints = critical,CA:false
    crlDistributionPoints = @crl_info
    extendedKeyUsage = clientAuth
    keyUsage = critical,digitalSignature
    subjectKeyIdentifier = hash

    改好配置文件之后,按照根CA的过程创建一个同样的目录结构,不过可以使用另外一个名称,比如sub-ca。

    2)二级CA生成

    与前面一样,创建二级CA需要两步。第一步生成密钥和CSR。当我们使用-config开关的时候,所有需要的信息都会从配置文件中加载进来。

    $ openssl req -new 
    -config sub-ca.conf 
    -out sub-ca.csr 
    -keyout private/sub-ca.key

    第二步我们使用根CA来签发证书。 -extensions开关指向配置文件中的sub_ca_ext,从而使用二级CA所需要的扩展。

    $ openssl ca 
    -config root-ca.conf 
    -in sub-ca.csr 
    -out sub-ca.crt 
    -extensions sub_ca_ext

    3)二级CA操作

    要签发服务器证书,可以在处理CSR文件的时候,在-extensions开关中指定server_ext

    $ openssl ca 
    -config sub-ca.conf 
    -in server.csr 
    -out server.crt 
    -extensions server_ext

    要签发客户端证书,可以在处理CSR文件的时候,在-extensions开关中指定client_ext

    $ openssl ca 
    -config sub-ca.conf 
    -in client.csr 
    -out client.crt 
    -extensions client_ext
    注意
    当收到新证书申请请求的时候,你需要在对所有信息进行验证之后才能进行操作。你
    需要确保所有资料符合规定,特别是当你处理的CSR文件是别人生成的时。特别要注
    意证书的可分辨名称以及basicContraints和subjectAlternativeName扩展。

    二级CA的CRL生成和证书的吊销过程与根CA是一样的。唯一不同的是OCSP响应程序所使用的端口;二级CA使用的是9081端口。推荐OCSP响应程序使用独立的证书,这样可以避免将二级CA部署到公开的服务器上.

     

    本文摘自《OpenSSL攻略》 

    详细操作扩展https://www.cnblogs.com/sparkdev/p/10369313.html

  • 相关阅读:
    python中字典一键多相同值反转技巧
    win10下安装mysql
    上台阶问题的具体走法用python来实现
    桥接模式
    适配器模式
    多线程中lock的使用
    原型模式
    多线程
    建造者模式
    代理模式
  • 原文地址:https://www.cnblogs.com/xdyixia/p/11684426.html
Copyright © 2011-2022 走看看