用openssl為EAP-TLS生成證書(CA證書,服務器證書,用戶證書)


用openssl為EAP-TLS生成證書(CA證書,服務器證書,用戶證書)

來源: https://www.cnblogs.com/osnosn/p/10597897.html 來自osnosn的博客
寫於: 2019-03-27.

本文參考了大神的文章:
 搭建一個「最安全」的Wi-Fi網絡楠站

本文是為"CentOS7用hostapd做radius服務器為WiFi提供802.1X企業認證" 中,WiFi的EAP-TLS認證,准備證書。
或者是為"Newifi OpenWrt 下 EAP-PEAP,EAP-TLS 企業級無線認證及 FreeRadius3" 中,WiFi的EAP-TLS認證,准備證書。
如果想為WEB服務器生成自簽名證書,我補充了一篇筆記: "用openssl為WEB服務器生成證書"

我用的是openssl-1.0.2k.
腳本支持生成RSA,ECC證書。 運行時帶參數指定類型。
-->開始。按以下路徑建立文件,腳本。ssl_create-cert-v0.4.7z

ssl_create-cert/   <-- 這個目錄, 自己隨便取名
   |_  2db/0serial
   |_  2db/2indexdb.txt
   |_  3certs_new/
   |_  4export/
   |_  clear_all_cert.sh
   |_  copy-pem-to.sh
   |_  create-crl.sh
   |_  new-ca.sh
   |_  new-server.sh
   |_  new-user.sh
   |_  revoke-user.sh
   |_  user_certs/
   |_  openssl.cnf
   |_  README

mkdir 2db/
echo "2233AA1234" > 2db/0serial 證書序列號,自己隨便編,十六進制數。

cat /dev/null > 2db/2indexdb.txt

此文件必須是0字節,否則openssl會報錯
wrong number of fields on line 1 (looking for field 6, got 1, '' left)

mkdir 3certs_new 4export user_certs

clear_all_cert.sh

#!/bin/sh
# clear_all_cert.sh
if [  "$#" -ne 1  -o  "$1" != "clearall" ]; then
        echo "Usage: $0 clearall"
        echo -e "\tClear all the \"keys\" and \"certs\"."
        echo -e "\tIt will remove *.pem"
        echo -e "\tIt will remove 3certs_new/* 4export/* user_certs/*"
        echo -e "\tIt will remove ALL!!!!!"
        exit 1
fi
if [ -f ca_key.pem ]; then
        rm -f ca_key.pem ca_cert.pem ca_cert.txt
fi
if [ -f crl.pem ]; then
        rm -f crl.pem ca_cert+crl.pem
fi
if [ -f server_key.pem ]; then
        rm -f server_key.pem server_cert.pem
