shadow1ng/fscan · error

unsupported public key type: %T

Error message

unsupported public key type: %T

What it means

When the certificate does carry a non-nil PublicKey, the library asserts it is an *rsa.PublicKey via a type assertion. Any other key type (ECDSA, Ed25519, etc.) fails the assertion and yields 'unsupported public key type: %T'. grdp only supports RSA server keys because the RDP standard security handshake uses RSA for the client random exchange.

Source

Thrown at libs/grdp/protocol/t125/gcc/gcc.go:434

	}
	if cert.PublicKey == nil {
		var pubKeyInfo struct {
			Algorithm        pkix.AlgorithmIdentifier
			SubjectPublicKey asn1.BitString
		}
		_, err = asn1.Unmarshal(cert.RawSubjectPublicKeyInfo, &pubKeyInfo)
		if err != nil {
			return nil, fmt.Errorf("unmarshal public key info: %w", err)
		}
		rsaPublicKey, err := x509.ParsePKCS1PublicKey(pubKeyInfo.SubjectPublicKey.Bytes)
		if err != nil {
			return nil, fmt.Errorf("parse PKCS1 public key: %w", err)
		}
		return rsaPublicKey, nil
	}
	rsaPublicKey, ok := cert.PublicKey.(*rsa.PublicKey)
	if !ok {
		return nil, fmt.Errorf("unsupported public key type: %T", cert.PublicKey)
	}
	return rsaPublicKey, nil
}
func (x *X509CertificateChain) Verify() bool {
	return true
}
func (x *X509CertificateChain) Encrypt() []byte {
	//todo
	return nil
}
func (x *X509CertificateChain) Unpack(r io.Reader) error {
	return struc.Unpack(r, x)
}

type ServerCoreData struct {
	RdpVersion              VERSION `struc:"uint32,little"`
	ClientRequestedProtocol uint32  `struc:"little"`
	EarlyCapabilityFlags    uint32  `struc:"little"`

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Issue an RSA-based certificate for the RDP host (2048-bit+ RSA) — RSA is the expected RDP server key type.
  2. Check cert.PublicKey's dynamic type via the %T text in the error to confirm which algorithm was found.
  3. Extend the library to support the key type if you control the codebase and the protocol allows it.
  4. Force the server to use standard RDP security/NLA with RSA keys.
Defensive patterns

Strategy: type-guard

Validate before calling

switch cert.PublicKey.(type) {
case *rsa.PublicKey:
	// ok
default:
	return errors.New("server certificate key must be RSA")
}

Type guard

func isRSAPublicKey(cert *x509.Certificate) bool {
	_, ok := cert.PublicKey.(*rsa.PublicKey)
	return ok
}

Try / catch

pub, err := certChain.PublicKey()
if err != nil && strings.Contains(err.Error(), "unsupported public key type") {
	return fmt.Errorf("host uses non-RSA server key; reissue RSA cert or skip host: %v", err)
}

Prevention

When it happens

Trigger: Connecting to an RDP host whose certificate uses an ECDSA/Ed25519 public key instead of RSA; the GCC cert chain parses fine but the key type is incompatible with grdp's key exchange.

Common situations: Modern/custom TLS configurations or non-Windows RDP implementations issuing ECC certificates; hardened environments that mandate ECC.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/b6d20f25ed891078. Report an issue: GitHub.