2424import java .util .Arrays ;
2525import java .util .Collection ;
2626import java .util .Objects ;
27+ import java .util .regex .Matcher ;
28+ import java .util .regex .Pattern ;
2729
2830import org .apache .sshd .client .session .AbstractClientSession ;
2931import org .apache .sshd .common .NamedFactory ;
@@ -291,7 +293,7 @@ protected void verifyCertificate(Session session, OpenSshCertificate openSshKey)
291293
292294 if (connectSocketAddress instanceof InetSocketAddress ) {
293295 String hostName = ((InetSocketAddress ) connectSocketAddress ).getHostString ();
294- if (GenericUtils . isEmpty (principals ) || (! principals . contains ( hostName ) )) {
296+ if (! hostMatches (principals , hostName )) {
295297 throw new SshException (SshConstants .SSH2_DISCONNECT_KEY_EXCHANGE_FAILED ,
296298 "KeyExchange signature verification failed, invalid principal " + hostName + " for key ID=" + keyId
297299 + " - allowed=" + principals );
@@ -314,4 +316,18 @@ protected void verifyCertificate(Session session, OpenSshCertificate openSshKey)
314316 + keyId );
315317 }
316318 }
319+
320+ private Pattern wildcardToRegex (String wildcardPattern ) {
321+ String re = "^\\ Q" + wildcardPattern + "\\ E$" ;
322+ re = re .replace ("?" , "\\ E.\\ Q" ).replaceAll ("\\ *+" , Matcher .quoteReplacement ("\\ E.*?\\ Q" )).replace ("\\ Q\\ E" , "" );
323+ return Pattern .compile (re );
324+ }
325+
326+ private boolean hostMatches (Collection <String > principals , String hostName ) {
327+ return principals .stream () //
328+ .filter (s -> s != null && !s .isEmpty ()) //
329+ .anyMatch (principal -> (principal .contains ("?" ) || principal .contains ("*" ))
330+ ? wildcardToRegex (principal ).matcher (hostName ).matches ()
331+ : principal .equals (hostName ));
332+ }
317333}
0 commit comments