怎样编译安装Certificate Authority Certificates

2017年11月27日 | 分类: 【技术】

安装系统CA证书:

CentOS 系统:

sudo curl https://curl.haxx.se/ca/cacert.pem -o /etc/pki/tls/certs/ca-bundle.crt 

Debian/Ubuntu系统:

sudo apt-get install --reinstall ca-certificates

方法1:直接下载 ca-bundle.crt

背景:php curl请求https接口。
报错:curl: (60) SSL certificate problem: unable to get local issuer certificate

此问题的出现是由于没有配置信任的服务器 HTTPS 验证。默认,cURL被设为不信任任何CAs,就是说,它不信任任何服务器验证。因此,这就是浏览器无法通过HTTPs访问你服务器的原因。

下载一个ca-bundle.crt,放到对应的目录,在php.ini文件中配置下路径:

下载:https://github.com/bagder/ca-bundle/blob/e9175fec5d0c4d42de24ed6d84a06d504d5e5a09/ca-bundle.crt
介绍:The Mozilla CA bundle extracted and converted to PEM at regular intervals. See the PEM file itself for the actual date of the latest Mozilla source change that is included in converted file.

在php.ini加入,重启web服务器

curl.cainfo="真实路径/ca-bundle.crt"

用此方法时,curl请求https请求方面设置如下:

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1);// 对认证证书来源的检查
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);// 从证书中检查SSL加密算法是否存在
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);// 使用自动跳转
//curl_setopt($curl, CURLOPT_CAINFO, 'D:/phpStudy/PHPTutorial/WWW/dataoke/runtime/myq.pem');

不能设置CURLOPT_CAINFO项要格外注意。

方法2:编译安装Certificate Authority Certificates

参考:http://www.linuxfromscratch.org/blfs/view/stable/postlfs/cacerts.html

Installed Programs: make-ca.sh, make-cert.pl and remove-expired-certs.sh
Installed Libraries: None
Installed Directories: /etc/ssl/certs

注意:因为Win下会产生句尾的^M,所以最好使用vi编辑;或者使用Win编辑后,使用dos2unix来处理。

yum安装:

yum install dos2unix

先创建一个文件:

/usr/bin/make-cert.pl

这个文件负责:reformat a certificate into a form needed by openssl.

内容如下:

#!/usr/bin/perl -w

# Used to generate PEM encoded files from Mozilla certdata.txt.
# Run as ./make-cert.pl > certificate.crt
#
# Parts of this script courtesy of RedHat (mkcabundle.pl)
#
# This script modified for use with single file data (tempfile.cer) extracted
# from certdata.txt, taken from the latest version in the Mozilla NSS source.
# mozilla/security/nss/lib/ckfw/builtins/certdata.txt
#
# Authors: DJ Lucas
#          Bruce Dubbs
#
# Version 20120211

my $certdata = './tempfile.cer';

open( IN, "cat $certdata|" )
    || die "could not open $certdata";

my $incert = 0;

while ( <IN> )
{
    if ( /^CKA_VALUE MULTILINE_OCTAL/ )
    {
        $incert = 1;
        open( OUT, "|openssl x509 -text -inform DER -fingerprint" )
            || die "could not pipe to openssl x509";
    }

    elsif ( /^END/ && $incert )
    {
        close( OUT );
        $incert = 0;
        print "\n\n";
    }

    elsif ($incert)
    {
        my @bs = split( /\\/ );
        foreach my $b (@bs)
        {
            chomp $b;
            printf( OUT "%c", oct($b) ) unless $b eq '';
        }
    }
}

再创建第二个文件:

/usr/bin/make-ca.sh

这个文件负责:creates the certificates and a bundle of all the certificates. It creates a ./certs directory and ./BLFS-ca-bundle-${VERSION}.crt

内容如下:

#!/bin/sh
# Begin make-ca.sh
# Script to populate OpenSSL's CApath from a bundle of PEM formatted CAs
#
# The file certdata.txt must exist in the local directory
# Version number is obtained from the version of the data.
#
# Authors: DJ Lucas
#          Bruce Dubbs
#
# Version 20120211

# Some data in the certs have UTF-8 characters
export LANG=en_US.utf8

certdata="certdata.txt"

if [ ! -r $certdata ]; then
  echo "$certdata must be in the local directory"
  exit 1
fi

REVISION=$(grep CVS_ID $certdata | cut -f4 -d'$')

if [ -z "${REVISION}" ]; then
  echo "$certfile has no 'Revision' in CVS_ID"
  exit 1
fi

VERSION=$(echo $REVISION | cut -f2 -d" ")

TEMPDIR=$(mktemp -d)
TRUSTATTRIBUTES="CKA_TRUST_SERVER_AUTH"
BUNDLE="BLFS-ca-bundle-${VERSION}.crt"
CONVERTSCRIPT="/usr/bin/make-cert.pl"
SSLDIR="/etc/ssl"

mkdir "${TEMPDIR}/certs"

# Get a list of starting lines for each cert
CERTBEGINLIST=$(grep -n "^# Certificate" "${certdata}" | cut -d ":" -f1)

