@@ -305,7 +305,8 @@ static int test_ConfigCopy(void)
305305 ret = wolfSSHD_ConfigSetHostCertFile (head , "/etc/ssh/host_cert.pub" );
306306 if (ret == WS_SUCCESS )
307307 ret = wolfSSHD_ConfigSetUserCAKeysFile (head , "/etc/ssh/ca.pub" );
308- /* AuthorizedKeysFile must go through PCL so authKeysFileSet flag is set */
308+ /* AuthorizedKeysFile via PCL to also exercise the config-parse path; the
309+ * authKeysFileSet flag is set either way and must survive the copy */
309310 if (ret == WS_SUCCESS ) ret = PCL ("AuthorizedKeysFile .ssh/authorized_keys" );
310311
311312 /* scalar fields */
@@ -651,6 +652,62 @@ static int test_IncludeRecursionBound(void)
651652 return ret ;
652653}
653654
655+ /* The public wolfSSHD_ConfigSetAuthKeysFile setter must mark the authorized
656+ * keys file as explicitly configured, otherwise certificate public-key logins
657+ * skip the authorized-keys check and rely on CA validation alone. */
658+ static int test_ConfigSetAuthKeysFile (void )
659+ {
660+ int ret = WS_SUCCESS ;
661+ WOLFSSHD_CONFIG * conf ;
662+
663+ conf = wolfSSHD_ConfigNew (NULL );
664+ if (conf == NULL )
665+ ret = WS_MEMORY_E ;
666+
667+ /* fresh config has no explicit authorized keys file */
668+ if (ret == WS_SUCCESS ) {
669+ if (wolfSSHD_ConfigGetAuthKeysFileSet (conf ) != 0 )
670+ ret = WS_FATAL_ERROR ;
671+ }
672+
673+ /* configuring a file through the public setter must set the flag */
674+ if (ret == WS_SUCCESS )
675+ ret = wolfSSHD_ConfigSetAuthKeysFile (conf , ".ssh/authorized_keys" );
676+ if (ret == WS_SUCCESS ) {
677+ if (wolfSSHD_ConfigGetAuthKeysFileSet (conf ) == 0 )
678+ ret = WS_FATAL_ERROR ;
679+ }
680+
681+ /* a failed update must leave the existing configuration intact: an
682+ * all-whitespace file makes CreateString fail, and both the previously
683+ * configured file and the flag must be untouched, not half cleared */
684+ if (ret == WS_SUCCESS ) {
685+ if (wolfSSHD_ConfigSetAuthKeysFile (conf , " " ) == WS_SUCCESS )
686+ ret = WS_FATAL_ERROR ; /* the bad value should have been rejected */
687+ }
688+ if (ret == WS_SUCCESS ) {
689+ if (wolfSSHD_ConfigGetAuthKeysFile (conf ) == NULL ||
690+ XSTRCMP (wolfSSHD_ConfigGetAuthKeysFile (conf ),
691+ ".ssh/authorized_keys" ) != 0 )
692+ ret = WS_FATAL_ERROR ;
693+ }
694+ if (ret == WS_SUCCESS ) {
695+ if (wolfSSHD_ConfigGetAuthKeysFileSet (conf ) == 0 )
696+ ret = WS_FATAL_ERROR ;
697+ }
698+
699+ /* removing the file must clear the flag again */
700+ if (ret == WS_SUCCESS )
701+ ret = wolfSSHD_ConfigSetAuthKeysFile (conf , NULL );
702+ if (ret == WS_SUCCESS ) {
703+ if (wolfSSHD_ConfigGetAuthKeysFileSet (conf ) != 0 )
704+ ret = WS_FATAL_ERROR ;
705+ }
706+
707+ wolfSSHD_ConfigFree (conf );
708+ return ret ;
709+ }
710+
654711/* Verifies ConfigFree releases all string fields - most useful under ASan. */
655712static int test_ConfigFree (void )
656713{
@@ -1013,6 +1070,7 @@ const TEST_CASE testCases[] = {
10131070 TEST_DECL (test_MatchUnsupportedSelector ),
10141071 TEST_DECL (test_CAKeysFileDiffers ),
10151072 TEST_DECL (test_IncludeRecursionBound ),
1073+ TEST_DECL (test_ConfigSetAuthKeysFile ),
10161074 TEST_DECL (test_ConfigFree ),
10171075#ifdef WOLFSSL_BASE64_ENCODE
10181076 TEST_DECL (test_CheckAuthKeysLine ),
0 commit comments