@@ -194,6 +194,10 @@ static int test_ConfigDefaults(void)
194194 if (wolfSSHD_ConfigGetPwAuth (conf ) == 0 )
195195 ret = WS_FATAL_ERROR ;
196196 }
197+ if (ret == WS_SUCCESS ) {
198+ if (wolfSSHD_ConfigGetPubKeyAuth (conf ) == 0 )
199+ ret = WS_FATAL_ERROR ;
200+ }
197201
198202 wolfSSHD_ConfigFree (conf );
199203 return ret ;
@@ -242,6 +246,11 @@ static int test_ParseConfigLine(void)
242246 {"Password auth yes" , "PasswordAuthentication yes" , 0 },
243247 {"Password auth invalid" , "PasswordAuthentication wolfsshd" , 1 },
244248
249+ /* Public key auth tests. */
250+ {"Pubkey auth no" , "PubkeyAuthentication no" , 0 },
251+ {"Pubkey auth yes" , "PubkeyAuthentication yes" , 0 },
252+ {"Pubkey auth invalid" , "PubkeyAuthentication wolfsshd" , 1 },
253+
245254 /* Include files tests. */
246255 {"Include file bad" , "Include sshd_config.d/test.bad" , 1 },
247256 {"Include file exists" , "Include sshd_config.d/01-test.conf" , 0 },
@@ -312,6 +321,9 @@ static int test_ConfigCopy(void)
312321 if (ret == WS_SUCCESS ) ret = PCL ("Port 2222" );
313322 if (ret == WS_SUCCESS ) ret = PCL ("LoginGraceTime 30" );
314323 if (ret == WS_SUCCESS ) ret = PCL ("PasswordAuthentication yes" );
324+ /* set to the non-default value so a dropped copy (which would leave the
325+ * wolfSSHD_ConfigNew default of 1) is caught */
326+ if (ret == WS_SUCCESS ) ret = PCL ("PubkeyAuthentication no" );
315327 if (ret == WS_SUCCESS ) ret = PCL ("PermitEmptyPasswords yes" );
316328 if (ret == WS_SUCCESS ) ret = PCL ("PermitRootLogin yes" );
317329 if (ret == WS_SUCCESS ) ret = PCL ("UsePrivilegeSeparation sandbox" );
@@ -389,6 +401,12 @@ static int test_ConfigCopy(void)
389401 if (wolfSSHD_ConfigGetPwAuth (match ) == 0 )
390402 ret = WS_FATAL_ERROR ;
391403 }
404+ /* pubKeyAuth was set to the non-default 'no' (0) on the head, so the copy
405+ * must carry 0; a dropped copy would surface as the default 1 here */
406+ if (ret == WS_SUCCESS ) {
407+ if (wolfSSHD_ConfigGetPubKeyAuth (match ) != 0 )
408+ ret = WS_FATAL_ERROR ;
409+ }
392410 if (ret == WS_SUCCESS ) {
393411 if (wolfSSHD_ConfigGetPermitEmptyPw (match ) == 0 )
394412 ret = WS_FATAL_ERROR ;
@@ -448,14 +466,17 @@ static int test_GetUserConfMatchOverride(void)
448466 * global head node unchanged. */
449467 if (ret == WS_SUCCESS ) ret = PCL ("Match User testuser" );
450468 if (ret == WS_SUCCESS ) ret = PCL ("PasswordAuthentication no" );
469+ if (ret == WS_SUCCESS ) ret = PCL ("PubkeyAuthentication no" );
451470 if (ret == WS_SUCCESS ) ret = PCL ("PermitEmptyPasswords no" );
452471 if (ret == WS_SUCCESS ) ret = PCL ("PermitRootLogin no" );
453472 if (ret == WS_SUCCESS ) ret = PCL ("AuthorizedKeysFile .ssh/match_keys" );
454473#undef PCL
455474
456- /* the global head node must keep the permissive values */
475+ /* the global head node must keep the permissive values (pubKeyAuth keeps
476+ * its default of 1, proving the Match override did not leak to the head) */
457477 if (ret == WS_SUCCESS ) {
458478 if (wolfSSHD_ConfigGetPwAuth (head ) != 1 ||
479+ wolfSSHD_ConfigGetPubKeyAuth (head ) != 1 ||
459480 wolfSSHD_ConfigGetPermitEmptyPw (head ) != 1 ||
460481 wolfSSHD_ConfigGetPermitRoot (head ) != 1 )
461482 ret = WS_FATAL_ERROR ;
@@ -473,6 +494,7 @@ static int test_GetUserConfMatchOverride(void)
473494 * ones RequestAuthentication and DoCheckUser will now enforce */
474495 if (ret == WS_SUCCESS ) {
475496 if (wolfSSHD_ConfigGetPwAuth (match ) != 0 ||
497+ wolfSSHD_ConfigGetPubKeyAuth (match ) != 0 ||
476498 wolfSSHD_ConfigGetPermitEmptyPw (match ) != 0 ||
477499 wolfSSHD_ConfigGetPermitRoot (match ) != 0 )
478500 ret = WS_FATAL_ERROR ;
@@ -1005,6 +1027,73 @@ static int test_CAKeysFileDiffers(void)
10051027 return ret ;
10061028}
10071029
1030+ /* Exercises the auth-method advertisement logic used by DefaultUserAuthTypes:
1031+ * a method is only offered when its config option is enabled. Covers all four
1032+ * permutations of PasswordAuthentication and PubkeyAuthentication, including the
1033+ * security-relevant cases where pubkey is disabled and where both are disabled
1034+ * (no methods advertised, mask == 0). */
1035+ static int test_GetUserAuthTypes (void )
1036+ {
1037+ int ret = WS_SUCCESS ;
1038+ int i ;
1039+
1040+ static const struct {
1041+ const char * desc ;
1042+ int pwAuth ; /* 1 = leave enabled, 0 = PasswordAuthentication no */
1043+ int pubKeyAuth ; /* 1 = leave enabled, 0 = PubkeyAuthentication no */
1044+ int expected ;
1045+ } vectors [] = {
1046+ {"both enabled advertises both" , 1 , 1 ,
1047+ WOLFSSH_USERAUTH_PASSWORD | WOLFSSH_USERAUTH_PUBLICKEY },
1048+ {"pubkey disabled advertises password only" , 1 , 0 ,
1049+ WOLFSSH_USERAUTH_PASSWORD },
1050+ {"password disabled advertises pubkey only" , 0 , 1 ,
1051+ WOLFSSH_USERAUTH_PUBLICKEY },
1052+ {"both disabled advertises nothing" , 0 , 0 , 0 },
1053+ };
1054+ const int numVectors = (int )(sizeof (vectors ) / sizeof (* vectors ));
1055+ WOLFSSHD_CONFIG * conf ;
1056+
1057+ for (i = 0 ; i < numVectors && ret == WS_SUCCESS ; ++ i ) {
1058+ Log (" Testing scenario: %s." , vectors [i ].desc );
1059+
1060+ conf = wolfSSHD_ConfigNew (NULL );
1061+ if (conf == NULL ) {
1062+ Log (" FAILED.\n" );
1063+ ret = WS_MEMORY_E ;
1064+ break ;
1065+ }
1066+
1067+ /* both options default to enabled in wolfSSHD_ConfigNew, so only the
1068+ * disabled cases need an explicit directive */
1069+ if (vectors [i ].pwAuth == 0 ) {
1070+ ret = ParseConfigLine (& conf , "PasswordAuthentication no" ,
1071+ (int )WSTRLEN ("PasswordAuthentication no" ), 0 );
1072+ }
1073+ if (ret == WS_SUCCESS && vectors [i ].pubKeyAuth == 0 ) {
1074+ ret = ParseConfigLine (& conf , "PubkeyAuthentication no" ,
1075+ (int )WSTRLEN ("PubkeyAuthentication no" ), 0 );
1076+ }
1077+
1078+ if (ret == WS_SUCCESS ) {
1079+ if (wolfSSHD_GetUserAuthTypes (conf ) != vectors [i ].expected ) {
1080+ Log (" FAILED.\n" );
1081+ ret = WS_FATAL_ERROR ;
1082+ }
1083+ else {
1084+ Log (" PASSED.\n" );
1085+ }
1086+ }
1087+ else {
1088+ Log (" FAILED.\n" );
1089+ }
1090+
1091+ wolfSSHD_ConfigFree (conf );
1092+ }
1093+
1094+ return ret ;
1095+ }
1096+
10081097const TEST_CASE testCases [] = {
10091098 TEST_DECL (test_ConfigDefaults ),
10101099 TEST_DECL (test_ParseConfigLine ),
@@ -1013,6 +1102,7 @@ const TEST_CASE testCases[] = {
10131102 TEST_DECL (test_MatchUnsupportedSelector ),
10141103 TEST_DECL (test_CAKeysFileDiffers ),
10151104 TEST_DECL (test_IncludeRecursionBound ),
1105+ TEST_DECL (test_GetUserAuthTypes ),
10161106 TEST_DECL (test_ConfigFree ),
10171107#ifdef WOLFSSL_BASE64_ENCODE
10181108 TEST_DECL (test_CheckAuthKeysLine ),
0 commit comments