{"record":{"id":"3b635aaf9c2dea55","repo":"shadow1ng/fscan","slug":"failed-to-get-server-public-key","errorCode":null,"errorMessage":"failed to get server public key","messagePattern":"failed to get server public key","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"libs/grdp/protocol/sec/sec.go","lineNumber":696,"sourceCode":"\tif err != nil {\n\t\tglog.Error(\"generateKeys failed:\", err)\n\t\tc.Emit(\"error\", err)\n\t\treturn false\n\t}\n\n\t//initialize keys\n\tc.currentDecrytKey = c.initialDecrytKey\n\tc.currentEncryptKey = c.initialEncryptKey\n\n\t//verify certificate\n\tif !c.ServerSecurityData().ServerCertificate.CertData.Verify() {\n\t\tglog.Warn(\"Cannot verify server identity\")\n\t}\n\n\tserverPubKey, err := c.ServerSecurityData().ServerCertificate.CertData.GetPublicKey()\n\tif err != nil || serverPubKey == nil {\n\t\tglog.Error(\"GetPublicKey failed:\", err)\n\t\tc.Emit(\"error\", errors.New(\"failed to get server public key\"))\n\t\treturn false\n\t}\n\tret, err := rsa.EncryptPKCS1v15(rand.Reader, serverPubKey, core.Reverse(clientRandom))\n\tif err != nil {\n\t\tglog.Error(\"EncryptPKCS1v15 err:\", err)\n\t\tc.Emit(\"error\", err)\n\t\treturn false\n\t}\n\tmessage := ClientSecurityExchangePDU{}\n\tmessage.EncryptedClientRandom = core.Reverse(ret)\n\tmessage.Length = uint32(len(message.EncryptedClientRandom) + 8)\n\tmessage.Padding = make([]byte, 8)\n\n\tglog.Debug(\"message:\", message)\n\n\tc.sendFlagged(EXCHANGE_PKT, message.serialize())\n\treturn true\n}","sourceCodeStart":678,"sourceCodeEnd":714,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/libs/grdp/protocol/sec/sec.go#L678-L714","documentation":"During the RDP secure handshake in sec/sec.go, the client extracts the RSA public key from the server's X.509 certificate (ServerSecurityData.ServerCertificate.CertData.GetPublicKey). If extraction fails or returns nil, the client emits 'failed to get server public key' and aborts the connection, since it cannot encrypt the client random with PKCS1v15.","triggerScenarios":"Server's cert blob (PROPRIARYSERVERCERT / X.509 CertData) is malformed, uses an unsupported certificate type (e.g. proprietary format without a parseable key), contains a non-RSA key, or GetPublicKey returns (nil, nil) for an empty/truncated cert body — all reached during the ClientInfoPDU/security exchange after receiving the server security data.","commonSituations":"Connecting to a server with an unusual or self-signed cert chain the parser mishandles; NLA/TLS negotiation mismatch leaving the security header fields wrong; older servers sending a proprietary server certificate (dwVersion 0x00000001) that GetPublicKey can't parse; truncated cert data over flaky networks.","solutions":["Inspect the server certificate bytes: run GetPublicKey against the CertData manually and check the error to see whether it's a parse failure or a nil key.","Ensure the client negotiates standard TLS/SSL (PROTOCOL_SSL or HYBRID) so the server sends a full X.509 certificate rather than a proprietary one.","Verify the ServerSecurityData unpacked correctly — log CertData length and dwVersion; a short read upstream yields an empty cert.","If the cert uses an EC/non-RSA key, add key-type handling in GetPublicKey or connect with encryption negotiated to match (the EncryptPKCS1v15 path requires RSA).","Retry the connection once; intermittent truncation can produce empty CertData."],"exampleFix":"// before\nserverPubKey, err := c.ServerSecurityData().ServerCertificate.CertData.GetPublicKey()\nif err != nil || serverPubKey == nil {\n    glog.Error(\"GetPublicKey failed:\", err)\n    c.Emit(\"error\", errors.New(\"failed to get server public key\"))\n    return false\n}\n// after\nserverPubKey, err := c.ServerSecurityData().ServerCertificate.CertData.GetPublicKey()\nif err != nil {\n    glog.Error(\"GetPublicKey failed:\", err)\n    c.Emit(\"error\", fmt.Errorf(\"failed to get server public key: %w\", err))\n    return false\n}\nif serverPubKey == nil {\n    c.Emit(\"error\", errors.New(\"failed to get server public key: empty cert data\"))\n    return false\n}","handlingStrategy":"try-catch","validationCode":"// pre-connect sanity check on the certificate blob\ncert := c.ServerSecurityData().ServerCertificate.CertData\nif cert == nil || len(cert) == 0 {\n    return errors.New(\"server returned empty certificate data; check security protocol negotiation\")\n}","typeGuard":"func hasServerPubKey(c *grdpClient) bool {\n    key, err := c.ServerSecurityData().ServerCertificate.CertData.GetPublicKey()\n    return err == nil && key != nil\n}","tryCatchPattern":"client.On(\"error\", func(err error) {\n    if strings.Contains(err.Error(), \"failed to get server public key\") {\n        glog.Error(\"server cert unusable; check TLS/NLA negotiation and cert format: \", err)\n        return\n    }\n    glog.Error(\"rdp error: \", err)\n})","preventionTips":["Negotiate standard SSL/HYBRID security protocol so the server presents a parseable X.509 cert","Verify server cert compatibility before deploying (test with openssl s_client or mstsc)","Handle RSA-only assumption: reject non-RSA server keys up front","Retry on intermittent connections that may truncate the security exchange"],"tags":["rdp","tls","certificate","public-key","handshake"],"backgroundTag":"authentication-required","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}