fi
if [ -d user_certs ]; then
        rm -f user_certs/*
fi
if [ -d 3certs_new ]; then
        rm -f 3certs_new/*
fi
if [ -d 4export ]; then
        rm -f 4export/*
fi
if [ -f 2db/0serial ]; then
        rm -f 2db/0serial.old
fi
if [ -f 2db/2indexdb.txt ]; then
        cat /dev/null > 2db/2indexdb.txt
        rm -f 2db/2indexdb.txt.attr 2db/2indexdb.txt.attr.old 2db/2indexdb.txt.old
fi
echo -e "ALL cert files removed."
echo "You may now run ./new-ca.sh to get start"
echo ""

copy-pem-to.sh

#!/bin/sh
# copy-pem-to.sh
DIR=$1
if [  "$#" -ne 1  -o  "${#DIR}" -le "1" ]; then
        echo "Usage: $0 dest_directory"
        echo -e "\t $0  ./"
        echo -e "\t $0  a/"
        exit 1
fi
if [ ! -d $DIR ]; then
        echo " \"$DIR\" directory not found. Exit."
        exit 1
fi

echo "copy \"ca_cert+crl.pem\" \"server_cert.pem\" \"server_key.pem\" to \"$DIR\""
cp -i ca_cert+crl.pem $DIR
cp -i server_cert.pem $DIR
cp -i server_key.pem  $DIR

create-crl.sh

#!/bin/sh
#./create-crl.sh

if [ ! -f ca_key.pem ]; then
        echo "CA not found. Exit."
        exit
fi
if [ -f crl.pem ]; then
        echo "CRL file found. Exit."
        exit
fi
openssl ca -gencrl -keyfile ca_key.pem -cert ca_cert.pem -out crl.pem -config openssl.cnf && \
cat ca_cert.pem crl.pem > ca_cert+crl.pem
echo "copy file \"server_cert.pem\" \"server_key.pem\" \"ca_cert+crl.pem\" to hostapd dir."
echo "And start service \"hostapd\"."

echo ""

new-ca.sh

#!/bin/sh
# new-ca.sh
# Create the master CA key and cert. This should be done once.
if [ -f ca_key.pem ]; then
        echo "Root CA key found. Exit."
        exit
fi
keytype=""
case "$1" in
   "rsa2048")
      keytype="rsa:2048"
      ;;
   "rsa4096")
      keytype="rsa:4096"
      ;;
   "ec256")
      keytype="ec:ec_param"
      openssl ecparam -name prime256v1 -out ec_param
      ;;
   "ec384")
      keytype="ec:ec_param"
      openssl ecparam -name secp384r1 -out ec_param
      ;;
   *)
      echo -e "\nUsage: $0  {rsa2048|rsa4096|ec256|ec384}\n"
      exit
      ;;
esac

exportdir="4export"

echo "Self-sign the root CA..."
echo "No Root CA key found. Generating one"
openssl req -x509 -nodes -days 36500 -newkey ${keytype} -keyout ca_key.pem -out ca_cert.pem -new -sha512 -config openssl.cnf -extensions v3_ca -utf8 -subj "/C=CN/ST=廣東/L=gz/O=Home/CN=Wifi EAP Root CA/"  && \
openssl x509 -outform der -in ca_cert.pem -out ./${exportdir}/CA.crt  && \
openssl x509 -in ca_cert.pem -noout -text > ca_cert.txt
echo "You may now run ./new-server.sh"
echo ""

new-server.sh

#!/bin/sh
# new-server.sh
# Create the server key and cert. 
if [ -f server_key.pem ]; then
        echo "Server key found. Exit."
        exit
fi
keytype=""
case "$1" in
   "rsa2048")
      keytype="rsa:2048"
      ;;
   "rsa4096")
      keytype="rsa:4096"
      ;;
   "ec256")
      keytype="ec:ec_param"
      openssl ecparam -name prime256v1 -out ec_param
      ;;
   "ec384")
      keytype="ec:ec_param"
      openssl ecparam -name secp384r1 -out ec_param
      ;;
   *)
      echo -e "\nUsage: $0  {rsa2048|rsa4096|ec256|ec384}\n"
      echo "server證書建議用RSA。"
      echo "ECC server證書會導致安卓無法連接。錯誤為\"no shared cipher\"."
      exit
      ;;
esac

echo "Create server ssl for hostapd."
echo "No Server key found. Generating one."

openssl req -nodes -new -newkey ${keytype} -keyout server_key.pem -out server_csr.pem -config openssl.cnf -utf8 -subj "/C=CN/ST=廣東/L=gz/O=Home/CN=WiFi Radius Server/"  && \
openssl ca -days 36500 -in server_csr.pem -out server_cert.pem -config openssl.cnf -extensions server_cert -batch  && \
rm -rf server_csr.pem
echo "You may now run ./create-crl.sh"
echo ""

new-user.sh

#!/bin/sh
# new-user.sh
# Create the user key and cert. This should be done once per cert.
if [ $# -lt 3 ]; then
   echo -e "\nUsage: $0  {rsa1024|rsa2048|rsa4096|ec256|ec384}  userName  days  [pass]\n    days between 2 and 365\n"
   exit 1
fi
CERT=$2
if [ -f user_certs/user_${CERT}_key.pem ]; then
        echo "user_certs/user_${CERT}_key.pem found. Exit."
        exit 0
fi
keytype=""
case "$1" in
   "rsa1024")
      keytype="rsa:1024"
      ;;
   "rsa2048")
      keytype="rsa:2048"
      ;;
   "rsa4096")
      keytype="rsa:4096"
      ;;
   "ec256")
      keytype="ec:ec_param"
      openssl ecparam -name prime256v1 -out ec_param
      ;;
   "ec384")
      keytype="ec:ec_param"
      openssl ecparam -name secp384r1 -out ec_param
      ;;
   *)
      echo -e "\nUsage: $0  {rsa1024|rsa2048|rsa4096|ec256|ec384}  userName  days  [pass]\n    days between 2 and 365\n"
      exit
      ;;
esac

DAYS=${3:-1}  # default 1
if [ "${DAYS}" -gt 365 -o "${DAYS}" -lt 2 ]; then
   if [ "${DAYS}" -ne 36500 ];then
      echo -e "\nUsage: $0  {rsa1024|rsa2048|rsa4096|ec256|ec384}  userName  days  [pass]\n    days between 2 and 365\n"
      exit 1
   fi
fi

PASS=${4:-123}  # default 123

exportdir="4export"

export RANDFILE=2db/.random_state
## win10連接EAP-TLS時強制使用用戶證書的"CN="作為用戶名。建議"CN="不要包含空格。
## freeradius3不允許用戶名中包含空格。用hostapd做radius時用戶名無此限制。
openssl req -nodes -new -newkey ${keytype} -keyout user_certs/user_${CERT}_key.pem -out user_certs/user_${CERT}_csr.pem -config openssl.cnf -utf8 -subj "/C=CN/ST=廣東/L=gz/O=Home/CN=WiFi-${CERT}/" && \
openssl ca -days ${DAYS} -in user_certs/user_${CERT}_csr.pem -out user_certs/user_${CERT}_cert.pem -config openssl.cnf -extensions user_cert -batch && \
rm -rf user_certs/user_${CERT}_csr.pem && \
echo -e "Export certs...\n \"Export Password\" MUST set for IOS.\n \"Export Password\" MAY empty for Android,windows."  && \
openssl pkcs12 -export -out ./${exportdir}/${CERT}.p12 -inkey user_certs/user_${CERT}_key.pem -in user_certs/user_${CERT}_cert.pem -certfile ca_cert.pem -caname "Wifi EAP RootCA" -name "${CERT}-wifi-user" -passout pass:${PASS}
# 友好名稱 "-name" "-caname" windows中不支持utf8中文

echo ""

revoke-user.sh

#!/bin/sh
# revoke-user.sh
CERT=$1
if [ $# -ne 1 ]; then
        echo "Usage: $0 userName"
        exit 1
fi
if [ ! -f user_certs/user_${CERT}_key.pem ]; then
        echo "user_certs/user_${CERT}_key.pem NOT found. Exit."
        exit 0
fi

openssl ca -revoke user_certs/user_${CERT}_cert.pem -config openssl.cnf && \
openssl ca -gencrl -keyfile ca_key.pem -cert ca_cert.pem -out crl.pem -config openssl.cnf && \
cat ca_cert.pem crl.pem > ca_cert+crl.pem
echo "You NEED update \"ca_cert_crl.pem\" file and restart service \"hostapd\"."


echo ""

chmod +x clear_all_cert.sh new-ca.sh new-server.sh create-crl.sh copy-pem-to.sh new-user.sh revoke-user.sh

openssl.cnf

#openssl.cnf
[ ca ]
default_ca = hostapd

[ hostapd ]
dir = .
serial = $dir/2db/0serial
database = $dir/2db/2indexdb.txt
new_certs_dir = $dir/3certs_new
certificate = $dir/ca_cert.pem
private_key = $dir/ca_key.pem
RANDFILE = $dir/2db/.random_state

default_bits = 4096
default_days = 36500
default_crl_days = 36500
default_md = sha512
#unique_subject = no

policy = policy_anything

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

[ req ]
distinguished_name = req_distinguished_name
string_mask = utf8only
[ req_distinguished_name ]

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical,CA:true
certificatePolicies=ia5org,@pl_section
[ server_cert ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = CA:false
extendedKeyUsage = serverAuth,msSGC,nsSGC
certificatePolicies=ia5org,@pl_section
[ user_cert ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = CA:false
#subjectAltName = email:copy
extendedKeyUsage = clientAuth,emailProtection,timeStamping
certificatePolicies=ia5org,@pl_section

[ pl_section ]
policyIdentifier = "X509v3 Any Policy"
# 頒發者說明的鏈接. windows中,要導入信任之后才生效.
CPS.1 = https://your.web.com/cps/readme.html
userNotice.1=@pl_notice
[ pl_notice ]
# 頒發者說明,Issuer statment. 不支持utf8中文,因為ia5org。
explicitText="Read deail at https://your.web.com/xxx.html"

userNotice.1 的文字說明,只能是英文,中文會亂碼。
文字說明,無論此證書是否被系統信任,查看證書時都會出現在"頒發者說明"中(Issuer Statement)。
CPS.1 的鏈接。系統未信任此證書時,是不顯示的。信任后,才會出現在"頒發者說明"中(Issuer Statement)。
CPS.1= 可以是 "http://" 也可以是 "https://"。

README

README
create by osnosn, 2019-03-20. version_0.2.
--------------
To clear all:
   ./clear_all_cert.sh

Certs for hostapd:
   modify C/ST/L/O/CN in new-ca.sh,new-server.sh,newuser.sh, 可以使用中文。
   modify openssl.cnf:
      CPS.1=
      explicitText=
   keytype: rsa2048, rsa4096, ec256, ec384.
   ./new-ca.sh
   ./new-server.sh
   ./create-crl.sh
  copy file "server_cert.pem" "server_key.pem" "ca_cert+crl.pem" to hostapd dir.
   ./copy-pem-to.sh
  And start service "hostapd".

Certs for user:
   ./new-user.sh

Revoke user:
   ./revoke-user.sh
  After revoke, replace file "ca_cert+crl.pem" and reload "hostapd".
--------------
server cert: ECC 會導致Android8 連接失敗, 錯誤為"no shared cipher"。建議用RSA。
ca, user cert 可以用ECC。
user cert in "user_certs/" and "4export/"
import "4export/xxx.p12" to  android,ios,windows client.
用戶證書 xxx.p12 在 "4export/" 目錄中,
一個p12文件包含ca證書,user證書,user密鑰三個內容。
android,windows可以一次導入三個內容。
ios會丟棄ca。

ios導入密鑰強制輸入加密密碼(密碼不能為空)。
android,windows導入密鑰可以接受空密碼。

windows 必須導入"當前用戶",否則連接wifi時不能識別證書。
windows連接EAP-TLS: 點擊搜索到的wifi ssid,出現輸入"用戶","密碼"時,點擊"用證書認證"(證書導入當前用戶后)。
---------

chmod +x clear_all_cert.sh new-ca.sh new-server.sh create-crl.sh copy-pem-to.sh new-user.sh revoke-user.sh

給android導入用戶證書一定要用p12格式,不能用pem格式。
Android不認pem格式中的密鑰,只認公鑰。導致沒密鑰不能用於連接WIFI。

使用方法:

修改 C=/ST=/L=/O=/CN= 的內容合適你自己。這些項可以使用中文。
修改 openssl.cnf 中 CPS.1= 和 explicitText= 。
在IOS,windows中可以看到,可以寫漂亮點。主要是CN=寫漂亮點。會顯示為證書名。
Android沒地方看證書描述。寫啥,Android都看不到。
./clear_all_cert.sh clearall
./new-ca.sh ec256
./new-server.sh rsa2048 #服務器證書建議用RSA
./create-crl.sh
./copy-pem-to.sh hostapd_conf_dir/
service restart hostapd
./new-user.sh ec256 user1 36500
./new-user.sh ec256 user2 36500
copy xx.p12 file from "4export/" 目錄,分發給用戶。

轉載請注明來源。
來源: https://www.cnblogs.com/osnosn/p/10597897.html 來自osnosn的博客
---------------end---------------


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM