package utils import ( "bytes" "crypto/rand" "fmt" "io" "os" "os/exec" "time" ) const ( OPENSSL_PATH = "openssl" // WORK_PATH = "/opt/arrokoth/ca-mini" WORK_PATH = "/Users/seven/arrokoth/sample-demo/certificate-management/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 }