mirror of
https://gitee.com/mirrors/AllinSSL.git
synced 2026-03-08 07:41:10 +08:00
【新增】私有ca
This commit is contained in:
399
backend/internal/private_ca/private_ca.go
Normal file
399
backend/internal/private_ca/private_ca.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user