1 概述

       本文之所以称之为半自动化,是因为证书的申请并非日常工作,只是一段时间才需要申请,同时,在创建证书和办法证书的时候,有些参数需要根据用户的需求自己调整,如证书的有效时间,还有,是否给私钥加密等等,因为叫脚本设置为半自动化,手动输入一些参数,到达用户的需求。当然如果环境是固定,参数也是固定,有效时间固定,该脚本配合crontab也可以实现自动化申请和颁发等操作

       CA机构,又称为证书授证(Certificate Authority)中心,作为电子商务交易中受信任和具有权威性的第三方,承担公钥体系中公钥的合法性检验的责任。CA中心为每个使用公开密钥的客户发放数字证书,

数字证书的作用是证明证书中列出的客户合法拥有证书中列出的公开密钥。CA机构的数字签名使得第三者不能伪造和篡改证书。它负责产生、分配并管理所有参与网上信息交换各方所需的数字证书,因此是安全电子信息交换的核心。

     更多关于PKI系统深入介绍,推荐查看如下博客

      http://blog.csdn.net/liuhuiyi/article/details/7776825

      本文将介绍通过openssl这个工具如何创建私有根CA,私有子CA,证书申请,证书颁发 和吊销证书等操作进行介绍

2 概念

2.1 创建私有CA

openssl的配置文件:/etc/pki/tls/openssl.cnf.这个配置文件里的相关配置,如证书信息匹配策略,证书的相关文件保存路径和命名都在这里做规定,本文将在文末附属该配置文件部分重要参数的介绍

其中,证书信息匹配策略有三种:匹配、支持和可选

匹配指要求申请填写的信息跟CA设置信息必须一致,支持指必须填写这项申请信息,可选指可有可无

用户在自己机器生成证书请求文件后,将对应请求文件发给服务器,服务器收到请求文件后,确认无误,将对于进行签发,并把证书发给申请主机

2.2 证书申请步骤

证书的申请有如下四个步骤

a. 生成申请请求

由客户端自己创建,完成后将生成的文件发送到证书签发机构

b. RA核验,

RA(Registration Authority),数字证书注册审批机构。RA系统是CA的证书发放、管理的延伸。它负责证书申请者的信息录入、审核以及证书发放等工作(安全审计)。同时,对发放的证书完成相应的管理功能(安全管理)。

c. CA签署

核验通过后,在CA服务器生成证书 

d. 获取证书

将创建完成的证书发给申请者

3. 实验步骤

3.1 创建根CA

3.1.1、创建所需要的文件
touch /etc/pki/CA/index.txt 
#生成证书索引数据库文件
echo 01 > /etc/pki/CA/serial 
#指定第一个颁发证书的序列号

3.1.2 CA自签证书

要先有私钥,才能给自己颁发证书

生成私钥,文件名是固定的,而且目录也是当前固定的目录,因为在配置文件里指定了路径和名称

cd /etc/pki/CA/


执行以下这步后会在该目录下生成加密的文件

(umask 066; openssl  genrsa-out  /etc/pki/CA/private/cakey.pem  -des 3  2048)

.生成自签名证书,给自己签名,-x509是关键字,表示要自己申请,而且给自己颁发证书

这里文件的路径都是有要求的,以下要输入密码

openssl  req -new -x509 -key  /etc/pki/CA/private/cakey.pem   -days 7300 -out  /etc/pki/CA/cacert.pem

要输入密码,然后要提交信息

-new: 生成新证书签署请求

-x509: 专用于CA生成自签证书

-key: 生成请求时用到的私钥文件

-days n:证书的有效期限

-out /PATH/TO/SOMECERTFILE: 证书的保存路径

3.2 创建子CA

3.2.1 CA上创建私钥和证书请求文件

方法和根CA基本一致

在 /etc/pki/CA下创建serial 和index.txt


以下加密des3,如果加密,每次办法都要输入密码


作为子CA,不能给自己颁发证书,要向根CA申请证书,不加x509选项

生成subca.csr文件,把这个文件复制到服务器根CA对应的目录/etc/kpi/CA/

3.2.2 CA上颁发证书给子CA

