【新增】私有ca

This commit is contained in:
v-me-50
2025-08-26 16:52:07 +08:00
parent e53a88e4dd
commit c9cb3fa5e1
10 changed files with 1520 additions and 0 deletions

View File

@@ -0,0 +1,399 @@
package private_ca
import (
"ALLinSSL/backend/public"
"encoding/json"
"fmt"
"time"
)
func CreateRootCA(name, commonName, organization, organizationalUnit, country, province, locality, keyType string, keyBits, validDays int64) error {
var err error
var data *CAConfig
if keyType == "sm2" {
// 国密SM2根证书 - 生成签名和加密双证书, 使用不同私钥
data, err = GenerateRootCASM2(name, commonName, organization, organizationalUnit, country, province, locality, int(validDays))
} else {
// 标准根证书 - 生成单一证书
data, err = GenerateRootCAStandard(name, commonName, organization, organizationalUnit, country, province, locality, KeyType(keyType), int(keyBits), int(validDays))
}
if err != nil {
return err
}
// 保存到数据库
s, err := GetSqlite()
if err != nil {
return err
}
_, err = s.Insert(public.StructToMap(data, true))
if err != nil {
return err
}
return nil
}
func CreateIntermediateCA(name, commonName, organization, organizationalUnit, country, province, locality string, rootId, keyBits, validDays int64) error {
s, err := GetSqlite()
if err != nil {
return err
}
issuers, err := s.Where("id=?", []interface{}{rootId}).Select()
if err != nil {
return err
}
if len(issuers) == 0 {
return fmt.Errorf("issuer with id %d not found", rootId)
}
issuer := issuers[0]
keyType := issuer["algorithm"].(string)
cert := issuer["cert"].(string)
key := issuer["key"].(string)
var data *CAConfig
if keyType == "sm2" {
// 国密SM2中级证书 - 生成签名和加密双证书, 使用不同私钥
enCert := issuer["en_cert"].(string)
enKey := issuer["en_key"].(string)
data, err = GenerateIntermediateCASM2(name, commonName, organization, organizationalUnit, country, province, locality, cert, key, enCert, enKey, int(validDays))
} else {
// 标准中级证书 - 生成单一证书
data, err = GenerateIntermediateCAStandard(name, commonName, organization, organizationalUnit, country, province, locality, cert, key, keyType, int(keyBits), int(validDays))
}
if err != nil {
return err
}
// 保存到数据库
insertData := public.StructToMap(data, true)
insertData["root_id"] = rootId
_, err = s.Insert(insertData)
if err != nil {
return err
}
return nil
}
func DeleteCA(id int64) error {
s, err := GetSqlite()
if err != nil {
return err
}
// 检查是否有子证书
children, err := s.Where("root_id=?", []interface{}{id}).Select()
if err != nil {
return err
}
if len(children) > 0 {
return fmt.Errorf("cannot delete CA with id %d: it has child CAs", id)
}
_, err = s.Where("root_id=?", []interface{}{id}).Delete()
if err != nil {
return err
}
return nil
}
func ListCAs(search string, p, limit int64) ([]map[string]interface{}, int, error) {
s, err := GetSqlite()
if err != nil {
return nil, 0, err
}
var data []map[string]any
var count int64
var limits []int64
if p >= 0 && limit >= 0 {
limits = []int64{0, limit}
if p > 1 {
limits[0] = (p - 1) * limit
limits[1] = limit
}
}
if search != "" {
data, err = s.Where("name like ? or cn like ?", []interface{}{"%" + search + "%", "%" + search + "%"}).Limit(limits).Order("create_time", "desc").Select()
count, err = s.Where("name like ? or cn like ?", []interface{}{"%" + search + "%", "%" + search + "%"}).Limit(limits).Order("create_time", "desc").Count()
} else {
data, err = s.Limit(limits).Order("create_time", "desc").Select()
count, err = s.Limit(limits).Order("create_time", "desc").Count()
}
if err != nil {
return data, int(count), err
}
return data, int(count), nil
}
func CreateLeafCert(caId, usage, keyBits, validDays int64, cn, san string) (*LeafCertConfig, error) {
if caId <= 0 {
return nil, fmt.Errorf("CA ID不能为空")
}
if san == "" {
return nil, fmt.Errorf("备用名称不能为空")
}
var sans SAN
err := json.Unmarshal([]byte(san), &sans)
if err != nil {
return nil, fmt.Errorf("备用名称格式错误: %v", err)
}
if cn == "" {
if len(sans.DNSNames) > 0 {
cn = sans.DNSNames[0]
} else {
cn = string(sans.IPAddresses[0])
}
}
s, err := GetSqlite()
if err != nil {
return nil, err
}
defer s.Close()
issuers, err := s.Where("id=?", []interface{}{caId}).Select()
if err != nil {
return nil, err
}
if len(issuers) == 0 {
return nil, fmt.Errorf("issuer with id %d not found", caId)
}
issuer := issuers[0]
if issuer["root_id"] == "" || issuer["root_id"] == nil {
return nil, fmt.Errorf("不允许使用根证书直接签发叶子证书,请先创建中间证书")
}
keyType := issuer["algorithm"].(string)
cert := issuer["cert"].(string)
key := issuer["key"].(string)
var issuerObj *Certificate
if keyType == "sm2" {
enCert := issuer["en_cert"].(string)
enKey := issuer["en_key"].(string)
issuerObj, err = NewCertificateFromPEMSM2([]byte(cert), []byte(key), []byte(enCert), []byte(enKey))
} else {
issuerObj, err = NewCertificateFromPEMStandard([]byte(cert), []byte(key), KeyType(keyType))
}
leafObj, err := GenerateLeafCertificate(cn, sans, issuerObj, KeyType(keyType), int(usage), int(keyBits), int(validDays))
if err != nil {
return nil, err
}
s.TableName = "leaf"
// 保存到数据库
leafObj.SAN = san
leafObj.CaId = caId
insertData := public.StructToMap(leafObj, true)
_, err = s.Insert(insertData)
if err != nil {
return nil, err
}
return leafObj, nil
}
func ListLeafCerts(caId int64, search string, p, limit int64) ([]map[string]interface{}, int, error) {
s, err := GetSqlite()
if err != nil {
return nil, 0, err
}
defer s.Close()
s.TableName = "leaf"
var data []map[string]any
var count int64
var limits []int64
if p >= 0 && limit >= 0 {
limits = []int64{0, limit}
if p > 1 {
limits[0] = (p - 1) * limit
limits[1] = limit
}
}
if caId > 0 && search != "" {
data, err = s.Where("ca_id=? and (cn like ? or san like ?)", []interface{}{caId, "%" + search + "%", "%" + search + "%"}).Limit(limits).Order("create_time", "desc").Select()
count, err = s.Where("ca_id=? and (cn like ? or san like ?)", []interface{}{caId, "%" + search + "%", "%" + search + "%"}).Limit(limits).Order("create_time", "desc").Count()
} else if caId > 0 {
data, err = s.Where("ca_id=?", []interface{}{caId}).Limit(limits).Order("create_time", "desc").Select()
count, err = s.Where("ca_id=?", []interface{}{caId}).Limit(limits).Order("create_time", "desc").Count()
} else if search != "" {
data, err = s.Where("cn like ? or san like ?", []interface{}{"%" + search + "%", "%" + search + "%"}).Limit(limits).Order("create_time", "desc").Select()
count, err = s.Where("cn like ? or san like ?", []interface{}{"%" + search + "%", "%" + search + "%"}).Limit(limits).Order("create_time", "desc").Count()
} else {
data, err = s.Limit(limits).Order("create_time", "desc").Select()
count, err = s.Limit(limits).Order("create_time", "desc").Count()
}
if err != nil {
return data, int(count), err
}
return data, int(count), nil
}
func DeleteLeafCert(id int64) error {
s, err := GetSqlite()
if err != nil {
return err
}
defer s.Close()
s.TableName = "leaf"
_, err = s.Where("id=?", []interface{}{id}).Delete()
if err != nil {
return err
}
return nil
}
func GetCert(id int64, certType string) (map[string]any, error) {
s, err := GetSqlite()
if err != nil {
return nil, err
}
defer s.Close()
s.TableName = certType
leafs, err := s.Where("id=?", []interface{}{id}).Select()
if err != nil {
return nil, err
}
if len(leafs) == 0 {
return nil, fmt.Errorf("leaf cert with id %d not found", id)
}
return leafs[0], nil
}
func WorkflowCreateLeafCert(params map[string]any, logger *public.Logger) (map[string]any, error) {
caId, ok := params["ca_id"].(float64)
if !ok || caId <= 0 {
return nil, fmt.Errorf("ca_id参数错误")
}
keyBits, ok := params["key_length"].(float64)
if !ok {
return nil, fmt.Errorf("key_length参数错误")
}
validDays, ok := params["valid_days"].(float64)
if !ok {
return nil, fmt.Errorf("valid_days参数错误")
}
endDay, ok := params["end_day"].(float64)
if !ok {
endDay = 0
}
cn, ok := params["cn"].(string)
if !ok {
cn = ""
}
san, ok := params["san"].(string)
if !ok || san == "" {
return nil, fmt.Errorf("san参数错误")
}
// 先获取ca信息确认是中间证书且不能是国密
s, err := GetSqlite()
if err != nil {
return nil, err
}
defer s.Close()
issuers, err := s.Where("id=?", []interface{}{caId}).Select()
if err != nil {
return nil, err
}
if len(issuers) == 0 {
return nil, fmt.Errorf("issuer with id %d not found", caId)
}
issuer := issuers[0]
if issuer["root_id"] == "" || issuer["root_id"] == nil {
return nil, fmt.Errorf("不允许使用根证书直接签发叶子证书,请先创建中间证书")
}
keyType := issuer["algorithm"].(string)
if keyType == "sm2" {
return nil, fmt.Errorf("暂不兼容国密证书,请使用标准证书")
}
// 判断中间证书不能为已过期,过期时间不能超过中间证书
caNotAfter, err := time.Parse("2006-01-02 15:04:05", issuer["not_after"].(string))
if err != nil {
return nil, fmt.Errorf("解析中间证书过期时间失败: %v", err)
}
maxValidDays := caNotAfter.Sub(time.Now()).Hours() / 24
if maxValidDays <= 0 {
return nil, fmt.Errorf("中间证书已过期,不能签发叶子证书")
}
if validDays > maxValidDays {
return nil, fmt.Errorf("叶子证书的有效期不能超过中间证书的有效期,中间证书将在 %s 过期,距离今天还有 %d 天", caNotAfter.Format("2006-01-02"), int(maxValidDays))
}
// 解析san判断数据库中是否已存在相同的cn和san
var sans SAN
err = json.Unmarshal([]byte(san), &sans)
if err != nil {
return nil, fmt.Errorf("备用名称格式错误: %v", err)
}
if cn == "" {
if len(sans.DNSNames) > 0 {
cn = sans.DNSNames[0]
} else {
cn = string(sans.IPAddresses[0])
}
}
s.TableName = "leaf"
// 获取所有未过期的证书判断是否有相同的cn和san
leafs, err := s.Where("ca_id=? and not_after>? and usage=1", []interface{}{caId, time.Now().Format("2006-01-02 15:04:05")}).Select()
if err != nil {
return nil, err
}
var certificate map[string]any
for _, v := range leafs {
// 判断剩余天数是否满足要求
if endDay > 0 {
notAfter, err := time.Parse("2006-01-02 15:04:05", v["not_after"].(string))
if err != nil {
continue
}
remainDays := notAfter.Sub(time.Now()).Hours() / 24
if remainDays < endDay {
continue
}
}
// 判断cn和san是否相同
if v["cn"] == cn {
var existingSAN SAN
err = json.Unmarshal([]byte(v["san"].(string)), &existingSAN)
if err != nil {
continue
}
if public.ContainsAllIgnoreBRepeats(existingSAN.DNSNames, sans.DNSNames) {
var existingIPs, newIPs []string
for _, ip := range existingSAN.IPAddresses {
existingIPs = append(existingIPs, ip.String())
}
for _, ip := range sans.IPAddresses {
newIPs = append(newIPs, ip.String())
}
if public.ContainsAllIgnoreBRepeats(existingIPs, newIPs) {
// 找到相同的证书,标记为跳过
logger.Debug("找到相同的证书,跳过创建", "id", v["id"])
certificate = map[string]any{
"cert": v["cert"],
"key": v["key"],
"skip": true,
}
break
}
}
}
}
if certificate == nil {
leaf, err := CreateLeafCert(int64(caId), 1, int64(keyBits), int64(validDays), cn, san)
if err != nil {
return nil, err
}
certificate = map[string]any{
"cert": leaf.Cert,
"key": leaf.Key,
}
}
return certificate, nil
}