Files
3x-ui-web-src/internal/pia/serverlist_signature.go
Sanaei f727d04f65
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
Docs CI / build (push) Canceled after 0s
Docs Deploy (GitHub Pages) / build (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Deploy Smoke Tests / noninteractive-install (ubuntu-24.04-arm) (push) Canceled after 0s
Deploy Smoke Tests / noninteractive-install (ubuntu-latest) (push) Canceled after 0s
Deploy Smoke Tests / release-tag-install (ubuntu-24.04-arm) (push) Canceled after 0s
Deploy Smoke Tests / release-tag-install (ubuntu-latest) (push) Canceled after 0s
Docs Deploy (GitHub Pages) / deploy (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
v3.7.0
2026-08-24 15:07:15 +02:00

64 lines
1.9 KiB
Go

package pia
import (
"bytes"
"crypto"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"unicode"
)
func VerifySignedServerList(raw, publicKeyPEM []byte) ([]byte, error) {
jsonBody, signature, err := splitSignedServerList(raw)
if err != nil {
return nil, WrapError(CodeCatalogSignatureInvalid, "The PIA region list signature is missing or invalid.", err)
}
block, _ := pem.Decode(publicKeyPEM)
if block == nil {
return nil, NewError(CodeCatalogSignatureInvalid, "The built-in region-list public key is invalid.")
}
parsed, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, WrapError(CodeCatalogSignatureInvalid, "The built-in region-list public key is invalid.", err)
}
publicKey, ok := parsed.(*rsa.PublicKey)
if !ok {
return nil, NewError(CodeCatalogSignatureInvalid, "The region-list public key is not RSA.")
}
digest := sha256.Sum256(jsonBody)
if err := rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, digest[:], signature); err != nil {
return nil, WrapError(CodeCatalogSignatureInvalid, "The PIA region list signature does not match its content.", err)
}
return jsonBody, nil
}
func splitSignedServerList(raw []byte) ([]byte, []byte, error) {
if len(raw) == 0 || raw[0] != '{' {
return nil, nil, fmt.Errorf("response does not start with a JSON object")
}
end := bytes.LastIndexByte(raw, '}')
if end < 0 || end == len(raw)-1 {
return nil, nil, fmt.Errorf("appended signature is absent")
}
jsonBody := append([]byte(nil), raw[:end+1]...)
encoded := bytes.Map(func(r rune) rune {
if unicode.IsSpace(r) {
return -1
}
return r
}, raw[end+1:])
if len(encoded) == 0 {
return nil, nil, fmt.Errorf("appended signature is empty")
}
signature := make([]byte, base64.StdEncoding.DecodedLen(len(encoded)))
n, err := base64.StdEncoding.Decode(signature, encoded)
if err != nil {
return nil, nil, fmt.Errorf("decode signature: %w", err)
}
return jsonBody, signature[:n], nil
}