这里对根私钥加了口令,所有要先输入密码,才能输入信息


生成文件subca.crt,把这个文件拷贝到子CA上,注意,这个文件拷贝到子CA上的时候,要把名称改成

cacert.pem,才能作为服务器端的私钥给客户端来签名颁发 

到这里服务器端根CA操作完成,此时子CA可以给其他的客户端颁发证书了

3.2.3  验证

找一台机器,向子CA申请证书


生成请求文件,这里输入的选项要和根CA的配置文件策略一致


完成后,将这个请求文件发送到子CA

这个操作在3.3里讲到


3.2.4 CA颁发证书给客户端

建议颁发的证书文件都放在统一的目录下,颁发的第一个证书是在serial01开始

openssl  ca -in rhel5.csr -out certs/rhel5.crt -days 300

出现如下报错,有的奇怪,都是henan,但是还是报错,因为这客户端版本5上的openssl版本和子CA上版本不一致,

导致不兼容。解决颁发是升级openssl的版本为同一版本


半自动化创建CA和申请证书_openssl

3.3颁发证书

3.3.1 在需要使用证书的主机生成证书请求

给web服务器生成私钥test.key 这个名字可以自命名,但是后缀不能 该,2048是长度

(umask066; openssl   genrsa-out /etc/pki/tls/private/test.key  2048)

生成证书申请文件,用私钥来生成请求文件,后缀一般建议为csr,和服务器生成基本一致,少了关键字-x509,表示不是自签名,而是申请证书

  -days 365申请时间,这个时间是没有意义的,因为是由服务器端颁发的时候指定,客户端指定时间是没有意义的

openssl  req  -new -key /etc/pki/tls/private/test.key -days 365 -out /etc/pki/tls/test.csr

这里的请求文件名(key名)每一次是默认要不一样的,如果要运行,需要更改index.txt.attr里的yes改成no

这里私钥文件没有加密des,所以和服务器不一样,不需要回车后填密码,只需要回车后填入信息

国家,省,公司这三项是配置模板里规定match的,所以要和服务器端一样

3.3.2 发送请求文件给CA

将证书请求文件传输给CA,可以用scp拷贝到服务器端对应的路径

3.3.3CA签署证书,并将证书颁发给请求者

 -days 365这里指定的时间是有效期,让客户端用多久的时间,有效的,不指定默认就是服务配置文件设定的时间

commonName = supplied这个字段是supplied,如果新的证书请求的信息的commonName和之前的请求信息一样,,那么当上一个请求信息生成的证书还没有被吊销的时候,新的证书将不再生成,生成0字节的文件

openssl  ca -in /tmp/test.csr -out /etc/pki/CA/certs/test.crt -days 365

完成后把证书文件发回给客户端

3.4  吊销证书

证书废除列表CRL(Certificate revocation lists,又称证书黑名单)为应用程序和其它系统提供了一种检验证书有效性的方式。任何一个证书废除以后,证书机构CA会通过发布CRL的方式来通知各个相关方。

比如当客户出现异常,服务器端可以吊销证书

3.4.1在客户端获取要吊销的证书的serial

openssl  x509 -in /PATH/FROM/CERT_FILE  [-noout|-serial|-subject]

3.4.2 在CA上吊销

根据客户提交的serial与subject信息,对比检验是

否与index.txt文件中的信息一致,吊销证书:

这一步是在CA服务上操作的,吊销后证书状态为R

openssl  ca -revoke /etc/pki/CA/newcerts/SERIAL.pem

吊销后,要把这个信息发布出去。客户端才知道哪些证书被吊销

3.4.3 指定第一个吊销证书的编号

在服务器根CA上操作

crlnumber证书吊销列表编号,在index.txt这个文件里可以看到证书的状态

echo 01 > /etc/pki/CA/crlnumber

/etc/pki/CA/crlnumber里保存的数字表示

接下去要吊销的是第几个证书,如已经吊销了5个证书,则当前文件保存的就是06,表示接下去要吊销第6个证书

注意:第一次更新证书吊销列表前,才需要执行,如果之前已经吊销过证书,这个语句就不需要执行了

3.4.4 更新证书吊销列表

把这个文件发布到官方网站上,让所有使用者都知道证书被吊销了

