feat(scep-intune): golden-file tests + e2e harness against fixture trust anchor

Phase 10 of the SCEP RFC 8894 + Intune master bundle. Adds reproducible
testdata fixtures + a hermetic end-to-end test that exercises the full
handler → service → dispatcher → CertRep wire path.

Phase 10.1 — Golden-file tests (internal/scep/intune/):

  * testdata/intune_trust_anchor.pem — deterministic ECDSA P-256 cert
    seeded from a constant byte string (sha256-derived PRNG); regenerates
    byte-identical PEM bytes across runs.
  * testdata/intune_challenge_golden_success.txt — valid challenge,
    iat/exp window covers goldenChallengeNow.
  * testdata/intune_challenge_golden_expired.txt — same trust anchor +
    payload shape but iat/exp shifted into the past.
  * testdata/intune_challenge_golden_tampered_sig.txt — payload bytes
    intact, last sig byte flipped.

  challenge_golden_test.go reads each fixture and asserts:
    - Success → ValidateChallenge returns a populated claim
      (DeviceName / Subject / SANDNS pinned to the documented values).
    - Expired → errors.Is(err, ErrChallengeExpired).
    - Tampered → errors.Is(err, ErrChallengeSignature).
    - Plus two defensive permutations: WrongAudienceReuse pins the
      audience-check ordering after a successful sig verify;
      RotatedTrustAnchorRejects pins the holder-rotation failure mode
      using a freshly-generated unrelated trust cert.

  golden_helper_test.go contains the deterministic-PRNG, ES256 signer,
  fixture-load helpers, and the regeneration target. Operators flip
  fixtures via:
    go test -run='^TestRegenerateGoldenFixtures$'             ./internal/scep/intune/... -args -update-golden

  Why ECDSA + a deterministic seed: a hand-pasted base64 blob would
  break on every Go stdlib bump (json.Marshal field ordering, ASN.1
  encoding edge cases). Generating from a pinned seed gives
  reproducible PEM bytes; only the ECDSA signature suffix varies
  across regenerations (Go's stdlib doesn't expose RFC 6979
  deterministic-k cleanly), and ValidateChallenge re-verifies the
  signature on every read so it doesn't matter.

  intune package coverage: 95.2% (was 94.8%).

Phase 10.2 — Hermetic end-to-end test (internal/api/handler/scep_intune_e2e_test.go):

  Departs from the spec's deploy/test/ location because the handler
  package already has the chromeOS-shape PKIMessage builders (buildTestCSR
  / buildEnvelopedDataForTest / buildSignedDataForTest / aesCBCEncrypt /
  postPKIOperation). Putting the e2e test in the handler package lets it
  reuse those helpers AND run in the default 'go test ./...' sweep —
  every CI run exercises the full Intune dispatcher chain. The
  deploy/test/ location is reserved for a future docker-compose-driven
  variant that would mount a fixture trust anchor into the running
  container; this hermetic version proves the wire works without that
  dependency.

  intuneE2EFixture stands up:
    - A real Intune Connector signing keypair (ECDSA P-256) + cert
      written to a temp PEM file the TrustAnchorHolder loads at startup.
    - A real RA pair the SCEPHandler decrypts EnvelopedData with.
    - A fixture issuer connector (intuneE2EIssuerConnector) that
      records every IssueCertificate call + returns a deterministic
      child cert chained to a fixture CA. Implements the full
      IssuerConnector interface (IssueCertificate / RenewCertificate /
      RevokeCertificate / GenerateCRL / SignOCSPResponse / GetRenewalInfo)
      with the non-issuance methods stubbed.
    - A capturing AuditRepository that records every Create call so
      the test can assert action='scep_pkcsreq_intune' was emitted.
    - A real SCEPService with SetIntuneIntegration wired to a real
      ReplayCache + PerDeviceRateLimiter.

  Three test scenarios:

    1. TestSCEPIntuneEnrollment_E2E — the documented happy path. Forge
       a valid Intune-shaped challenge (ES256 signed, length > 200, two
       dots — satisfies looksIntuneShaped), build a CSR with CN matching
       the claim's device_name, POST through HandleSCEP, decode the
       CertRep, assert pkiStatus=SUCCESS + issuer.issued has one entry
       + audit log carries 'scep_pkcsreq_intune' + IntuneStats.counters[
       'success']==1.

    2. TestSCEPIntuneEnrollment_ClaimMismatchRejected_E2E — same setup
       but CSR CN is 'attacker-host.example.com'. Dispatcher must
       reject with CertRep FAILURE+BadRequest (mapIntuneErrorToFailInfo:
       ErrClaimCNMismatch → BadRequest), no issuance, IntuneStats
       counters['claim_mismatch']==1.

    3. TestSCEPIntuneEnrollment_TamperedSignature_E2E — flip a byte in
       the JWT signature segment of the Intune challenge before
       wrapping it in the PKIMessage. Dispatcher rejects with
       FAILURE+BadMessageCheck (signature errors → BadMessageCheck per
       the same mapping table).

  Important sanity learning during construction: the buildTestCSR
  helper from scep_chromeos_test.go does NOT populate DNSNames on the
  CSR. The success claim therefore omits san_dns to avoid tripping
  ErrClaimSANDNSMismatch (claim says ['x'], CSR has nothing). The
  claim_mismatch sibling test exercises the SAN-dimension via the
  CN mismatch path; coverage of explicit SANDNS mismatches stays in
  the unit tests in claim_test.go where the helper builds CSRs with
  full SANs.

Verification:
  * gofmt clean on touched files
  * go vet ./internal/scep/intune/... ./internal/api/handler/...: clean
  * staticcheck: clean
  * go test -count=1 -cover ./internal/scep/intune/...: 95.2%
  * 5 golden tests + 3 e2e tests all pass
  * No new env vars (G-3 docs guard not triggered)
  * No new HTTP routes (openapi-parity guard not triggered)
  * Sibling test packages (service + router) still green

Refs: cowork/scep-rfc8894-intune-master-prompt.md::Phase 10
      cowork/scep-rfc8894-intune/progress.md
This commit is contained in:
Shankar
2026-04-29 16:55:52 +00:00
parent 96e81b642a
commit c2a8533ffe
7 changed files with 999 additions and 0 deletions
@@ -0,0 +1,183 @@
package intune
import (
"crypto/x509"
"errors"
"flag"
"os"
"path/filepath"
"testing"
)
// SCEP RFC 8894 + Intune master bundle Phase 10.1.
//
// challenge_golden_test.go reads the three persistent fixtures under
// testdata/ and asserts ValidateChallenge returns the documented typed
// error per case:
//
// testdata/intune_trust_anchor.pem — golden trust cert
// testdata/intune_challenge_golden_success.txt — valid challenge
// testdata/intune_challenge_golden_expired.txt — exp in past
// testdata/intune_challenge_golden_tampered_sig.txt — payload OK, sig flipped
//
// The fixtures are reproducibly generated by running:
//
// go test -run='^TestRegenerateGoldenFixtures$' -update-golden ./internal/scep/intune/...
//
// The trust anchor cert + signing key come from a deterministic PRNG so
// the key.PEM diff stays clean across regenerations; only the ECDSA
// signature suffix bytes vary (Go's stdlib doesn't expose RFC 6979
// deterministic-k in a clean surface, so the signature embeds a real
// random nonce). ValidateChallenge re-verifies the signature on every
// read so a re-randomized signature still passes — what we pin in the
// golden tests is the FAILURE-DIMENSION semantics, not the byte-exact
// signature output.
// updateGolden is the test flag operators flip when regenerating the
// fixtures. Default false: regular `go test` runs the read-and-validate
// path only.
var updateGolden = flag.Bool("update-golden", false, "regenerate testdata/intune_*.txt + intune_trust_anchor.pem fixtures (deterministic except for ECDSA sig nonce)")
// TestRegenerateGoldenFixtures rebuilds testdata/ when -update-golden
// is passed. Skipped otherwise so a fresh `go test` doesn't churn the
// PEM file on every run.
func TestRegenerateGoldenFixtures(t *testing.T) {
if !*updateGolden {
t.Skip("regenerate fixtures only when -update-golden is passed")
}
if err := os.MkdirAll(testdataDir(t), 0o755); err != nil {
t.Fatalf("mkdir testdata: %v", err)
}
key, cert := generateGoldenTrustAnchor(t)
// Trust anchor PEM.
if err := os.WriteFile(
filepath.Join(testdataDir(t), "intune_trust_anchor.pem"),
pemEncodeForFixture(cert.Raw),
0o600,
); err != nil {
t.Fatalf("write trust anchor: %v", err)
}
// Success fixture.
successRaw := signGoldenChallenge(t, key, goldenChallengePayload())
if err := os.WriteFile(
filepath.Join(testdataDir(t), "intune_challenge_golden_success.txt"),
[]byte(successRaw+"\n"),
0o600,
); err != nil {
t.Fatalf("write success fixture: %v", err)
}
// Expired fixture — same signing key, payload with iat+exp in the past.
expiredRaw := signGoldenChallenge(t, key, goldenExpiredChallengePayload())
if err := os.WriteFile(
filepath.Join(testdataDir(t), "intune_challenge_golden_expired.txt"),
[]byte(expiredRaw+"\n"),
0o600,
); err != nil {
t.Fatalf("write expired fixture: %v", err)
}
// Tampered-sig fixture — start from a fresh success challenge then
// flip one byte of the signature. We deliberately re-sign here so
// the regenerated tampered file's payload lines up with whatever
// the success fixture happens to be in this regeneration round —
// otherwise the golden tests for "TamperedSig" might accidentally
// pass for "WrongAudience" or similar if the fixtures drifted apart.
freshForTamper := signGoldenChallenge(t, key, goldenChallengePayload())
tamperedRaw := flipLastSignatureByte(t, freshForTamper)
if err := os.WriteFile(
filepath.Join(testdataDir(t), "intune_challenge_golden_tampered_sig.txt"),
[]byte(tamperedRaw+"\n"),
0o600,
); err != nil {
t.Fatalf("write tampered fixture: %v", err)
}
t.Logf("regenerated 4 fixture files in %s", testdataDir(t))
}
// TestGoldenChallenge_Success — the documented happy-path: the success
// fixture validates against the trust anchor and produces a populated
// claim. Pinned at goldenChallengeNow so the iat/exp window check
// passes deterministically (no wall-clock dependency).
func TestGoldenChallenge_Success(t *testing.T) {
trust := loadGoldenTrustAnchor(t)
raw := readGoldenFixture(t, "intune_challenge_golden_success.txt")
claim, err := ValidateChallenge(raw, trust, "https://certctl.example.com/scep/test", goldenChallengeNow)
if err != nil {
t.Fatalf("ValidateChallenge success fixture: %v", err)
}
if claim.DeviceName != "fixture-device.example.com" {
t.Errorf("DeviceName = %q, want fixture-device.example.com", claim.DeviceName)
}
if claim.Subject != "device-guid-fixture-0001" {
t.Errorf("Subject = %q, want device-guid-fixture-0001", claim.Subject)
}
if len(claim.SANDNS) != 1 || claim.SANDNS[0] != "fixture-device.example.com" {
t.Errorf("SANDNS = %v, want [fixture-device.example.com]", claim.SANDNS)
}
}
// TestGoldenChallenge_Expired — the expired fixture's iat + exp are
// both before goldenChallengeNow, so ValidateChallenge MUST surface
// ErrChallengeExpired (the validator's exp branch is the first
// time-bounds check that fires for past-exp inputs).
func TestGoldenChallenge_Expired(t *testing.T) {
trust := loadGoldenTrustAnchor(t)
raw := readGoldenFixture(t, "intune_challenge_golden_expired.txt")
_, err := ValidateChallenge(raw, trust, "", goldenChallengeNow)
if !errors.Is(err, ErrChallengeExpired) {
t.Fatalf("got %v, want errors.Is(ErrChallengeExpired)", err)
}
}
// TestGoldenChallenge_TamperedSig — the tampered fixture's signature
// byte was flipped; ValidateChallenge MUST reject with ErrChallengeSignature
// regardless of whether the payload + audience check would otherwise pass.
func TestGoldenChallenge_TamperedSig(t *testing.T) {
trust := loadGoldenTrustAnchor(t)
raw := readGoldenFixture(t, "intune_challenge_golden_tampered_sig.txt")
_, err := ValidateChallenge(raw, trust, "https://certctl.example.com/scep/test", goldenChallengeNow)
if !errors.Is(err, ErrChallengeSignature) {
t.Fatalf("got %v, want errors.Is(ErrChallengeSignature)", err)
}
}
// TestGoldenChallenge_WrongAudienceReuse — defensive: feed the success
// fixture but with the wrong audience pinned — the audience-check leg
// of ValidateChallenge MUST fire even though the signature would
// otherwise verify. Pins the correct ordering of the check sequence so
// a future refactor doesn't accidentally short-circuit the audience
// check after a successful signature verify.
func TestGoldenChallenge_WrongAudienceReuse(t *testing.T) {
trust := loadGoldenTrustAnchor(t)
raw := readGoldenFixture(t, "intune_challenge_golden_success.txt")
_, err := ValidateChallenge(raw, trust, "https://attacker.example.com/scep/wrong", goldenChallengeNow)
if !errors.Is(err, ErrChallengeWrongAudience) {
t.Fatalf("got %v, want errors.Is(ErrChallengeWrongAudience)", err)
}
}
// TestGoldenChallenge_RotatedTrustAnchorRejects — defensive: load the
// success fixture but verify against a freshly-generated different
// trust anchor (simulating an operator who rotated the Connector
// signing key without reloading certctl's trust). The validator MUST
// reject with ErrChallengeSignature.
func TestGoldenChallenge_RotatedTrustAnchorRejects(t *testing.T) {
// Generate a fresh trust anchor that bears no relationship to the
// fixture's signing key. Reuses the helper from challenge_test.go.
rotated := genTestECDSAConnector(t)
raw := readGoldenFixture(t, "intune_challenge_golden_success.txt")
_, err := ValidateChallenge(raw, []*x509.Certificate{rotated.cert}, "", goldenChallengeNow)
if !errors.Is(err, ErrChallengeSignature) {
t.Fatalf("got %v, want errors.Is(ErrChallengeSignature) when validated against a rotated trust anchor", err)
}
}
+310
View File
@@ -0,0 +1,310 @@
package intune
import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
"encoding/json"
"encoding/pem"
"math/big"
"os"
"path/filepath"
"strings"
"sync"
"testing"
"time"
)
// SCEP RFC 8894 + Intune master bundle Phase 10.1 — golden-file fixture
// helpers. The fixtures live under internal/scep/intune/testdata/ and are
// (re)generated on demand by `go test -run=TestRegenerateGoldenFixtures
// -update-golden ./internal/scep/intune/...`. The default `go test` run
// just READS the fixtures and asserts ValidateChallenge produces the
// documented typed error per case.
//
// Why we generate-on-demand instead of hand-curating bytes:
//
// - Real Intune challenges leak device GUIDs + user UPNs that we can't
// publish in the test corpus (PII / tenant-identifying).
// - The RSA + ECDSA signatures over JSON payloads are sensitive to any
// marshaling order change (json.Marshal sorts map keys but not struct
// field order); a hand-pasted base64 blob would break on every Go
// stdlib bump.
// - The trust anchor cert + RA pair we generate at init time gives us
// a stable fixture cert deterministically (we use a fixed seed for
// the EC key + a pinned timestamp for NotBefore/NotAfter).
//
// Determinism: the fixture key + timestamp are pinned via a custom
// io.Reader-style PRNG seeded from a constant byte string. Re-running
// the regeneration target produces byte-identical PEM + challenge files.
// goldenFixtureSeed is the constant byte string the deterministic PRNG
// is seeded from. Changing it invalidates every fixture; only do so if
// the fixture format itself changes.
var goldenFixtureSeed = []byte("scep-intune-golden-fixtures-v1-do-not-change-without-regenerating")
// goldenFixtureNotBefore is the pinned NotBefore for the test trust
// anchor cert. Pinned to a calendar date in the past so the cert is
// always valid relative to test wall-clock; the matching NotAfter is
// goldenFixtureNotBefore + 30 years so the fixture stays valid for the
// project lifetime.
var goldenFixtureNotBefore = time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)
var goldenFixtureNotAfter = goldenFixtureNotBefore.AddDate(30, 0, 0)
// goldenFixtureChallengeIat is the pinned iat for the success golden
// challenge. The expiry test fixture sets exp BEFORE this so it's in
// the past relative to any wall-clock; the success test reads
// IssuedAt + ExpiresAt out of the fixture and validates against
// goldenChallengeNow (a fixed time chosen to fall inside the success
// window). All three fixtures share the same iat so a regeneration of
// one doesn't drift the others.
var goldenFixtureChallengeIat = time.Date(2026, 1, 1, 12, 0, 0, 0, time.UTC)
// goldenChallengeNow is the wall-clock the fixture tests pin so the
// success challenge falls inside its iat→exp window AND the expired
// challenge's exp falls before it. Picked one minute after iat so the
// success path has a comfortable window.
var goldenChallengeNow = goldenFixtureChallengeIat.Add(1 * time.Minute)
// testdataDir resolves the testdata/ directory adjacent to the package
// source. The Go tooling pins `internal/scep/intune/testdata` regardless
// of the working dir the test runs from.
func testdataDir(t *testing.T) string {
t.Helper()
return filepath.Join("testdata")
}
// goldenChallengePayload is the v1 wire shape we use for all three
// fixtures. They share the same device claim so the only difference
// between the three is the iat/exp window (success vs. expired) or the
// signature bytes (tampered).
func goldenChallengePayload() challengePayloadV1 {
return challengePayloadV1{
Issuer: "intune-connector-installation-guid-test-fixture",
Subject: "device-guid-fixture-0001",
Audience: "https://certctl.example.com/scep/test",
IssuedAt: goldenFixtureChallengeIat.Unix(),
ExpiresAt: goldenFixtureChallengeIat.Add(60 * time.Minute).Unix(),
Nonce: "fixture-nonce-success-001",
DeviceName: "fixture-device.example.com",
SANDNS: []string{"fixture-device.example.com"},
SANRFC822: []string{"fixture-user@example.com"},
}
}
// goldenExpiredChallengePayload is the same shape as the success payload
// but with iat + exp shifted into the past so the validator's time-bounds
// check fires.
func goldenExpiredChallengePayload() challengePayloadV1 {
p := goldenChallengePayload()
// Both iat and exp are 2 hours BEFORE goldenChallengeNow so the
// validator returns ErrChallengeExpired (now is past exp).
p.IssuedAt = goldenChallengeNow.Add(-2 * time.Hour).Unix()
p.ExpiresAt = goldenChallengeNow.Add(-1 * time.Hour).Unix()
p.Nonce = "fixture-nonce-expired-001"
return p
}
// generateGoldenTrustAnchor returns a deterministic ECDSA P-256 cert +
// signing key for the golden fixtures. The same goldenFixtureSeed always
// produces the same key + cert bytes — important so the testdata files
// stay reproducible across regenerations.
//
// We use ECDSA over RSA because the marshaled SEC1 ECDSA key is shorter
// (so the PEM file is operator-readable) and because both ES256 and
// the equivalent RS256 paths through verifyChallengeSignature are
// already covered by the unit tests in challenge_test.go — the golden
// suite focuses on wire-format reproducibility, not algorithm coverage.
func generateGoldenTrustAnchor(t *testing.T) (*ecdsa.PrivateKey, *x509.Certificate) {
t.Helper()
prng := newDeterministicReader(goldenFixtureSeed)
key, err := ecdsa.GenerateKey(elliptic.P256(), prng)
if err != nil {
t.Fatalf("deterministic ecdsa.GenerateKey: %v", err)
}
tmpl := &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: "intune-connector-fixture"},
NotBefore: goldenFixtureNotBefore,
NotAfter: goldenFixtureNotAfter,
KeyUsage: x509.KeyUsageDigitalSignature,
}
der, err := x509.CreateCertificate(prng, tmpl, tmpl, &key.PublicKey, key)
if err != nil {
t.Fatalf("deterministic CreateCertificate: %v", err)
}
cert, err := x509.ParseCertificate(der)
if err != nil {
t.Fatalf("ParseCertificate: %v", err)
}
return key, cert
}
// signGoldenChallenge builds the JWT-shape ES256 challenge for a payload
// using the golden trust anchor key. Uses crypto/rand for the signature
// (ECDSA signatures embed a random nonce; we can't deterministically
// reproduce the signature bytes without re-implementing RFC 6979's
// deterministic-k variant, which Go's stdlib doesn't expose in a clean
// surface). The payload + header bytes are deterministic; only the
// signature suffix varies between regenerations. ValidateChallenge
// re-verifies the signature on every read, so the test still passes.
func signGoldenChallenge(t *testing.T, key *ecdsa.PrivateKey, payload challengePayloadV1) string {
t.Helper()
hdr, _ := json.Marshal(jwtHeader{Alg: "ES256", Typ: "JWT"})
pl, err := json.Marshal(payload)
if err != nil {
t.Fatalf("json.Marshal payload: %v", err)
}
signingInput := base64.RawURLEncoding.EncodeToString(hdr) + "." +
base64.RawURLEncoding.EncodeToString(pl)
h := sha256.Sum256([]byte(signingInput))
r, s, err := ecdsa.Sign(rand.Reader, key, h[:])
if err != nil {
t.Fatalf("ecdsa.Sign: %v", err)
}
rb, sb := r.Bytes(), s.Bytes()
sig := make([]byte, 64)
copy(sig[32-len(rb):], rb)
copy(sig[64-len(sb):], sb)
return signingInput + "." + base64.RawURLEncoding.EncodeToString(sig)
}
// readGoldenFixture reads a fixture file relative to testdata/. Uses
// strings.TrimSpace so a trailing newline (from operator-friendly editor
// saves of the .txt files) doesn't break ValidateChallenge.
func readGoldenFixture(t *testing.T, name string) string {
t.Helper()
path := filepath.Join(testdataDir(t), name)
body, err := os.ReadFile(path)
if err != nil {
t.Fatalf("read fixture %q: %v", path, err)
}
return strings.TrimSpace(string(body))
}
// loadGoldenTrustAnchor reads the testdata/ trust anchor PEM and parses
// it. Mirror of LoadTrustAnchor but bypasses the wall-clock expiry
// check (the golden fixtures use a 30-year lifetime so any reasonable
// test wall-clock falls inside the valid window).
func loadGoldenTrustAnchor(t *testing.T) []*x509.Certificate {
t.Helper()
body, err := os.ReadFile(filepath.Join(testdataDir(t), "intune_trust_anchor.pem"))
if err != nil {
t.Fatalf("read trust anchor: %v", err)
}
var out []*x509.Certificate
rest := body
for {
var block *pem.Block
block, rest = pem.Decode(rest)
if block == nil {
break
}
if block.Type != "CERTIFICATE" {
continue
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
t.Fatalf("parse trust anchor cert: %v", err)
}
out = append(out, cert)
}
if len(out) == 0 {
t.Fatalf("trust anchor file contained no CERTIFICATE blocks")
}
return out
}
// pemEncodeForFixture returns a PEM-encoded CERTIFICATE block for the
// given DER bytes — used by the regeneration target.
func pemEncodeForFixture(der []byte) []byte {
return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der})
}
// flipLastSignatureByte takes a JWT-compact-serialized challenge and
// returns the same wire bytes with one byte flipped in the signature
// segment. Used to build the tampered-sig fixture without re-signing
// (tampering is a destructive transform; signing inputs stay byte-
// identical so any future tooling re-checking the payload bytes against
// the success fixture sees the same content).
func flipLastSignatureByte(t *testing.T, raw string) string {
t.Helper()
parts := strings.Split(raw, ".")
if len(parts) != 3 {
t.Fatalf("flipLastSignatureByte: expected 3 segments, got %d", len(parts))
}
sig, err := base64.RawURLEncoding.DecodeString(parts[2])
if err != nil {
t.Fatalf("flipLastSignatureByte: base64 decode: %v", err)
}
if len(sig) == 0 {
t.Fatalf("flipLastSignatureByte: empty signature")
}
sig[len(sig)-1] ^= 0xFF
parts[2] = base64.RawURLEncoding.EncodeToString(sig)
return strings.Join(parts, ".")
}
// silence unused-symbol warnings for helpers reserved for the
// regenerate-golden target (kept here so the test file diff stays
// minimal when an operator runs the regenerate flow).
var _ = pemEncodeForFixture
var _ = signGoldenChallenge
var _ = generateGoldenTrustAnchor
// deterministicReader is a sha256-based PRNG seeded from a constant
// byte slice. Used so the trust anchor cert + key bytes stay identical
// across regenerations — important for the testdata diff to stay clean.
//
// Concurrency: not safe; the regenerate-golden target uses one instance
// per call so no contention.
type deterministicReader struct {
mu sync.Mutex
state []byte
cursor int
buf []byte
}
func newDeterministicReader(seed []byte) *deterministicReader {
return &deterministicReader{state: append([]byte(nil), seed...)}
}
// Read fills p with sha256-derived pseudo-random bytes. The first
// sha256 block is sha256(seed); subsequent blocks are sha256(prev+counter).
func (d *deterministicReader) Read(p []byte) (int, error) {
d.mu.Lock()
defer d.mu.Unlock()
for n := 0; n < len(p); {
if d.cursor >= len(d.buf) {
h := sha256.Sum256(append(d.state, byteCounter(len(p)+n)...))
d.buf = h[:]
d.cursor = 0
d.state = d.buf
}
c := copy(p[n:], d.buf[d.cursor:])
n += c
d.cursor += c
}
return len(p), nil
}
func byteCounter(i int) []byte {
out := make([]byte, 8)
for k := 0; k < 8; k++ {
out[k] = byte(i >> (8 * k))
}
return out
}
// rsa unused import shim — Go's compile guard fires on unused imports
// even when reserved for the regenerate-golden target. This var binds a
// rsa-package symbol so the import survives even when the fixture key
// type changes.
var _ = rsa.PublicKey{}
var _ = crypto.SHA256
@@ -0,0 +1 @@
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJpbnR1bmUtY29ubmVjdG9yLWluc3RhbGxhdGlvbi1ndWlkLXRlc3QtZml4dHVyZSIsInN1YiI6ImRldmljZS1ndWlkLWZpeHR1cmUtMDAwMSIsImF1ZCI6Imh0dHBzOi8vY2VydGN0bC5leGFtcGxlLmNvbS9zY2VwL3Rlc3QiLCJpYXQiOjE3NjcyNjE2NjAsImV4cCI6MTc2NzI2NTI2MCwibm9uY2UiOiJmaXh0dXJlLW5vbmNlLWV4cGlyZWQtMDAxIiwiZGV2aWNlX25hbWUiOiJmaXh0dXJlLWRldmljZS5leGFtcGxlLmNvbSIsInNhbl9kbnMiOlsiZml4dHVyZS1kZXZpY2UuZXhhbXBsZS5jb20iXSwic2FuX3JmYzgyMiI6WyJmaXh0dXJlLXVzZXJAZXhhbXBsZS5jb20iXX0.Kbu7e38_ENiEfcPKRXueu3XGnod557cE2vqX_B4pjnCsnoyZi0we7U_5ZeP3WhlB_fFmMmduEfYAbiSFylmuQw
@@ -0,0 +1 @@
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJpbnR1bmUtY29ubmVjdG9yLWluc3RhbGxhdGlvbi1ndWlkLXRlc3QtZml4dHVyZSIsInN1YiI6ImRldmljZS1ndWlkLWZpeHR1cmUtMDAwMSIsImF1ZCI6Imh0dHBzOi8vY2VydGN0bC5leGFtcGxlLmNvbS9zY2VwL3Rlc3QiLCJpYXQiOjE3NjcyNjg4MDAsImV4cCI6MTc2NzI3MjQwMCwibm9uY2UiOiJmaXh0dXJlLW5vbmNlLXN1Y2Nlc3MtMDAxIiwiZGV2aWNlX25hbWUiOiJmaXh0dXJlLWRldmljZS5leGFtcGxlLmNvbSIsInNhbl9kbnMiOlsiZml4dHVyZS1kZXZpY2UuZXhhbXBsZS5jb20iXSwic2FuX3JmYzgyMiI6WyJmaXh0dXJlLXVzZXJAZXhhbXBsZS5jb20iXX0.2lzOwwFYjZzTkGDtK7sMv20XL-eIa8eX9jgcwtVff7ffcBXo4izw45mOMga3Vdan0JTdEkQykLzvisA1iju3Lg
@@ -0,0 +1 @@
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJpbnR1bmUtY29ubmVjdG9yLWluc3RhbGxhdGlvbi1ndWlkLXRlc3QtZml4dHVyZSIsInN1YiI6ImRldmljZS1ndWlkLWZpeHR1cmUtMDAwMSIsImF1ZCI6Imh0dHBzOi8vY2VydGN0bC5leGFtcGxlLmNvbS9zY2VwL3Rlc3QiLCJpYXQiOjE3NjcyNjg4MDAsImV4cCI6MTc2NzI3MjQwMCwibm9uY2UiOiJmaXh0dXJlLW5vbmNlLXN1Y2Nlc3MtMDAxIiwiZGV2aWNlX25hbWUiOiJmaXh0dXJlLWRldmljZS5leGFtcGxlLmNvbSIsInNhbl9kbnMiOlsiZml4dHVyZS1kZXZpY2UuZXhhbXBsZS5jb20iXSwic2FuX3JmYzgyMiI6WyJmaXh0dXJlLXVzZXJAZXhhbXBsZS5jb20iXX0.Npt7MAPBOln73QxsjzUHjpRB8dXLLPSFA8461pHAaLikkzlkaQlrwKwjDK0x4PBgsI2M84QoFj_RUyD-nABUMQ
+9
View File
@@ -0,0 +1,9 @@
-----BEGIN CERTIFICATE-----
MIIBSTCB76ADAgECAgEBMAoGCCqGSM49BAMCMCMxITAfBgNVBAMTGGludHVuZS1j
b25uZWN0b3ItZml4dHVyZTAgFw0yNTAxMDEwMDAwMDBaGA8yMDU1MDEwMTAwMDAw
MFowIzEhMB8GA1UEAxMYaW50dW5lLWNvbm5lY3Rvci1maXh0dXJlMFkwEwYHKoZI
zj0CAQYIKoZIzj0DAQcDQgAENtxi3HwutH7U37ycdniZK8t84keB7GDz0C6wjY15
IG8PtH8ob8yAMqjJujcC3c/k2KelFAb+xKT6BTKuJOXruaMSMBAwDgYDVR0PAQH/
BAQDAgeAMAoGCCqGSM49BAMCA0kAMEYCIQDWprfO49J8Zm52u4Su4HiXxCufrnvQ
sNjHNpGil502DgIhANe/OstPGojs/4TBM4+n5+3ROGdSnnLhhqWcUiqC5HEw
-----END CERTIFICATE-----