# Get a list of ending lines for each cert
CERTENDLIST=`grep -n "^CKA_TRUST_STEP_UP_APPROVED" "${certdata}" | cut -d ":" -f 1`

# Start a loop
for certbegin in ${CERTBEGINLIST}; do
  for certend in ${CERTENDLIST}; do
    if test "${certend}" -gt "${certbegin}"; then
      break
    fi
  done

  # Dump to a temp file with the name of the file as the beginning line number
  sed -n "${certbegin},${certend}p" "${certdata}" > "${TEMPDIR}/certs/${certbegin}.tmp"
done

unset CERTBEGINLIST CERTDATA CERTENDLIST certbegin certend

mkdir -p certs
rm -f certs/*      # Make sure the directory is clean

for tempfile in ${TEMPDIR}/certs/*.tmp; do
  # Make sure that the cert is trusted...
  grep "CKA_TRUST_SERVER_AUTH" "${tempfile}" | \
    egrep "TRUST_UNKNOWN|NOT_TRUSTED" > /dev/null

  if test "${?}" = "0"; then
    # Throw a meaningful error and remove the file
    cp "${tempfile}" tempfile.cer
    perl ${CONVERTSCRIPT} > tempfile.crt
    keyhash=$(openssl x509 -noout -in tempfile.crt -hash)
    echo "Certificate ${keyhash} is not trusted!  Removing..."
    rm -f tempfile.cer tempfile.crt "${tempfile}"
    continue
  fi

  # If execution made it to here in the loop, the temp cert is trusted
  # Find the cert data and generate a cert file for it

  cp "${tempfile}" tempfile.cer
  perl ${CONVERTSCRIPT} > tempfile.crt
  keyhash=$(openssl x509 -noout -in tempfile.crt -hash)
  mv tempfile.crt "certs/${keyhash}.pem"
  rm -f tempfile.cer "${tempfile}"
  echo "Created ${keyhash}.pem"
done

# Remove blacklisted files
# MD5 Collision Proof of Concept CA
if test -f certs/8f111d69.pem; then
  echo "Certificate 8f111d69 is not trusted!  Removing..."
  rm -f certs/8f111d69.pem
fi

# Finally, generate the bundle and clean up.
cat certs/*.pem >  ${BUNDLE}
rm -r "${TEMPDIR}"

再创建第三个文件:

/usr/sbin/remove-expired-certs.sh

这个文件负责:remove expired certificates from a directory.

内容如下:

#!/bin/sh
# Begin /usr/sbin/remove-expired-certs.sh
#
# Version 20120211

# Make sure the date is parsed correctly on all systems
mydate()
{
  local y=$( echo $1 | cut -d" " -f4 )
  local M=$( echo $1 | cut -d" " -f1 )
  local d=$( echo $1 | cut -d" " -f2 )
  local m

  if [ ${d} -lt 10 ]; then d="0${d}"; fi

  case $M in
    Jan) m="01";;
    Feb) m="02";;
    Mar) m="03";;
    Apr) m="04";;
    May) m="05";;
    Jun) m="06";;
    Jul) m="07";;
    Aug) m="08";;
    Sep) m="09";;
    Oct) m="10";;
    Nov) m="11";;
    Dec) m="12";;
  esac

  certdate="${y}${m}${d}"
}

OPENSSL=/usr/bin/openssl
DIR=/etc/ssl/certs

if [ $# -gt 0 ]; then
  DIR="$1"
fi

certs=$( find ${DIR} -type f -name "*.pem" -o -name "*.crt" )
today=$( date +%Y%m%d )

for cert in $certs; do
  notafter=$( $OPENSSL x509 -enddate -in "${cert}" -noout )
  date=$( echo ${notafter} |  sed 's/^notAfter=//' )
  mydate "$date"

  if [ ${certdate} -lt ${today} ]; then
     echo "${cert} expired on ${certdate}! Removing..."
     rm -f "${cert}"
  fi
done

去除句尾的^M并更改文件权限:

dos2unix /usr/bin/make-cert.pl && dos2unix /usr/bin/make-ca.sh && dos2unix /usr/sbin/remove-expired-certs.sh 
chmod +x /usr/bin/make-cert.pl && chmod +x /usr/bin/make-ca.sh && chmod u+x /usr/sbin/remove-expired-certs.sh

然后执行命令:

URL=http://anduin.linuxfromscratch.org/BLFS/other/certdata.txt && rm -f certdata.txt && wget $URL && make-ca.sh && unset URL

然后执行命令:

SSLDIR=/etc/ssl && remove-expired-certs.sh certs && install -d ${SSLDIR}/certs && cp -v certs/*.pem ${SSLDIR}/certs && c_rehash && install BLFS-ca-bundle*.crt ${SSLDIR}/ca-bundle.crt && ln -sfv ../ca-bundle.crt ${SSLDIR}/certs/ca-certificates.crt && unset SSLDIR

如果发现没有c_rehash命令:

yum安装:

yum install openssl-perl

最后:Finally, clean up the current directory:

rm -r certs BLFS-ca-bundle*

最后生成文件将用于后续的gnutls的编译:

/etc/ssl/ca-bundle.crt