openssl ca  -gencrl  -out  /etc/pki/CA/crl/crl.pem

3.4.5查看crl文件

执行如下语句进行查看,不是必须的步骤

openssl crl -in  /etc/pki/CA/crl/crl.pem -noout  -text

4 半自动化脚本

以下的脚本,将实现以上5个步骤,为了方便演示,将操作写在同一脚本里。通过选项操作对应的操作。

用户只需要输入相关操作,就可以完成CA的搭建和证书申请,颁发,吊销等操作

脚本如下

#!/bin/bash
#
#******************************************************************************
#Author:               Sunny
#Date:                 2017-09-09
#FileName:             install_ca.sh
#version:              1.0
#Your change info:     
#Description:          For auto create CA,subCA,generate and revoke cert
#Copyright(C):         2017  All rihts reserved
#*****************************************************************************

CApath=/etc/pki/CA
certpath=/etc/pki/CA/certs
tlspath=/etc/pki/tls
tlsprivatepath=/etc/pki/tls/private
caprivatepate=/etc/pki/CA/private


#check certification info,run below cmd
#openssl x509 -in cent7bbaa.crt -noout -text

#check certification request infomation,run cmd as below
#openssl req -noout -text -in aa.csr

#check certification status,run cmd as below,01 is serial number
#openssl ca -status 01



active_ip(){
actip=$(ip a| grep -E "[0-9]+\/"| cut -d / -f1|sed -nr  's@.*( [0-9]+\.[^0][0-9]*\.[0-9]+\.[0-9]+)@\1@p'|cut -d " " -f2|head -1)
}

pri_key_name(){
echo "private key name should end with .key,such as clent.key"
read -p "enter your private key name(default:client."$actip".key) " prikey
if [ -z ${prikey:-} ];then
prikey=client."$actip".key
fi
}

cli_csr_name(){
echo "Cert request name should end with .crs,such as clent.csr"
read -p "enter your cert request name(default:client."$actip".csr) " clicsr
if [ -z ${clicsr:-} ];then
clicsr=client."$actip".csr
fi
}

key_length(){
echo "key length should be one of 1024,2048,4096"
read -p "enter your private key length(default:2048): " length
if [ -z ${length:-} ]; then
length=2048
fi
}


root_pre(){

[ -e "$CApath"/index.txt ] || touch  "$CApath"/index.txt
[ -e "$CApath"/serial ] || echo 01 >  "$CApath"/serial
#create a server private key
echo "unless you have modify ca private key name in /etc/pki/tls/openssl.cnf,only use default cakey.pem"read -p "enter your ca private key name accord to openssl.cnf (default:cakey.pem) " cakey
if [ -z ${cakey:-} ];then
cakey=cakey.pem
fi
key_length
if [ -e "$caprivatepate"/"$cakey"  ] ;then
echo "The server already have private key,$cakey, under "$caprivatepate"/,please check"
else
umask 066;
read -p "enter yes to encrypt private key,other enter will no enrypt: " yorn
if [ "$yorn" = yes ];then
   read -p "enter encrypt key word(eg:-des3): " encry
   openssl genrsa -out "$caprivatepate"/"$cakey" "$encry" "$length"
   else
    openssl genrsa -out "$caprivatepate"/"$cakey"  "$length"
fi
umask 022;
fi

}



echo "Enter 1 : run at root CA server and rootca_sig_itself"
echo "Enter 2 : run at sub_server,generate a private key and signature request file,and send request file to root CA "
echo "Enter 3 : run at client host,generate certification requst file and send to server auto"
echo "Enter 4 : run at server,generate certification and send to client auto"
echo "Enter 5 : run at server,to revoke some certification"
read -p "Please input your choice: " choice

case $choice in

1)

root_pre;

#generate a signature certificate for itself,-x509 is key work,means it signature to itself
echo "unless you have modify ca  signature certificate name in /etc/pki/tls/openssl.cnf,only use default cacert.pem"
read -p "enter your ca signature cer name accord to openssl.cnf (default:cacert.pem) " cacert
if [ -z ${cacert:-} ];then
cacert=cacert.pem
fi
if [ -e "$CApath"/"$cacert"  ] ;then
 echo "The server already have signature certificate,"$cacert" under "$CApath",please check"
 else
