@@ -1076,3 +1076,94 @@ func TestCompatibleAlgoAndSignatures(t *testing.T) {
10761076 }
10771077 }
10781078}
1079+
1080+ // configurablePublicKeyCallback is a public key callback that allows to
1081+ // configure the signature algorithm and format. This way we can emulate the
1082+ // behavior of buggy clients.
1083+ type configurablePublicKeyCallback struct {
1084+ signer AlgorithmSigner
1085+ signatureAlgo string
1086+ signatureFormat string
1087+ }
1088+
1089+ func (cb configurablePublicKeyCallback ) method () string {
1090+ return "publickey"
1091+ }
1092+
1093+ func (cb configurablePublicKeyCallback ) auth (session []byte , user string , c packetConn , rand io.Reader , extensions map [string ][]byte ) (authResult , []string , error ) {
1094+ pub := cb .signer .PublicKey ()
1095+
1096+ ok , err := validateKey (pub , cb .signatureAlgo , user , c )
1097+ if err != nil {
1098+ return authFailure , nil , err
1099+ }
1100+ if ! ok {
1101+ return authFailure , nil , fmt .Errorf ("invalid public key" )
1102+ }
1103+
1104+ pubKey := pub .Marshal ()
1105+ data := buildDataSignedForAuth (session , userAuthRequestMsg {
1106+ User : user ,
1107+ Service : serviceSSH ,
1108+ Method : cb .method (),
1109+ }, cb .signatureAlgo , pubKey )
1110+ sign , err := cb .signer .SignWithAlgorithm (rand , data , underlyingAlgo (cb .signatureFormat ))
1111+ if err != nil {
1112+ return authFailure , nil , err
1113+ }
1114+
1115+ s := Marshal (sign )
1116+ sig := make ([]byte , stringLength (len (s )))
1117+ marshalString (sig , s )
1118+ msg := publickeyAuthMsg {
1119+ User : user ,
1120+ Service : serviceSSH ,
1121+ Method : cb .method (),
1122+ HasSig : true ,
1123+ Algoname : cb .signatureAlgo ,
1124+ PubKey : pubKey ,
1125+ Sig : sig ,
1126+ }
1127+ p := Marshal (& msg )
1128+ if err := c .writePacket (p ); err != nil {
1129+ return authFailure , nil , err
1130+ }
1131+ var success authResult
1132+ success , methods , err := handleAuthResponse (c )
1133+ if err != nil {
1134+ return authFailure , nil , err
1135+ }
1136+ if success == authSuccess || ! containsMethod (methods , cb .method ()) {
1137+ return success , methods , err
1138+ }
1139+
1140+ return authFailure , methods , nil
1141+ }
1142+
1143+ func TestPublicKeyAndAlgoCompatibility (t * testing.T ) {
1144+ cert := & Certificate {
1145+ Key : testPublicKeys ["rsa" ],
1146+ ValidBefore : CertTimeInfinity ,
1147+ CertType : UserCert ,
1148+ }
1149+ cert .SignCert (rand .Reader , testSigners ["ecdsa" ])
1150+ certSigner , err := NewCertSigner (cert , testSigners ["rsa" ])
1151+ if err != nil {
1152+ t .Fatalf ("NewCertSigner: %v" , err )
1153+ }
1154+
1155+ clientConfig := & ClientConfig {
1156+ User : "user" ,
1157+ HostKeyCallback : InsecureIgnoreHostKey (),
1158+ Auth : []AuthMethod {
1159+ configurablePublicKeyCallback {
1160+ signer : certSigner .(AlgorithmSigner ),
1161+ signatureAlgo : KeyAlgoRSASHA256 ,
1162+ signatureFormat : KeyAlgoRSASHA256 ,
1163+ },
1164+ },
1165+ }
1166+ if err := tryAuth (t , clientConfig ); err == nil {
1167+ t .Error ("cert login passed with incompatible public key type and algorithm" )
1168+ }
1169+ }
0 commit comments