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) }