fix(license): harden release key validation and fingerprint logging

(cherry picked from commit f253ed2778)
This commit is contained in:
rcourtman
2026-02-07 14:18:44 +00:00
parent eb7b399a55
commit 0424c5ae3b
3 changed files with 71 additions and 6 deletions

View File

@@ -2,6 +2,7 @@ package license
import (
"crypto/ed25519"
"crypto/sha256"
"encoding/base64"
"os"
"strings"
@@ -14,6 +15,14 @@ import (
// Example: go build -ldflags "-X github.com/rcourtman/pulse-go-rewrite/internal/license.EmbeddedPublicKey=BASE64_KEY"
var EmbeddedPublicKey string = ""
func publicKeyFingerprint(key ed25519.PublicKey) string {
if len(key) == 0 {
return ""
}
sum := sha256.Sum256(key)
return "SHA256:" + base64.StdEncoding.EncodeToString(sum[:])
}
// InitPublicKey initializes the public key for license validation.
// Priority:
// 1. PULSE_LICENSE_PUBLIC_KEY environment variable (base64 encoded)
@@ -30,7 +39,10 @@ func InitPublicKey() {
// Fall through to try embedded key instead of returning
} else {
SetPublicKey(key)
log.Info().Msg("License public key loaded from environment")
log.Info().
Str("source", "environment").
Str("fingerprint", publicKeyFingerprint(key)).
Msg("License public key loaded")
return
}
}
@@ -42,7 +54,10 @@ func InitPublicKey() {
log.Error().Err(err).Msg("Failed to decode embedded public key")
} else {
SetPublicKey(key)
log.Info().Msg("License public key loaded from embedded key")
log.Info().
Str("source", "embedded").
Str("fingerprint", publicKeyFingerprint(key)).
Msg("License public key loaded")
return
}
}

View File

@@ -2,8 +2,10 @@ package license
import (
"crypto/ed25519"
"crypto/sha256"
"encoding/base64"
"os"
"strings"
"testing"
)
@@ -115,3 +117,22 @@ func TestDecodePublicKey(t *testing.T) {
})
}
}
func TestPublicKeyFingerprint(t *testing.T) {
pub, _, _ := ed25519.GenerateKey(nil)
got := publicKeyFingerprint(pub)
if !strings.HasPrefix(got, "SHA256:") {
t.Fatalf("expected SHA256 prefix, got %q", got)
}
sum := sha256.Sum256(pub)
want := "SHA256:" + base64.StdEncoding.EncodeToString(sum[:])
if got != want {
t.Fatalf("fingerprint mismatch: got %q want %q", got, want)
}
if empty := publicKeyFingerprint(nil); empty != "" {
t.Fatalf("expected empty fingerprint for nil key, got %q", empty)
}
}

View File

@@ -19,12 +19,41 @@ RELEASE_DIR="release"
echo "Building Pulse v${VERSION}..."
# Optional public key embedding for license validation
# Require public key embedding for release-grade license validation.
# Explicitly opt out with PULSE_ALLOW_MISSING_LICENSE_KEY=true (not recommended).
LICENSE_LDFLAGS=""
if [[ -n "${PULSE_LICENSE_PUBLIC_KEY:-}" ]]; then
LICENSE_LDFLAGS="-X github.com/rcourtman/pulse-go-rewrite/internal/license.EmbeddedPublicKey=${PULSE_LICENSE_PUBLIC_KEY}"
if [[ -z "${PULSE_LICENSE_PUBLIC_KEY:-}" ]]; then
if [[ "${PULSE_ALLOW_MISSING_LICENSE_KEY:-false}" == "true" ]]; then
echo "Warning: PULSE_LICENSE_PUBLIC_KEY not set; continuing because PULSE_ALLOW_MISSING_LICENSE_KEY=true."
else
echo "Error: PULSE_LICENSE_PUBLIC_KEY is required for release builds." >&2
echo "Set PULSE_ALLOW_MISSING_LICENSE_KEY=true only for local non-release debugging." >&2
exit 1
fi
else
echo "Warning: PULSE_LICENSE_PUBLIC_KEY not set; Pulse Pro license activation will fail for release binaries."
decoded_key_len=$(printf '%s' "${PULSE_LICENSE_PUBLIC_KEY}" | openssl base64 -d -A 2>/dev/null | wc -c | tr -d ' ')
if [[ "${decoded_key_len}" != "32" ]]; then
echo "Error: PULSE_LICENSE_PUBLIC_KEY must decode to 32 bytes (Ed25519 public key)." >&2
exit 1
fi
if [[ -n "${PULSE_LICENSE_PUBLIC_KEY_FINGERPRINT:-}" ]]; then
expected_fingerprint="${PULSE_LICENSE_PUBLIC_KEY_FINGERPRINT#SHA256:}"
actual_fingerprint=$(printf '%s' "${PULSE_LICENSE_PUBLIC_KEY}" | openssl base64 -d -A 2>/dev/null | openssl dgst -sha256 -binary | openssl base64 -A)
if [[ -z "${actual_fingerprint}" ]]; then
echo "Error: Failed to compute fingerprint for PULSE_LICENSE_PUBLIC_KEY." >&2
exit 1
fi
if [[ "${actual_fingerprint}" != "${expected_fingerprint}" ]]; then
echo "Error: PULSE_LICENSE_PUBLIC_KEY fingerprint mismatch." >&2
echo "Expected: SHA256:${expected_fingerprint}" >&2
echo "Actual: SHA256:${actual_fingerprint}" >&2
exit 1
fi
echo "Verified license public key fingerprint: SHA256:${actual_fingerprint}"
fi
LICENSE_LDFLAGS="-X github.com/rcourtman/pulse-go-rewrite/internal/license.EmbeddedPublicKey=${PULSE_LICENSE_PUBLIC_KEY}"
fi
# Clean previous builds