{"record":{"id":"9cef00badf98c177","repo":"XTLS/Xray-core","slug":"parse-server-public-key-not-rsa","errorCode":null,"errorMessage":"parse server public key: not rsa","messagePattern":"parse server public key: not rsa","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"transport/internet/finalmask/xmc/client.go","lineNumber":152,"sourceCode":"\t)\n\n\terr = pkt.readFields(&serverId, &publicKey, &verifyToken)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read encryption request fields: %w\", err)\n\t}\n\n\tif !bytes.Equal(publicKey, c.rsaPublicKey) {\n\t\treturn fmt.Errorf(\"server public key mismatch\")\n\t}\n\n\tk, err := x509.ParsePKIXPublicKey(publicKey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parse server public key: %w\", err)\n\t}\n\n\trsaPublicKey, ok := k.(*rsa.PublicKey)\n\tif !ok {\n\t\treturn fmt.Errorf(\"parse server public key: not rsa\")\n\t}\n\n\tsharedSecret := make([]byte, 16)\n\tif _, err = rand.Read(sharedSecret); err != nil {\n\t\treturn fmt.Errorf(\"generate shared secret: %w\", err)\n\t}\n\n\tencryptedSharedSecret, err := rsa.EncryptPKCS1v15(rand.Reader, rsaPublicKey, sharedSecret)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"encrypt shared secret: %w\", err)\n\t}\n\n\tverifyToken = append(verifyToken, []byte(c.password)...) // append pre-shared password\n\n\tencryptedVerifyToken, err := rsa.EncryptPKCS1v15(rand.Reader, rsaPublicKey, verifyToken)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"encrypt verify token: %w\", err)\n\t}","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/finalmask/xmc/client.go#L134-L170","documentation":"x509.ParsePKIXPublicKey succeeded but returned a key that is not *rsa.PublicKey (for example an ECDSA or Ed25519 key). The xmc protocol requires RSA because the client encrypts the 16-byte shared secret and the password-suffixed verify token with rsa.EncryptPKCS1v15. Any non-RSA key cannot be used for this handshake.","triggerScenarios":"Config.WrapConnClient connects to a server whose advertised rsa_public_key decodes to an ECDSA/Ed25519 PublicKey. The x509 parse succeeds, then the type assertion k.(*rsa.PublicKey) fails.","commonSituations":"An operator generated a modern Ed25519 or P-256 key with openssl and put it where the protocol requires RSA; or a key-generation script defaulted to ECDSA. Note that a PKCS#1 RSA key would instead fail at the ParsePKIX step (error 860), not here.","solutions":["Generate an RSA key (>= 2048 bits, e.g. crypto/rsa.GenerateKey(rand.Reader, 2048)) and export with x509.MarshalPKIXPublicKey","Replace the mis-typed key in Config.RsaPublicKey on the client and in the server's key config","Add a startup self-check: parse the configured key and assert the *rsa.PublicKey type before dialing"],"exampleFix":"// before\npriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)\nder, _ := x509.MarshalPKIXPublicKey(&priv.PublicKey)\ncfg.RsaPublicKey = der\n\n// after\npriv, _ := rsa.GenerateKey(rand.Reader, 2048)\nder, _ := x509.MarshalPKIXPublicKey(&priv.PublicKey)\ncfg.RsaPublicKey = der","handlingStrategy":"type-guard","validationCode":"k, err := x509.ParsePKIXPublicKey(cfg.RsaPublicKey)\nif err != nil {\n    return fmt.Errorf(\"config key unparsable: %w\", err)\n}\nif _, ok := k.(*rsa.PublicKey); !ok {\n    return fmt.Errorf(\"config key must be RSA, got %T\", k)\n}","typeGuard":"func isRSAKey(b []byte) bool {\n    k, err := x509.ParsePKIXPublicKey(b)\n    if err != nil {\n        return false\n    }\n    _, ok := k.(*rsa.PublicKey)\n    return ok\n}","tryCatchPattern":null,"preventionTips":["Generate keys with crypto/rsa.GenerateKey, not ecdsa/ed25519","Assert key type in a config validation step at process start","Document in the config template that only RSA (PKIX DER) is accepted"],"tags":["crypto","rsa","key-type","config","go"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}