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}), nilView on GitHub (pinned to 78f0c4079e)
Solutions
- 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
- 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
- Normalize all client keys to unencrypted PKCS#8 RSA PEM at provisioning time
- Keep certificates, keys, and CSRs in clearly named files (client.key, client.pem, ca.pem)
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
- client key pem is invalid
- home ca certificate pem is invalid
- client key is not rsa
- home tls: load client certificate: %w
- home tls: ca-cert contains no PEM certificates
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/e21c05766a6141f9.
Report an issue: GitHub.