plugai_updsrv/internal/licensecheck/licensecheck.go

110 lines
2.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package licensecheck
import (
"crypto/ecdsa"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/base64"
"encoding/json"
"encoding/pem"
"errors"
"math/big"
"os"
"strings"
"time"
"intent-system/internal/hostid" // 你的 GetRootDiskSerial 包
)
/* ---------- ① 常量:内置公钥 ---------- */
const publicKeyPEM = `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKQtVKlXjOro4qPoavqOU8m5qda0k
olAhHgTayzNuR+nOP1AnjQm10ehhV7Aafo8fUnjxs/rAM+MRdmzcEXrWnw==
-----END PUBLIC KEY-----`
/* ---------- ② 与服务端保持一致的结构 ---------- */
type licenseRequest struct {
MachineID string `json:"machine_id"`
Expiry string `json:"expiry"`
Features []string `json:"features"`
}
/* ---------- ③ 入口Validate(path) ---------- */
func Validate(licPath string) error {
raw, err := os.ReadFile(licPath)
if err != nil {
return err
}
parts := strings.Split(strings.TrimSpace(string(raw)), ".")
if len(parts) != 2 {
return errors.New("invalid license format")
}
payloadB64, sigB64 := parts[0], parts[1]
payload, err := base64.StdEncoding.DecodeString(payloadB64)
if err != nil {
return errors.New("payload base64 decode failed")
}
// 1. 验签
pubKey, err := parsePublicKey(publicKeyPEM)
if err != nil {
return err
}
if !verifySignature(pubKey, payload, sigB64) {
return errors.New("signature mismatch")
}
// 2. 解析字段
var req licenseRequest
if err := json.Unmarshal(payload, &req); err != nil {
return err
}
// 3. 校验机身号
sn, err := hostid.GetRootDiskSerial()
if err != nil {
return err
}
if req.MachineID != sn {
return errors.New("machine ID mismatch")
}
// 4. 校验过期
expiry, err := time.Parse("2006-01-02", req.Expiry)
if err != nil || time.Now().After(expiry) {
return errors.New("license expired")
}
return nil // 👍 通过
}
/* ---------- ④ 辅助函数 ---------- */
func parsePublicKey(pemStr string) (*ecdsa.PublicKey, error) {
block, _ := pem.Decode([]byte(pemStr))
if block == nil || block.Type != "PUBLIC KEY" {
return nil, errors.New("invalid PEM")
}
pubAny, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
return pubAny.(*ecdsa.PublicKey), nil
}
type ecdsaSig struct{ R, S *big.Int }
func verifySignature(pub *ecdsa.PublicKey, msg []byte, sigB64 string) bool {
sigBytes, err := base64.StdEncoding.DecodeString(sigB64)
if err != nil {
return false
}
var sig ecdsaSig
if _, err = asn1.Unmarshal(sigBytes, &sig); err != nil {
return false
}
hash := sha256.Sum256(msg)
return ecdsa.Verify(pub, hash[:], sig.R, sig.S)
}