Files
license/sdk/licence/envelope.go
2026-07-31 16:59:55 +08:00

127 lines
4.4 KiB
Go

package licence
import (
"bytes"
"crypto/ed25519"
"encoding/json"
"fmt"
"unicode/utf8"
)
type SigningKeyCertificate struct {
FormatVersion int `json:"format_version"`
KeyID string `json:"key_id"`
PublicKey string `json:"public_key"`
RootSignature string `json:"root_signature"`
}
type Envelope struct {
FormatVersion int `json:"format_version"`
Licence Claims `json:"licence"`
SigningKeyCertificate SigningKeyCertificate `json:"signing_key_certificate"`
Signature string `json:"signature"`
}
func Parse(content []byte) (Envelope, error) {
var envelope Envelope
if len(content) > maximumLicenceFileBytes {
return envelope, ErrFileTooLarge
}
if err := strictDecodeJSON(content, &envelope); err != nil {
return envelope, fmt.Errorf("%w: %v", ErrMalformedFile, err)
}
if err := validateEnvelopeFormat(envelope); err != nil {
return envelope, err
}
return envelope, nil
}
func MarshalEnvelope(envelope Envelope) ([]byte, error) {
if err := validateEnvelopeFormat(envelope); err != nil {
return nil, err
}
var output bytes.Buffer
encoder := json.NewEncoder(&output)
encoder.SetEscapeHTML(false)
encoder.SetIndent("", " ")
if err := encoder.Encode(envelope); err != nil {
return nil, fmt.Errorf("编码许可证文件: %w", err)
}
if output.Len() > maximumLicenceFileBytes {
return nil, ErrFileTooLarge
}
return output.Bytes(), nil
}
func RootPublicKey() ed25519.PublicKey {
publicKey := make(ed25519.PublicKey, len(rootPublicKey))
copy(publicKey, rootPublicKey[:])
return publicKey
}
func VerifySigningKeyCertificate(c SigningKeyCertificate) (ed25519.PublicKey, error) {
if c.FormatVersion != formatVersion {
return nil, fmt.Errorf("%w: 格式版本错误", ErrInvalidKeyCertificate)
}
if _, err := parseUUID(c.KeyID); err != nil {
return nil, fmt.Errorf("%w: 密钥 ID 格式错误", ErrInvalidKeyCertificate)
}
publicKey, err := decodeBase64URL(c.PublicKey, ed25519.PublicKeySize)
if err != nil {
return nil, fmt.Errorf("%w: 公钥格式错误", ErrInvalidKeyCertificate)
}
rootSignature, err := decodeBase64URL(c.RootSignature, ed25519.SignatureSize)
if err != nil {
return nil, fmt.Errorf("%w: 根签名格式错误", ErrInvalidKeyCertificate)
}
message, err := CertificateMessage(c)
if err != nil {
return nil, fmt.Errorf("%w: 凭证消息格式错误", ErrInvalidKeyCertificate)
}
if !ed25519.Verify(rootPublicKey[:], message, rootSignature) {
return nil, fmt.Errorf("%w: 根签名验证失败", ErrInvalidKeyCertificate)
}
result := make(ed25519.PublicKey, len(publicKey))
copy(result, publicKey)
return result, nil
}
func validateEnvelopeFormat(envelope Envelope) error {
if envelope.FormatVersion != formatVersion || envelope.SigningKeyCertificate.FormatVersion != formatVersion {
return ErrUnsupportedVersion
}
if _, err := parseUUID(envelope.Licence.ID); err != nil {
return fmt.Errorf("%w: 许可证 ID 格式错误", ErrMalformedFile)
}
if _, err := parseUUID(envelope.Licence.SigningKeyID); err != nil {
return fmt.Errorf("%w: 签发密钥 ID 格式错误", ErrMalformedFile)
}
if _, err := parseUUID(envelope.SigningKeyCertificate.KeyID); err != nil {
return fmt.Errorf("%w: 凭证密钥 ID 格式错误", ErrMalformedFile)
}
if !utf8.ValidString(envelope.Licence.PlatformName) || !utf8.ValidString(envelope.Licence.Workspace) {
return fmt.Errorf("%w: 主体字符串不是有效的 UTF-8", ErrMalformedFile)
}
if _, err := envelope.Licence.IssuedOn.Time(); err != nil {
return fmt.Errorf("%w: 签发日期格式错误", ErrMalformedFile)
}
if _, err := envelope.Licence.ValidFrom.Time(); err != nil {
return fmt.Errorf("%w: 生效日期格式错误", ErrMalformedFile)
}
if _, err := envelope.Licence.ExpiresOn.Time(); err != nil {
return fmt.Errorf("%w: 到期日期格式错误", ErrMalformedFile)
}
if _, err := decodeBase64URL(envelope.SigningKeyCertificate.PublicKey, ed25519.PublicKeySize); err != nil {
return fmt.Errorf("%w: 凭证公钥格式错误", ErrMalformedFile)
}
if _, err := decodeBase64URL(envelope.SigningKeyCertificate.RootSignature, ed25519.SignatureSize); err != nil {
return fmt.Errorf("%w: 根签名格式错误", ErrMalformedFile)
}
if _, err := decodeBase64URL(envelope.Signature, ed25519.SignatureSize); err != nil {
return fmt.Errorf("%w: 许可证签名格式错误", ErrMalformedFile)
}
return nil
}