init
This commit is contained in:
321
ca-server/pkg/utils/ca_util.go
Normal file
321
ca-server/pkg/utils/ca_util.go
Normal file
@@ -0,0 +1,321 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
OPENSSL_PATH = "openssl"
|
||||
// WORK_PATH = "/opt/arrokoth/ca-mini"
|
||||
WORK_PATH = "/home/code/git/ca-mini/ca-server"
|
||||
CA_CERT = WORK_PATH + "/ca/CaRoot.crt"
|
||||
CA_CONFIG = WORK_PATH + "/ca/ca.conf"
|
||||
CERT_PATH = WORK_PATH + "/cert"
|
||||
CRL = WORK_PATH + "/crl/CaRoot.crl"
|
||||
)
|
||||
|
||||
// GenerateRandomString 生成指定长度的随机字符串
|
||||
func GenerateRandomString(length int) (string, error) {
|
||||
// 创建一个字节切片,用于存储随机数据
|
||||
bytes := make([]byte, length)
|
||||
|
||||
// 使用crypto/rand包生成随机字节
|
||||
_, err := io.ReadFull(rand.Reader, bytes)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to generate random string: %v", err)
|
||||
}
|
||||
|
||||
// 将随机字节转换为Base64字符串
|
||||
// randomString := base64.RawURLEncoding.EncodeToString(bytes)
|
||||
|
||||
// 将随机字节转换为十六进制字符串
|
||||
randomString := fmt.Sprintf("%x", bytes)
|
||||
|
||||
return randomString, nil
|
||||
}
|
||||
|
||||
// 根据时间戳+随机数生成唯一ID
|
||||
func GenerateUniqueID() (string, error) {
|
||||
// 获取当前时间戳
|
||||
timestamp := time.Now().UnixNano()
|
||||
|
||||
// 生成随机数
|
||||
randomNumber, err := GenerateRandomString(8)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 拼接时间戳和随机数
|
||||
uniqueID := fmt.Sprintf("%d%s", timestamp, randomNumber)
|
||||
|
||||
// uniqueID := fmt.Sprintf("%d%s", timestamp, uuid.New().String())
|
||||
|
||||
return uniqueID, nil
|
||||
}
|
||||
|
||||
func GetKeyFilePath(keyId string) string {
|
||||
return CERT_PATH + "/" + keyId + ".key"
|
||||
}
|
||||
|
||||
func GetCsrFilePath(keyId string) string {
|
||||
return CERT_PATH + "/" + keyId + ".csr"
|
||||
}
|
||||
|
||||
func GetCertFilePath(subject string) string {
|
||||
return CERT_PATH + "/" + subject + ".crt"
|
||||
}
|
||||
|
||||
// 生成密钥
|
||||
func GenerateKey(alg string, len int) (string, error) {
|
||||
// 生成私钥
|
||||
// openssl genrsa -out Ca.key 2048
|
||||
var keyAlg string
|
||||
var keyLen string
|
||||
id, err := GenerateUniqueID()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
keyFilePath := GetKeyFilePath(id)
|
||||
switch alg {
|
||||
case "rsa":
|
||||
keyAlg = "rsa"
|
||||
case "ec":
|
||||
keyAlg = "ec"
|
||||
default:
|
||||
keyAlg = "rsa"
|
||||
}
|
||||
|
||||
switch len {
|
||||
case 1024:
|
||||
keyLen = "1024"
|
||||
case 2048:
|
||||
keyLen = "2048"
|
||||
case 4096:
|
||||
keyLen = "4096"
|
||||
default:
|
||||
keyLen = "2048"
|
||||
}
|
||||
// 创建命令
|
||||
xcmd := exec.Command(OPENSSL_PATH, "gen"+keyAlg, "-out", keyFilePath, keyLen)
|
||||
|
||||
// 捕获标准输出和标准错误
|
||||
var stdout, stderr bytes.Buffer
|
||||
xcmd.Stdout = &stdout
|
||||
xcmd.Stderr = &stderr
|
||||
|
||||
// 执行命令
|
||||
err = xcmd.Run()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("命令执行失败: %v\n错误输出: %s", err, stderr.String())
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// 生成证书请求
|
||||
func GenerateCsr(id string, subject string, sans []string) (string, error) {
|
||||
// 生成证书请求
|
||||
// openssl req -new -key Ca.key -out Ca.csr -subj "/C=CN/ST=BeiJing/L=BeiJing/O=xxx/OU=dev/CN=CaRoot/emailAddress=CaRoot@xxx.com"
|
||||
keyFilePath := GetKeyFilePath(id)
|
||||
csrFilePath := GetCsrFilePath(id)
|
||||
// 创建命令
|
||||
// xcmd := exec.Command(OPENSSL_PATH, "req", "-new", "-key", keyFilePath, "-out", csrFilePath, "-subj", subject)
|
||||
args := []string{"req", "-new", "-key", keyFilePath, "-out", csrFilePath, "-subj", subject}
|
||||
// if len(sans) > 0 {
|
||||
// sanStr := joinSans(sans)
|
||||
// args = append(args, "-addext", "subjectAltName = "+sanStr)
|
||||
// }
|
||||
xcmd := exec.Command(OPENSSL_PATH, args...)
|
||||
// 捕获标准输出和标准错误
|
||||
var stdout, stderr bytes.Buffer
|
||||
xcmd.Stdout = &stdout
|
||||
xcmd.Stderr = &stderr
|
||||
// 执行命令
|
||||
err := xcmd.Run()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("命令执行失败: %v\n错误输出: %s", err, stderr.String())
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// 生成证书
|
||||
func GenerateCert(id string, days int) (string, error) {
|
||||
// 生成证书
|
||||
// openssl x509 -req -in Ca.csr -signkey Ca.key -out Ca.crt
|
||||
// openssl ca -config ca.conf -notext -batch -in ./subordinate/Ca.csr -out ./subordinate/Ca.crt
|
||||
csrFilePath := GetCsrFilePath(id)
|
||||
certFilePath := GetCertFilePath(id)
|
||||
xargs := []string{
|
||||
"ca",
|
||||
"-config", CA_CONFIG,
|
||||
"-notext",
|
||||
"-batch",
|
||||
"-in", csrFilePath,
|
||||
"-out", certFilePath,
|
||||
}
|
||||
if days > 0 && days < 3650 {
|
||||
xargs = append(xargs, "-days", fmt.Sprintf("%d", days))
|
||||
}
|
||||
|
||||
// 创建命令
|
||||
xcmd := exec.Command(OPENSSL_PATH, xargs...)
|
||||
|
||||
// 捕获标准输出和标准错误
|
||||
var stdout, stderr bytes.Buffer
|
||||
xcmd.Stdout = &stdout
|
||||
xcmd.Stderr = &stderr
|
||||
|
||||
// 执行命令
|
||||
err := xcmd.Run()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("命令执行失败: %v\n错误输出: %s", err, stderr.String())
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// 生成黑名单
|
||||
func GenerateCrl(id string) (string, error) {
|
||||
// 生成黑名单
|
||||
// openssl ca -gencrl -out crl.pem -config ca.conf
|
||||
xargs := []string{
|
||||
"ca",
|
||||
"-config", CA_CONFIG,
|
||||
"-gencrl",
|
||||
"-out", CRL,
|
||||
}
|
||||
|
||||
// 创建命令
|
||||
xcmd := exec.Command(OPENSSL_PATH, xargs...)
|
||||
|
||||
// 捕获标准输出和标准错误
|
||||
var stdout, stderr bytes.Buffer
|
||||
xcmd.Stdout = &stdout
|
||||
xcmd.Stderr = &stderr
|
||||
|
||||
// 执行命令
|
||||
err := xcmd.Run()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("命令执行失败: %v\n错误输出: %s", err, stderr.String())
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// 撤销证书
|
||||
func RevokeCert(id string) (string, error) {
|
||||
// 撤销证书
|
||||
// openssl ca -revoke ./subordinate/Ca.crt -config ca.conf
|
||||
certFilePath := GetCertFilePath(id)
|
||||
xargs := []string{
|
||||
"ca",
|
||||
"-config", CA_CONFIG,
|
||||
"-revoke", certFilePath,
|
||||
}
|
||||
|
||||
// 创建命令
|
||||
xcmd := exec.Command(OPENSSL_PATH, xargs...)
|
||||
|
||||
// 捕获标准输出和标准错误
|
||||
var stdout, stderr bytes.Buffer
|
||||
xcmd.Stdout = &stdout
|
||||
xcmd.Stderr = &stderr
|
||||
|
||||
// 执行命令
|
||||
err := xcmd.Run()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("命令执行失败: %v\n错误输出: %s", err, stderr.String())
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// 检查证书是否在黑名单中
|
||||
func CheckCertInCrl(certFilePath string) (bool, error) {
|
||||
// 检查证书是否在黑名单中
|
||||
// openssl verify -CAfile /opt/arrokoth/ca-mini/ca/CaRoot.crt -CRLfile /opt/arrokoth/ca-mini/crl/CaRoot.crl /opt/arrokoth/ca-mini/cert/17455454097526357682Q7pIOUE70I.crt
|
||||
// openssl crl -in crl.pem -noout -text
|
||||
xargs := []string{
|
||||
"crl",
|
||||
"-in", certFilePath,
|
||||
"-noout",
|
||||
"-text",
|
||||
}
|
||||
|
||||
// 创建命令
|
||||
xcmd := exec.Command(OPENSSL_PATH, xargs...)
|
||||
|
||||
// 捕获标准输出和标准错误
|
||||
var stdout, stderr bytes.Buffer
|
||||
xcmd.Stdout = &stdout
|
||||
xcmd.Stderr = &stderr
|
||||
|
||||
// 执行命令
|
||||
err := xcmd.Run()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("命令执行失败: %v\n错误输出: %s", err, stderr.String())
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// 读取文件内容
|
||||
func ReadFile(filePath string) (string, error) {
|
||||
data, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("读取文件失败: %v", err)
|
||||
}
|
||||
// 将数据转换为字符串
|
||||
content := string(data)
|
||||
return content, nil
|
||||
}
|
||||
|
||||
// 读取CA证书
|
||||
func GetCaCert() (string, error) {
|
||||
data, err := ReadFile(CA_CERT)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("读取CA证书失败: %v", err)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// 读取证书
|
||||
func GetCert(id string) (string, error) {
|
||||
data, err := ReadFile(GetCertFilePath(id))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("读取证书失败: %v", err)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// 读取私钥
|
||||
func GetKey(id string) (string, error) {
|
||||
data, err := ReadFile(GetKeyFilePath(id))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("读取私钥失败: %v", err)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// 读取证书请求
|
||||
func GetCsr(id string) (string, error) {
|
||||
data, err := ReadFile(GetCsrFilePath(id))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("读取证书请求失败: %v", err)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// joinSans 拼接 SAN 字段,例如 DNS:example.com, IP:192.168.0.1
|
||||
func joinSans(sans []string) string {
|
||||
result := ""
|
||||
for i, san := range sans {
|
||||
if i > 0 {
|
||||
result += ", "
|
||||
}
|
||||
result += san
|
||||
}
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user