{"record":{"id":"20d5dce2fbc9c46f","repo":"XTLS/Xray-core","slug":"parse-server-public-key-w","errorCode":null,"errorMessage":"parse server public key: %w","messagePattern":"parse server public key: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"transport/internet/finalmask/xmc/client.go","lineNumber":147,"sourceCode":"\n\tvar (\n\t\tserverId    String\n\t\tpublicKey   Bytes\n\t\tverifyToken Bytes\n\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","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/finalmask/xmc/client.go#L129-L165","documentation":"The client received the server's Encryption Request packet and the raw public key bytes matched the configured key, but Go's x509.ParsePKIXPublicKey failed to decode those bytes as a DER-encoded SubjectPublicKeyInfo. This means the configured RsaPublicKey passed the byte-equality check yet is not a valid PKIX/DER structure. In practice this only happens when both sides share the same malformed key material.","triggerScenarios":"Calling Config.WrapConnClient (or the first Read/Write on the wrapped conn) against an xmc server whose rsa_public_key config bytes are not DER PKIX output (e.g. PEM text, base64, raw modulus, or truncated DER). Because the client first checks bytes.Equal(publicKey, c.rsaPublicKey), the server must be echoing back the exact same malformed bytes.","commonSituations":"The key was copied from a PEM file including the '-----BEGIN-----' headers, pasted as base64 instead of raw DER, generated with a different encoding (PKCS#1 instead of PKIX), or truncated by a protobuf/JSON config pipeline that treats it as a string.","solutions":["Regenerate the key and export it as DER PKIX: x509.MarshalPKIXPublicKey(&priv.PublicKey) — this is the exact format ParsePKIXPublicKey expects","If the key is stored as PEM, strip headers and base64-decode before putting it in Config.RsaPublicKey","Verify with a quick Go check: x509.ParsePKIXPublicKey(cfg.RsaPublicKey) must succeed before starting the tunnel","Ensure both client (RsaPublicKey) and server (RsaPublicKey/RsaPrivateKey) configs use the same DER bytes"],"exampleFix":"// before (PEM text in config)\ncfg.RsaPublicKey = []byte(`-----BEGIN PUBLIC KEY-----\\nMIIB...\\n-----END PUBLIC KEY-----`)\n\n// after (raw DER PKIX bytes)\nblock, _ := pem.Decode(pemBytes)\nderBytes := block.Bytes // already DER PKIX for a PUBLIC KEY block\ncfg.RsaPublicKey = derBytes","handlingStrategy":"validation","validationCode":"der, err := base64.StdEncoding.DecodeString(strings.TrimSpace(cfgB64))\nif err != nil {\n    return fmt.Errorf(\"rsa key is not valid base64: %w\", err)\n}\nif _, err := x509.ParsePKIXPublicKey(der); err != nil {\n    return fmt.Errorf(\"rsa_public_key is not DER PKIX: %w\", err)\n}","typeGuard":"func isValidPKIXRSAKey(b []byte) bool {\n    if len(b) == 0 {\n        return false\n    }\n    k, err := x509.ParsePKIXPublicKey(b)\n    return err == nil && k.(*rsa.PublicKey) != nil\n}","tryCatchPattern":"if _, err := conn.Read(buf); err != nil && strings.Contains(err.Error(), \"parse server public key\") {\n    log.Fatalf(\"bad RsaPublicKey config (not DER PKIX): %v\", err)\n}","preventionTips":["Store keys as raw DER bytes in config, never PEM text","Add a unit test that parses the configured key with x509.ParsePKIXPublicKey at config-load time","Use x509.MarshalPKIXPublicKey to produce keys so the format is correct by construction"],"tags":["crypto","x509","rsa","config","go"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}