openssl  req -new -x509 -key "$caprivatepate"/"$cakey"   -days 7300 -out  "$CApath"/"$cacert"
fi
;;

2)

root_pre;
#generate a signature certificate request file and send to root CA
read -p "enter your ca signature cer request file  (default:subca.csr): " subcacert
if [ -z ${subcacert:-} ];then
subcacert=subca.csr
fi
if [ -e "$CApath"/"$subcacert"  ] ;then
 echo "The sub ca already have signature certificate,"$subcacert"under "$CApath",please check"
 else
openssl  req -new  -key "$caprivatepate"/"$cakey"   -days 7300 -out  "$CApath"/"$subcacert"
fi

#send request file to root CA
read -p "which root CA would you send(default:192.168.32.61): " serip
if [ -z ${serip:-} ];then
serip=192.168.32.61
fi
expect -c "
   spawn  scp   "$CApath"/"$subcacert"   root@"$serip":"$CApath"/certs/
   expect {
           \"*assword\" {set timeout 500; send \"Pass1234\r\"; }
           \"yes/no\" { send \"yes\r\"; exp_continue; }
    }
    expect eof"
;;

3)
echo "Please check whether you are in client"
#client generate private key
active_ip
pri_key_name
cli_csr_name
key_length


if [ -e "$tlsprivatepath"/"$prikey"  ] ;then
echo "The client already have private key "$prikey" under "$tlsprivatepat",please check"
else
umask 066;
if [ "$yorn" = yes ];then
   read -p "enter encrypt key word(eg:-des3): " encry
   openssl genrsa -out "$tlsprivatepath"/"$prikey" "$encry" "$length"
   else
    openssl genrsa -out "$tlsprivatepath"/"$prikey"  "$length"
fi
umask 022;
fi
#generate a signature certificate to root ca,without -x509.

if [ -e "$tlspath"/"$clicsr"  ] ;then
 echo "The client already have signature certificate request file,"$clicsr" under "$tlspath",please check"
 else
openssl req -new -key "$tlsprivatepath"/"$prikey" -out "$tlspath"/"$clicsr"
fi
#send request file to CA
read -p "which CA would you send(default:192.168.32.61): " serip
if [ -z ${serip:-} ];then
serip=192.168.32.61
fi
expect -c "
   spawn  scp  "$tlspath"/"$clicsr" root@"$serip":"$CApath"/certs/
   expect {
           \"*assword\" {set timeout 500; send \"Pass1234\r\"; }
           \"yes/no\" { send \"yes\r\"; exp_continue; }
    }
    expect eof"
;;
4)
read -p "enter which requst file in "$CApath"/certs you want want server to generate as certification(eg:cent7.csr): " clientrsq
read -p "enter new client cetification name(eg:cent7.crt): " crtname
[ -e "$CApath"/certs/"$crtname" ] && { echo $crtname exist,please check;exit 6; }
read -p "enter many days would the cert be avlid(eg:365): " days
if [ -e "$CApath"/certs/"$clientrsq" ];then
#attention,no only $crtname be generated,but also serial.pem file will be generate under dir newcerts

 openssl ca -in  "$CApath"/certs/"$clientrsq" -out "$CApath"/certs/"$crtname" -days "$days"
else
  echo "$clientrsq does no exist in "$CApath"/certs,please check"
fi

read -p "which client would you send(eg:192.168.32.61): " clip
expect -c "
   spawn  scp   "$CApath"/certs/"$crtname"  root@"$clip":"$tlspath"
   expect {
           \"*assword\" {set timeout 500; send \"Pass1234\r\"; }
           \"yes/no\" { send \"yes\r\"; exp_continue; }
    }
    expect eof"

;;
5)
read -p "Please input the serial number you want to revoke(eg:03): " sernum
echo "you can run cmd  openssl x509 -in cent7bt.crt -noout -text  to check the serial number,cent7bt.crt is the certification you want to revoke"
openssl ca -revoke /etc/pki/CA/newcerts/"$sernum".pem
crlnum=$(cat /etc/pki/CA/crlnumber)
[ -z $crlnum ] && echo 01 > /etc/pki/CA/crlnumber;
openssl ca -gencrl -out /etc/pki/CA/crl/crl.pem;
#check the the crl list
#openssl   crl  -in /etc/pki/CA/crl/crl.pem  -noout  -text
;;


