mirror of
				https://github.com/TeaOSLab/EdgeAPI.git
				synced 2025-11-04 16:00:24 +08:00 
			
		
		
		
	增加OCSP Stapling功能
This commit is contained in:
		@@ -113,6 +113,8 @@ func (this *SSLCertDAO) CreateCert(tx *dbs.Tx, adminId int64, userId int64, isOn
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	op.CommonNames = commonNamesJSON
 | 
						op.CommonNames = commonNamesJSON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						op.OcspIsUpdated = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = this.Save(tx, op)
 | 
						err = this.Save(tx, op)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return 0, err
 | 
							return 0, err
 | 
				
			||||||
@@ -121,7 +123,18 @@ func (this *SSLCertDAO) CreateCert(tx *dbs.Tx, adminId int64, userId int64, isOn
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UpdateCert 修改证书
 | 
					// UpdateCert 修改证书
 | 
				
			||||||
func (this *SSLCertDAO) UpdateCert(tx *dbs.Tx, certId int64, isOn bool, name string, description string, serverName string, isCA bool, certData []byte, keyData []byte, timeBeginAt int64, timeEndAt int64, dnsNames []string, commonNames []string) error {
 | 
					func (this *SSLCertDAO) UpdateCert(tx *dbs.Tx,
 | 
				
			||||||
 | 
						certId int64,
 | 
				
			||||||
 | 
						isOn bool,
 | 
				
			||||||
 | 
						name string,
 | 
				
			||||||
 | 
						description string,
 | 
				
			||||||
 | 
						serverName string,
 | 
				
			||||||
 | 
						isCA bool,
 | 
				
			||||||
 | 
						certData []byte,
 | 
				
			||||||
 | 
						keyData []byte,
 | 
				
			||||||
 | 
						timeBeginAt int64,
 | 
				
			||||||
 | 
						timeEndAt int64,
 | 
				
			||||||
 | 
						dnsNames []string, commonNames []string) error {
 | 
				
			||||||
	if certId <= 0 {
 | 
						if certId <= 0 {
 | 
				
			||||||
		return errors.New("invalid certId")
 | 
							return errors.New("invalid certId")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -156,6 +169,8 @@ func (this *SSLCertDAO) UpdateCert(tx *dbs.Tx, certId int64, isOn bool, name str
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	op.CommonNames = commonNamesJSON
 | 
						op.CommonNames = commonNamesJSON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						op.OcspIsUpdated = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = this.Save(tx, op)
 | 
						err = this.Save(tx, op)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -194,6 +209,7 @@ func (this *SSLCertDAO) ComposeCertConfig(tx *dbs.Tx, certId int64, cacheMap *ut
 | 
				
			|||||||
	config.ServerName = cert.ServerName
 | 
						config.ServerName = cert.ServerName
 | 
				
			||||||
	config.TimeBeginAt = int64(cert.TimeBeginAt)
 | 
						config.TimeBeginAt = int64(cert.TimeBeginAt)
 | 
				
			||||||
	config.TimeEndAt = int64(cert.TimeEndAt)
 | 
						config.TimeEndAt = int64(cert.TimeEndAt)
 | 
				
			||||||
 | 
						config.OCSP = []byte(cert.Ocsp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if IsNotNull(cert.DnsNames) {
 | 
						if IsNotNull(cert.DnsNames) {
 | 
				
			||||||
		dnsNames := []string{}
 | 
							dnsNames := []string{}
 | 
				
			||||||
@@ -356,6 +372,41 @@ func (this *SSLCertDAO) CheckUserCert(tx *dbs.Tx, certId int64, userId int64) er
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ListCertsToUpdateOCSP 查找需要更新OCSP的证书
 | 
				
			||||||
 | 
					func (this *SSLCertDAO) ListCertsToUpdateOCSP(tx *dbs.Tx, size int64) (result []*SSLCert, err error) {
 | 
				
			||||||
 | 
						_, err = this.Query(tx).
 | 
				
			||||||
 | 
							State(SSLCertStateEnabled).
 | 
				
			||||||
 | 
							Attr("ocspIsUpdated", false).
 | 
				
			||||||
 | 
							Limit(size).
 | 
				
			||||||
 | 
							Slice(&result).
 | 
				
			||||||
 | 
							FindAll()
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UpdateCertOSCP 修改OCSP
 | 
				
			||||||
 | 
					func (this *SSLCertDAO) UpdateCertOSCP(tx *dbs.Tx, certId int64, ocsp []byte, errString string) error {
 | 
				
			||||||
 | 
						if ocsp == nil {
 | 
				
			||||||
 | 
							ocsp = []byte{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 限制长度
 | 
				
			||||||
 | 
						if len(errString) > 300 {
 | 
				
			||||||
 | 
							errString = errString[:300]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := this.Query(tx).
 | 
				
			||||||
 | 
							Pk(certId).
 | 
				
			||||||
 | 
							Set("ocsp", ocsp).
 | 
				
			||||||
 | 
							Set("ocspError", errString).
 | 
				
			||||||
 | 
							Set("ocspIsUpdated", true).
 | 
				
			||||||
 | 
							UpdateQuickly()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return this.NotifyUpdate(tx, certId)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NotifyUpdate 通知更新
 | 
					// NotifyUpdate 通知更新
 | 
				
			||||||
func (this *SSLCertDAO) NotifyUpdate(tx *dbs.Tx, certId int64) error {
 | 
					func (this *SSLCertDAO) NotifyUpdate(tx *dbs.Tx, certId int64) error {
 | 
				
			||||||
	policyIds, err := SharedSSLPolicyDAO.FindAllEnabledPolicyIdsWithCertId(tx, certId)
 | 
						policyIds, err := SharedSSLPolicyDAO.FindAllEnabledPolicyIdsWithCertId(tx, certId)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,52 +1,58 @@
 | 
				
			|||||||
package models
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SSL证书
 | 
					// SSLCert SSL证书
 | 
				
			||||||
type SSLCert struct {
 | 
					type SSLCert struct {
 | 
				
			||||||
	Id          uint32 `field:"id"`          // ID
 | 
						Id            uint32 `field:"id"`            // ID
 | 
				
			||||||
	AdminId     uint32 `field:"adminId"`     // 管理员ID
 | 
						AdminId       uint32 `field:"adminId"`       // 管理员ID
 | 
				
			||||||
	UserId      uint32 `field:"userId"`      // 用户ID
 | 
						UserId        uint32 `field:"userId"`        // 用户ID
 | 
				
			||||||
	State       uint8  `field:"state"`       // 状态
 | 
						State         uint8  `field:"state"`         // 状态
 | 
				
			||||||
	CreatedAt   uint64 `field:"createdAt"`   // 创建时间
 | 
						CreatedAt     uint64 `field:"createdAt"`     // 创建时间
 | 
				
			||||||
	UpdatedAt   uint64 `field:"updatedAt"`   // 修改时间
 | 
						UpdatedAt     uint64 `field:"updatedAt"`     // 修改时间
 | 
				
			||||||
	IsOn        uint8  `field:"isOn"`        // 是否启用
 | 
						IsOn          uint8  `field:"isOn"`          // 是否启用
 | 
				
			||||||
	Name        string `field:"name"`        // 证书名
 | 
						Name          string `field:"name"`          // 证书名
 | 
				
			||||||
	Description string `field:"description"` // 描述
 | 
						Description   string `field:"description"`   // 描述
 | 
				
			||||||
	CertData    string `field:"certData"`    // 证书内容
 | 
						CertData      string `field:"certData"`      // 证书内容
 | 
				
			||||||
	KeyData     string `field:"keyData"`     // 密钥内容
 | 
						KeyData       string `field:"keyData"`       // 密钥内容
 | 
				
			||||||
	ServerName  string `field:"serverName"`  // 证书使用的主机名
 | 
						ServerName    string `field:"serverName"`    // 证书使用的主机名
 | 
				
			||||||
	IsCA        uint8  `field:"isCA"`        // 是否为CA证书
 | 
						IsCA          uint8  `field:"isCA"`          // 是否为CA证书
 | 
				
			||||||
	GroupIds    string `field:"groupIds"`    // 证书分组
 | 
						GroupIds      string `field:"groupIds"`      // 证书分组
 | 
				
			||||||
	TimeBeginAt uint64 `field:"timeBeginAt"` // 开始时间
 | 
						TimeBeginAt   uint64 `field:"timeBeginAt"`   // 开始时间
 | 
				
			||||||
	TimeEndAt   uint64 `field:"timeEndAt"`   // 结束时间
 | 
						TimeEndAt     uint64 `field:"timeEndAt"`     // 结束时间
 | 
				
			||||||
	DnsNames    string `field:"dnsNames"`    // DNS名称列表
 | 
						DnsNames      string `field:"dnsNames"`      // DNS名称列表
 | 
				
			||||||
	CommonNames string `field:"commonNames"` // 发行单位列表
 | 
						CommonNames   string `field:"commonNames"`   // 发行单位列表
 | 
				
			||||||
	IsACME      uint8  `field:"isACME"`      // 是否为ACME自动生成的
 | 
						IsACME        uint8  `field:"isACME"`        // 是否为ACME自动生成的
 | 
				
			||||||
	AcmeTaskId  uint64 `field:"acmeTaskId"`  // ACME任务ID
 | 
						AcmeTaskId    uint64 `field:"acmeTaskId"`    // ACME任务ID
 | 
				
			||||||
	NotifiedAt  uint64 `field:"notifiedAt"`  // 最后通知时间
 | 
						NotifiedAt    uint64 `field:"notifiedAt"`    // 最后通知时间
 | 
				
			||||||
 | 
						Ocsp          string `field:"ocsp"`          // OCSP缓存
 | 
				
			||||||
 | 
						OcspIsUpdated uint8  `field:"ocspIsUpdated"` // OCSP是否已更新
 | 
				
			||||||
 | 
						OcspError     string `field:"ocspError"`     // OCSP更新错误
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type SSLCertOperator struct {
 | 
					type SSLCertOperator struct {
 | 
				
			||||||
	Id          interface{} // ID
 | 
						Id            interface{} // ID
 | 
				
			||||||
	AdminId     interface{} // 管理员ID
 | 
						AdminId       interface{} // 管理员ID
 | 
				
			||||||
	UserId      interface{} // 用户ID
 | 
						UserId        interface{} // 用户ID
 | 
				
			||||||
	State       interface{} // 状态
 | 
						State         interface{} // 状态
 | 
				
			||||||
	CreatedAt   interface{} // 创建时间
 | 
						CreatedAt     interface{} // 创建时间
 | 
				
			||||||
	UpdatedAt   interface{} // 修改时间
 | 
						UpdatedAt     interface{} // 修改时间
 | 
				
			||||||
	IsOn        interface{} // 是否启用
 | 
						IsOn          interface{} // 是否启用
 | 
				
			||||||
	Name        interface{} // 证书名
 | 
						Name          interface{} // 证书名
 | 
				
			||||||
	Description interface{} // 描述
 | 
						Description   interface{} // 描述
 | 
				
			||||||
	CertData    interface{} // 证书内容
 | 
						CertData      interface{} // 证书内容
 | 
				
			||||||
	KeyData     interface{} // 密钥内容
 | 
						KeyData       interface{} // 密钥内容
 | 
				
			||||||
	ServerName  interface{} // 证书使用的主机名
 | 
						ServerName    interface{} // 证书使用的主机名
 | 
				
			||||||
	IsCA        interface{} // 是否为CA证书
 | 
						IsCA          interface{} // 是否为CA证书
 | 
				
			||||||
	GroupIds    interface{} // 证书分组
 | 
						GroupIds      interface{} // 证书分组
 | 
				
			||||||
	TimeBeginAt interface{} // 开始时间
 | 
						TimeBeginAt   interface{} // 开始时间
 | 
				
			||||||
	TimeEndAt   interface{} // 结束时间
 | 
						TimeEndAt     interface{} // 结束时间
 | 
				
			||||||
	DnsNames    interface{} // DNS名称列表
 | 
						DnsNames      interface{} // DNS名称列表
 | 
				
			||||||
	CommonNames interface{} // 发行单位列表
 | 
						CommonNames   interface{} // 发行单位列表
 | 
				
			||||||
	IsACME      interface{} // 是否为ACME自动生成的
 | 
						IsACME        interface{} // 是否为ACME自动生成的
 | 
				
			||||||
	AcmeTaskId  interface{} // ACME任务ID
 | 
						AcmeTaskId    interface{} // ACME任务ID
 | 
				
			||||||
	NotifiedAt  interface{} // 最后通知时间
 | 
						NotifiedAt    interface{} // 最后通知时间
 | 
				
			||||||
 | 
						Ocsp          interface{} // OCSP缓存
 | 
				
			||||||
 | 
						OcspIsUpdated interface{} // OCSP是否已更新
 | 
				
			||||||
 | 
						OcspError     interface{} // OCSP更新错误
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewSSLCertOperator() *SSLCertOperator {
 | 
					func NewSSLCertOperator() *SSLCertOperator {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -167,6 +167,9 @@ func (this *SSLPolicyDAO) ComposePolicyConfig(tx *dbs.Tx, policyId int64, cacheM
 | 
				
			|||||||
		config.HSTS = hstsConfig
 | 
							config.HSTS = hstsConfig
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ocsp
 | 
				
			||||||
 | 
						config.OCSPIsOn = policy.OcspIsOn == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if cacheMap != nil {
 | 
						if cacheMap != nil {
 | 
				
			||||||
		cacheMap.Put(cacheKey, config)
 | 
							cacheMap.Put(cacheKey, config)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -196,7 +199,7 @@ func (this *SSLPolicyDAO) FindAllEnabledPolicyIdsWithCertId(tx *dbs.Tx, certId i
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CreatePolicy 创建Policy
 | 
					// CreatePolicy 创建Policy
 | 
				
			||||||
func (this *SSLPolicyDAO) CreatePolicy(tx *dbs.Tx, adminId int64, userId int64, http2Enabled bool, minVersion string, certsJSON []byte, hstsJSON []byte, clientAuthType int32, clientCACertsJSON []byte, cipherSuitesIsOn bool, cipherSuites []string) (int64, error) {
 | 
					func (this *SSLPolicyDAO) CreatePolicy(tx *dbs.Tx, adminId int64, userId int64, http2Enabled bool, minVersion string, certsJSON []byte, hstsJSON []byte, ocspIsOn bool, clientAuthType int32, clientCACertsJSON []byte, cipherSuitesIsOn bool, cipherSuites []string) (int64, error) {
 | 
				
			||||||
	op := NewSSLPolicyOperator()
 | 
						op := NewSSLPolicyOperator()
 | 
				
			||||||
	op.State = SSLPolicyStateEnabled
 | 
						op.State = SSLPolicyStateEnabled
 | 
				
			||||||
	op.IsOn = true
 | 
						op.IsOn = true
 | 
				
			||||||
@@ -213,6 +216,8 @@ func (this *SSLPolicyDAO) CreatePolicy(tx *dbs.Tx, adminId int64, userId int64,
 | 
				
			|||||||
		op.Hsts = hstsJSON
 | 
							op.Hsts = hstsJSON
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						op.OcspIsOn = ocspIsOn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	op.ClientAuthType = clientAuthType
 | 
						op.ClientAuthType = clientAuthType
 | 
				
			||||||
	if len(clientCACertsJSON) > 0 {
 | 
						if len(clientCACertsJSON) > 0 {
 | 
				
			||||||
		op.ClientCACerts = clientCACertsJSON
 | 
							op.ClientCACerts = clientCACertsJSON
 | 
				
			||||||
@@ -234,7 +239,7 @@ func (this *SSLPolicyDAO) CreatePolicy(tx *dbs.Tx, adminId int64, userId int64,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UpdatePolicy 修改Policy
 | 
					// UpdatePolicy 修改Policy
 | 
				
			||||||
func (this *SSLPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, http2Enabled bool, minVersion string, certsJSON []byte, hstsJSON []byte, clientAuthType int32, clientCACertsJSON []byte, cipherSuitesIsOn bool, cipherSuites []string) error {
 | 
					func (this *SSLPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, http2Enabled bool, minVersion string, certsJSON []byte, hstsJSON []byte, ocspIsOn bool, clientAuthType int32, clientCACertsJSON []byte, cipherSuitesIsOn bool, cipherSuites []string) error {
 | 
				
			||||||
	if policyId <= 0 {
 | 
						if policyId <= 0 {
 | 
				
			||||||
		return errors.New("invalid policyId")
 | 
							return errors.New("invalid policyId")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -251,6 +256,8 @@ func (this *SSLPolicyDAO) UpdatePolicy(tx *dbs.Tx, policyId int64, http2Enabled
 | 
				
			|||||||
		op.Hsts = hstsJSON
 | 
							op.Hsts = hstsJSON
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						op.OcspIsOn = ocspIsOn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	op.ClientAuthType = clientAuthType
 | 
						op.ClientAuthType = clientAuthType
 | 
				
			||||||
	if len(clientCACertsJSON) > 0 {
 | 
						if len(clientCACertsJSON) > 0 {
 | 
				
			||||||
		op.ClientCACerts = clientCACertsJSON
 | 
							op.ClientCACerts = clientCACertsJSON
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
package models
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//
 | 
					// SSLPolicy SSL配置策略
 | 
				
			||||||
type SSLPolicy struct {
 | 
					type SSLPolicy struct {
 | 
				
			||||||
	Id               uint32 `field:"id"`               // ID
 | 
						Id               uint32 `field:"id"`               // ID
 | 
				
			||||||
	AdminId          uint32 `field:"adminId"`          // 管理员ID
 | 
						AdminId          uint32 `field:"adminId"`          // 管理员ID
 | 
				
			||||||
@@ -14,6 +14,7 @@ type SSLPolicy struct {
 | 
				
			|||||||
	CipherSuites     string `field:"cipherSuites"`     // 加密算法套件
 | 
						CipherSuites     string `field:"cipherSuites"`     // 加密算法套件
 | 
				
			||||||
	Hsts             string `field:"hsts"`             // HSTS设置
 | 
						Hsts             string `field:"hsts"`             // HSTS设置
 | 
				
			||||||
	Http2Enabled     uint8  `field:"http2Enabled"`     // 是否启用HTTP/2
 | 
						Http2Enabled     uint8  `field:"http2Enabled"`     // 是否启用HTTP/2
 | 
				
			||||||
 | 
						OcspIsOn         uint8  `field:"ocspIsOn"`         // 是否启用OCSP
 | 
				
			||||||
	State            uint8  `field:"state"`            // 状态
 | 
						State            uint8  `field:"state"`            // 状态
 | 
				
			||||||
	CreatedAt        uint64 `field:"createdAt"`        // 创建时间
 | 
						CreatedAt        uint64 `field:"createdAt"`        // 创建时间
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -31,6 +32,7 @@ type SSLPolicyOperator struct {
 | 
				
			|||||||
	CipherSuites     interface{} // 加密算法套件
 | 
						CipherSuites     interface{} // 加密算法套件
 | 
				
			||||||
	Hsts             interface{} // HSTS设置
 | 
						Hsts             interface{} // HSTS设置
 | 
				
			||||||
	Http2Enabled     interface{} // 是否启用HTTP/2
 | 
						Http2Enabled     interface{} // 是否启用HTTP/2
 | 
				
			||||||
 | 
						OcspIsOn         interface{} // 是否启用OCSP
 | 
				
			||||||
	State            interface{} // 状态
 | 
						State            interface{} // 状态
 | 
				
			||||||
	CreatedAt        interface{} // 创建时间
 | 
						CreatedAt        interface{} // 创建时间
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,7 +43,7 @@ func (this *SSLPolicyService) CreateSSLPolicy(ctx context.Context, req *pb.Creat
 | 
				
			|||||||
		// TODO
 | 
							// TODO
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	policyId, err := models.SharedSSLPolicyDAO.CreatePolicy(tx, adminId, userId, req.Http2Enabled, req.MinVersion, req.SslCertsJSON, req.HstsJSON, req.ClientAuthType, req.ClientCACertsJSON, req.CipherSuitesIsOn, req.CipherSuites)
 | 
						policyId, err := models.SharedSSLPolicyDAO.CreatePolicy(tx, adminId, userId, req.Http2Enabled, req.MinVersion, req.SslCertsJSON, req.HstsJSON, req.OcspIsOn, req.ClientAuthType, req.ClientCACertsJSON, req.CipherSuitesIsOn, req.CipherSuites)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -68,7 +68,7 @@ func (this *SSLPolicyService) UpdateSSLPolicy(ctx context.Context, req *pb.Updat
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = models.SharedSSLPolicyDAO.UpdatePolicy(tx, req.SslPolicyId, req.Http2Enabled, req.MinVersion, req.SslCertsJSON, req.HstsJSON, req.ClientAuthType, req.ClientCACertsJSON, req.CipherSuitesIsOn, req.CipherSuites)
 | 
						err = models.SharedSSLPolicyDAO.UpdatePolicy(tx, req.SslPolicyId, req.Http2Enabled, req.MinVersion, req.SslCertsJSON, req.HstsJSON, req.OcspIsOn, req.ClientAuthType, req.ClientCACertsJSON, req.CipherSuitesIsOn, req.CipherSuites)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										176
									
								
								internal/tasks/ssl_cert_update_ocsp_task.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								internal/tasks/ssl_cert_update_ocsp_task.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,176 @@
 | 
				
			|||||||
 | 
					// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package tasks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"crypto"
 | 
				
			||||||
 | 
						"crypto/tls"
 | 
				
			||||||
 | 
						"crypto/x509"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/db/models"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/goman"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"golang.org/x/crypto/ocsp"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						dbs.OnReadyDone(func() {
 | 
				
			||||||
 | 
							goman.New(func() {
 | 
				
			||||||
 | 
								NewSSLCertUpdateOCSPTask().Start()
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SSLCertUpdateOCSPTask struct {
 | 
				
			||||||
 | 
						ticker *time.Ticker
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewSSLCertUpdateOCSPTask() *SSLCertUpdateOCSPTask {
 | 
				
			||||||
 | 
						return &SSLCertUpdateOCSPTask{
 | 
				
			||||||
 | 
							ticker: time.NewTicker(5 * time.Minute),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *SSLCertUpdateOCSPTask) Start() {
 | 
				
			||||||
 | 
						for range this.ticker.C {
 | 
				
			||||||
 | 
							err := this.Loop()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								remotelogs.Error("SSLCertUpdateOCSPTask", err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *SSLCertUpdateOCSPTask) Loop() error {
 | 
				
			||||||
 | 
						ok, err := models.SharedSysLockerDAO.Lock(nil, "ssl_cert_update_ocsp_task", 300-1) // 假设执行时间为1秒
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx *dbs.Tx
 | 
				
			||||||
 | 
						certs, err := models.SharedSSLCertDAO.ListCertsToUpdateOCSP(tx, 10)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return errors.New("list certs failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, cert := range certs {
 | 
				
			||||||
 | 
							ocspData, err := this.UpdateCertOCSP(cert)
 | 
				
			||||||
 | 
							var errString = ""
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								errString = err.Error()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							err = models.SharedSSLCertDAO.UpdateCertOSCP(tx, int64(cert.Id), ocspData, errString)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return errors.New("update ocsp failed: " + err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *SSLCertUpdateOCSPTask) UpdateCertOCSP(certOne *models.SSLCert) (ocspData []byte, err error) {
 | 
				
			||||||
 | 
						if certOne.IsCA == 1 || len(certOne.CertData) == 0 || len(certOne.KeyData) == 0 {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						keyPair, err := tls.X509KeyPair([]byte(certOne.CertData), []byte(certOne.KeyData))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("parse certificate failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(keyPair.Certificate) == 0 {
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var certData = keyPair.Certificate[0]
 | 
				
			||||||
 | 
						cert, err := x509.ParseCertificate(certData)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("parse certificate block failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 是否已过期
 | 
				
			||||||
 | 
						var now = time.Now()
 | 
				
			||||||
 | 
						if cert.NotBefore.After(now) || cert.NotAfter.Before(now) {
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(cert.IssuingCertificateURL) == 0 || len(cert.OCSPServer) == 0 {
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(cert.DNSNames) == 0 {
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var issuerURL = cert.IssuingCertificateURL[0]
 | 
				
			||||||
 | 
						var ocspServerURL = cert.OCSPServer[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var httpClient = utils.SharedHttpClient(5 * time.Second)
 | 
				
			||||||
 | 
						issuerReq, err := http.NewRequest(http.MethodGet, issuerURL, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("request issuer certificate failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						issuerReq.Header.Set("User-Agent", teaconst.ProductName+"/"+teaconst.Version)
 | 
				
			||||||
 | 
						issuerResp, err := httpClient.Do(issuerReq)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("request issuer certificate failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							_ = issuerResp.Body.Close()
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						issuerData, err := ioutil.ReadAll(issuerResp.Body)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("read issuer certificate failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						issuerCert, err := x509.ParseCertificate(issuerData)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("parse issuer certificate failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buf, err := ocsp.CreateRequest(cert, issuerCert, &ocsp.RequestOptions{
 | 
				
			||||||
 | 
							Hash: crypto.SHA1,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("create ocsp request failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ocspReq, err := http.NewRequest(http.MethodPost, ocspServerURL, bytes.NewBuffer(buf))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("request ocsp failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ocspReq.Header.Set("Content-Type", "application/ocsp-request")
 | 
				
			||||||
 | 
						ocspReq.Header.Set("Accept", "application/ocsp-response")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ocspResp, err := httpClient.Do(ocspReq)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("request ocsp failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							_ = ocspResp.Body.Close()
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						respData, err := ioutil.ReadAll(ocspResp.Body)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("read ocsp failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ocspResult, err := ocsp.ParseResponse(respData, issuerCert)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errors.New("decode ocsp failed: " + err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 只返回Good的ocsp
 | 
				
			||||||
 | 
						if ocspResult.Status == ocsp.Good {
 | 
				
			||||||
 | 
							return respData, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								internal/tasks/ssl_cert_update_ocsp_task_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								internal/tasks/ssl_cert_update_ocsp_task_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package tasks_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/tasks"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSSLCertUpdateOCSPTask_Loop(t *testing.T) {
 | 
				
			||||||
 | 
						dbs.NotifyReady()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var task = tasks.NewSSLCertUpdateOCSPTask()
 | 
				
			||||||
 | 
						err := task.Loop()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user