router-for-me/CLIProxyAPI · error

private_key invalid pkcs8: %w

Error message

private_key invalid pkcs8: %w

What it means

From ensureRSAPrivateKey when the PEM block is typed 'PRIVATE KEY' (PKCS#8 generic) but x509.ParsePKCS8PrivateKey fails on its DER bytes (keyutil.go:98-101). The wrapper is fine; the inner ASN.1 payload is not parseable as any PKCS#8 key.

Source

Thrown at internal/auth/vertex/keyutil.go:101

	return string(pem.EncodeToMemory(rsaBlock)), nil
}

func ensureRSAPrivateKey(block *pem.Block) (*pem.Block, error) {
	if block == nil {
		return nil, fmt.Errorf("pem block is nil")
	}

	if block.Type == "RSA PRIVATE KEY" {
		if _, err := x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
			return nil, fmt.Errorf("private_key invalid rsa: %w", err)
		}
		return block, nil
	}

	if block.Type == "PRIVATE KEY" {
		key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
		if err != nil {
			return nil, fmt.Errorf("private_key invalid pkcs8: %w", err)
		}
		rsaKey, ok := key.(*rsa.PrivateKey)
		if !ok {
			return nil, fmt.Errorf("private_key is not an RSA key")
		}
		der := x509.MarshalPKCS1PrivateKey(rsaKey)
		return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: der}, nil
	}

	// Attempt auto-detection: try PKCS#1 first, then PKCS#8.
	if rsaKey, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {
		der := x509.MarshalPKCS1PrivateKey(rsaKey)
		return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: der}, nil
	}
	if key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {
		if rsaKey, ok := key.(*rsa.PrivateKey); ok {
			der := x509.MarshalPKCS1PrivateKey(rsaKey)
			return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: der}, nil

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Validate independently: openssl pkcs8 -in key.pem -nocrypt -noout; if it fails, the key file itself is bad
  2. Re-export an unencrypted PKCS#8 RSA key or, simplest, re-download the GCP service account JSON
  3. If the key is PBES2-encrypted, decrypt it first (openssl pkcs8 -passin ...) and store the plaintext in the secret manager

Example fix

# before: encrypted PKCS#8 stored raw
-----BEGIN ENCRYPTED PRIVATE KEY-----
# after: decrypt then store
openssl pkcs8 -in enc.pem -passin file:pass.txt -nocrypt -out plain.pem
Defensive patterns

Strategy: validation

Validate before calling

block, _ := pem.Decode([]byte(pk))
if block != nil && block.Type == "PRIVATE KEY" {
    if _, err := x509.ParsePKCS8PrivateKey(block.Bytes); err != nil {
        return fmt.Errorf("PKCS#8 body unparseable; key corrupt or encrypted")
    }
}

Prevention

When it happens

Trigger: Corrupted or truncated PKCS#8 DER body; encrypted PKCS#8 (PBES2) keys whose DER begins with encryption parameters Go parses but rejects as an unparseable plain key; mismatched base64 padding introduced by hand edits.

Common situations: Downloading keys through tools that mangle base64 line lengths; using encrypted export formats from other clouds; byte-level truncation in CI secret variables.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/e78902e1f052c77b. Report an issue: GitHub.