*)
  echo  "your input is wrong,please check"
  ;;
esac


unset ip
unset crtname
unset CApath
unset clinetsrq


5 /etc/pki/tls/openssl.cnf 讲解

本附录只针对一些重要字段用中文做了备注,内容如下

/etc/pki/tls/openssl.cnf 
CA的配置文件,这个文件文件很关键,配置和CA密切相关

[ CA_default ]  这里新创建的文件名必须一样,如果要改,就要跟defaults一样

dir     = /etc/pki/CA       # Where everything is kept,CA工作目录,CA信息保存的目录
                             #
certs       = $dir/certs        # Where the issued certs are kept,定义一个变量
crl_dir     = $dir/crl      # Where the issued crl are kept,证书吊销列表
database    = $dir/index.txt    # database index file.这个是一个文件,保存证书数据库,如颁发了哪些证书,证书编号,证书状态等信息保存在这里,这个文件默认没有,要手工创建一个空文件,颁发证书的时候,会手动颁发,没有空文件的话,颁发的时候会报错
#unique_subject = no            # Set to 'no' to allow creation of
                    # several ctificates with same subject.
new_certs_dir   = $dir/newcerts     # default place for new certs.默认新证书的放置目录,这个文件是自动生成的,用数字编号
certificate = $dir/cacert.pem   # The CA certificate,CA自己的证书,根CA自己给自己颁发,子CA上级颁发
serial      = $dir/serial       # The current serial number,要手动创建,当前系列号,是一个16进制数,实际意义是下一个证书的编号,默认是从00开始,可以自己指定开始的值,必须是16进制数
crlnumber   = $dir/crlnumber    # the current crl number,证书吊销编号,也是指下一个证书被吊销的编号,即下一个被吊销的证书的编号
                    # must be commented out to leave a V1 CRL
crl     = $dir/crl.pem      # The current CRL
private_key = $dir/private/cakey.pem# The private key。CA的私钥
RANDFILE    = $dir/private/.rand    # private random number file,随机数

x509_extensions = usr_cert      # The extentions to add to the cert

# Comment out the following two lines for the "traditional"
# (and highly broken) format.
name_opt    = ca_default        # Subject Name options,命名方式
cert_opt    = ca_default        # Certificate field options

# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
# so this is commented out by default to leave a V1 CRL.
# crlnumber must also be commented out to leave a V1 CRL.
# crl_extensions    = crl_ext

default_days    = 365           # how long to certify for,证书的有效期,可以指定
default_crl_days= 30            # how long before next CRL,CRL的有效期
default_md  = default       # use public key default MD
preserve    = no            # keep passed DN ordering

# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
policy      = policy_match,策略,由下面来指定,表示客户要申请证书的时候,要求客户提供的信息

# For the CA policy
[ policy_match ]  这个是系统默认的策略
countryName     = match  国家,match是必须匹配,两边都是同样的信息,其他的可以不一样
stateOrProvinceName = match  省,match如果不一样,就会拒绝,不会颁发证书
organizationName    = match  组织
organizationalUnitName  = optional 部门 
commonName      = supplied  通用名,如网站服务器的域名,一般是严格匹配,也可以写成泛域名,申请费用比较贵
emailAddress        = optional  ,可选项,不强制要求一样

# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ] 给外部使用,不用match选项,都不要求完全一样
countryName     = optional
stateOrProvinceName = optional
localityName        = optional
organizationName    = optional
organizationalUnitName  = optional
commonName      = supplied
emailAddress        = optional

[ req ]
default_bits        = 2048
default_md      = sha1
default_keyfile     = privkey.pem
distinguished_name  = req_distinguished_name
attributes      = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert

6 总结

由于openssl这个命令很强大,有大量的参数,本文只是列出的参数是生成很颁发等必须用到的几个参数,如果需要有更多其他选项,用户可自行添加