router-for-me/CLIProxyAPI · error

client key pem type %q is unsupported

Error message

client key pem type %q is unsupported

What it means

Returned by parseRSAPrivateKeyPEM in internal/home/certificate.go for a PEM block whose type is neither 'RSA PRIVATE KEY' (PKCS#1) nor 'PRIVATE KEY' (PKCS#8). The %q verb includes the actual block type, e.g. 'EC PRIVATE KEY' (SEC1) or 'ENCRYPTED PRIVATE KEY' (PKCS#8 encrypted).

Source

Thrown at internal/home/certificate.go:280

	block, _ := pem.Decode(raw)
	if block == nil {
		return nil, fmt.Errorf("client key pem is invalid")
	}
	switch block.Type {
	case "RSA PRIVATE KEY":
		return x509.ParsePKCS1PrivateKey(block.Bytes)
	case "PRIVATE KEY":
		key, errParse := x509.ParsePKCS8PrivateKey(block.Bytes)
		if errParse != nil {
			return nil, errParse
		}
		rsaKey, ok := key.(*rsa.PrivateKey)
		if !ok {
			return nil, fmt.Errorf("client key is not rsa")
		}
		return rsaKey, nil
	default:
		return nil, fmt.Errorf("client key pem type %q is unsupported", block.Type)
	}
}

func createClientCSR(certificateID string, key *rsa.PrivateKey) ([]byte, error) {
	certificateID = strings.TrimSpace(certificateID)
	if certificateID == "" {
		return nil, fmt.Errorf("certificate id is required")
	}
	template := &x509.CertificateRequest{
		Subject: pkix.Name{
			CommonName: certificateID,
		},
	}
	der, errCreate := x509.CreateCertificateRequest(rand.Reader, template, key)
	if errCreate != nil {
		return nil, errCreate
	}
	return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: der}), nil

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Read the quoted block type in the error: 'EC PRIVATE KEY' means wrong algorithm — regenerate with openssl genrsa; 'ENCRYPTED PRIVATE KEY' means decrypt first: openssl pkcs8 -topk8 -nocrypt -in encrypted.key -out key.pem; a CERTIFICATE type means the config points at the wrong file
  2. Regenerate the key as unencrypted RSA PEM and re-enroll

Example fix

# before (encrypted pkcs8)
home:
  client-key: /etc/cliproxy/encrypted.key

# after
openssl pkcs8 -topk8 -nocrypt -in /etc/cliproxy/encrypted.key -out /etc/cliproxy/client.key
home:
  client-key: /etc/cliproxy/client.key
Defensive patterns

Strategy: validation

Validate before calling

block, _ := pem.Decode(raw)
switch block.Type {
case "RSA PRIVATE KEY", "PRIVATE KEY": // ok
case "ENCRYPTED PRIVATE KEY":
    return errors.New("client key is passphrase-protected; decrypt with: openssl pkcs8 -topk8 -nocrypt")
case "EC PRIVATE KEY":
    return errors.New("client key is EC; regenerate with: openssl genrsa -out client.key 2048")
default:
    return fmt.Errorf("client key PEM type %q unusable", block.Type)
}

Prevention

When it happens

Trigger: Supplying an SEC1 EC key ('EC PRIVATE KEY'), an encrypted PKCS#8 key ('ENCRYPTED PRIVATE KEY'), or an unrelated PEM block (certificate, public key) as the client key.

Common situations: Key generated with openssl ec without converting to PKCS#8; passphrase-protected key exported from a browser or PKI tool; public key or certificate file mistakenly referenced by the client-key config field.

Related errors


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