@@ -1076,3 +1076,94 @@ func TestCompatibleAlgoAndSignatures(t *testing.T) {
1076
1076
}
1077
1077
}
1078
1078
}
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