@@ -212,11 +212,12 @@ static int _handle_missing_features(xmpp_conn_t *conn, void *userdata)
212212 return 0 ;
213213}
214214
215- typedef void (* text_handler )(xmpp_conn_t * conn , const char * text );
215+ typedef void (* text_handler )(xmpp_conn_t * conn , const char * text , void * userdata );
216216static void _foreach_child (xmpp_conn_t * conn ,
217217 xmpp_stanza_t * parent ,
218218 const char * name ,
219- text_handler hndl )
219+ text_handler hndl ,
220+ void * userdata )
220221{
221222 xmpp_stanza_t * children ;
222223 for (children = xmpp_stanza_get_children (parent ); children ;
@@ -227,29 +228,32 @@ static void _foreach_child(xmpp_conn_t *conn,
227228 if (text == NULL )
228229 continue ;
229230
230- hndl (conn , text );
231+ hndl (conn , text , userdata );
231232
232233 strophe_free (conn -> ctx , text );
233234 }
234235 }
235236}
236237
237- static void _handle_sasl_children (xmpp_conn_t * conn , const char * text )
238+ static void _handle_sasl_children (xmpp_conn_t * conn , const char * text , void * userdata )
238239{
240+ int * support = userdata ;
239241 if (strcasecmp (text , "PLAIN" ) == 0 ) {
240- conn -> sasl_support |= SASL_MASK_PLAIN ;
242+ * support |= SASL_MASK_PLAIN ;
241243 } else if (strcasecmp (text , "EXTERNAL" ) == 0 &&
242244 (conn -> tls_client_cert || conn -> tls_client_key )) {
243- conn -> sasl_support |= SASL_MASK_EXTERNAL ;
245+ * support |= SASL_MASK_EXTERNAL ;
244246 } else if (strcasecmp (text , "DIGEST-MD5" ) == 0 ) {
245- conn -> sasl_support |= SASL_MASK_DIGESTMD5 ;
247+ * support |= SASL_MASK_DIGESTMD5 ;
246248 } else if (strcasecmp (text , "ANONYMOUS" ) == 0 ) {
247- conn -> sasl_support |= SASL_MASK_ANONYMOUS ;
249+ * support |= SASL_MASK_ANONYMOUS ;
250+ } else if (strcasecmp (text , "HT-SHA-256-EXPR" ) == 0 ) {
251+ * support |= SASL_MASK_HT_SHA_256_EXPR ;
248252 } else {
249253 size_t n ;
250254 for (n = 0 ; n < scram_algs_num ; ++ n ) {
251255 if (strcasecmp (text , scram_algs [n ]-> scram_name ) == 0 ) {
252- conn -> sasl_support |= scram_algs [n ]-> mask ;
256+ * support |= scram_algs [n ]-> mask ;
253257 break ;
254258 }
255259 }
@@ -284,13 +288,27 @@ _handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
284288
285289 if (child ) {
286290 conn -> sasl_support |= SASL_MASK_SASL2 ;
287- _foreach_child (conn , child , "mechanism" , _handle_sasl_children );
291+ _foreach_child (conn , child , "mechanism" , _handle_sasl_children ,
292+ & conn -> sasl_support );
293+
294+
295+ xmpp_stanza_t * inlin = xmpp_stanza_get_child_by_name_and_ns (child ,
296+ "inline" , XMPP_NS_SASL2 );
297+ if (inlin ) {
298+ xmpp_stanza_t * fast = xmpp_stanza_get_child_by_name_and_ns (inlin ,
299+ "fast" , XMPP_NS_FAST );
300+ if (fast ) {
301+ _foreach_child (conn , fast , "mechanism" , _handle_sasl_children ,
302+ & conn -> fast_support );
303+ }
304+ }
288305 } else {
289306 /* check for SASL */
290307 child = xmpp_stanza_get_child_by_name_and_ns (stanza , "mechanisms" ,
291308 XMPP_NS_SASL );
292309 if (child ) {
293- _foreach_child (conn , child , "mechanism" , _handle_sasl_children );
310+ _foreach_child (conn , child , "mechanism" , _handle_sasl_children ,
311+ & conn -> sasl_support );
294312 }
295313 }
296314
@@ -756,7 +774,7 @@ static xmpp_stanza_t *_make_starttls(xmpp_conn_t *conn)
756774 return starttls ;
757775}
758776
759- static xmpp_stanza_t * _make_sasl_auth (xmpp_conn_t * conn , const char * mechanism , const char * initial_data )
777+ static xmpp_stanza_t * _make_sasl_auth (xmpp_conn_t * conn , const char * mechanism , const char * initial_data , int fast_count )
760778{
761779 xmpp_stanza_t * auth , * init , * user_agent ;
762780 xmpp_stanza_t * inittxt = NULL ;
@@ -836,6 +854,31 @@ static xmpp_stanza_t *_make_sasl_auth(xmpp_conn_t *conn, const char *mechanism,
836854 }
837855 xmpp_stanza_add_child_ex (auth , user_agent , 0 );
838856 }
857+ if (fast_count >= 0 ) {
858+ char count_str [50 ];
859+ size_t result = snprintf (count_str , sizeof (count_str ), "%d" , fast_count );
860+ if (result > 0 && result < sizeof (count_str )) {
861+ xmpp_stanza_t * fast = xmpp_stanza_new (conn -> ctx );
862+ if (!fast ) {
863+ xmpp_stanza_release (auth );
864+ return NULL ;
865+ }
866+ xmpp_stanza_set_name (fast , "fast" );
867+ xmpp_stanza_set_ns (fast , XMPP_NS_FAST );
868+ xmpp_stanza_set_attribute (fast , "count" , count_str );
869+ xmpp_stanza_add_child_ex (auth , fast , 0 );
870+ }
871+ } else if (conn -> fast_support & SASL_MASK_HT_SHA_256_EXPR ) {
872+ xmpp_stanza_t * request_token = xmpp_stanza_new (conn -> ctx );
873+ if (!request_token ) {
874+ xmpp_stanza_release (auth );
875+ return NULL ;
876+ }
877+ xmpp_stanza_set_name (request_token , "request-token" );
878+ xmpp_stanza_set_ns (request_token , XMPP_NS_FAST );
879+ xmpp_stanza_set_attribute (request_token , "mechanism" , "HT-SHA-256-EXPR" );
880+ xmpp_stanza_add_child_ex (auth , request_token , 0 );
881+ }
839882 } else {
840883 xmpp_stanza_set_name (auth , "auth" );
841884 xmpp_stanza_set_ns (auth , XMPP_NS_SASL );
@@ -916,7 +959,7 @@ static void _auth(xmpp_conn_t *conn)
916959
917960 if (anonjid && (conn -> sasl_support & SASL_MASK_ANONYMOUS )) {
918961 /* some crap here */
919- auth = _make_sasl_auth (conn , "ANONYMOUS" , NULL );
962+ auth = _make_sasl_auth (conn , "ANONYMOUS" , NULL , -1 );
920963 if (!auth ) {
921964 disconnect_mem_error (conn );
922965 return ;
@@ -945,7 +988,7 @@ static void _auth(xmpp_conn_t *conn)
945988 }
946989 }
947990
948- auth = _make_sasl_auth (conn , "EXTERNAL" , str );
991+ auth = _make_sasl_auth (conn , "EXTERNAL" , str , -1 );
949992 strophe_free (conn -> ctx , str );
950993 if (!auth ) {
951994 disconnect_mem_error (conn );
@@ -963,6 +1006,69 @@ static void _auth(xmpp_conn_t *conn)
9631006 strophe_error (conn -> ctx , "auth" ,
9641007 "No node in JID, and SASL ANONYMOUS unsupported." );
9651008 xmpp_disconnect (conn );
1009+ } else if (conn -> fast_token && xmpp_conn_is_secured (conn ) && conn -> fast_support & SASL_MASK_HT_SHA_256_EXPR ) {
1010+ const char * binding_type ;
1011+ size_t binding_type_len ;
1012+ if (tls_init_channel_binding (conn -> tls , & binding_type ,
1013+ & binding_type_len )) {
1014+ return ;
1015+ }
1016+ if (strcmp (binding_type , "tls-exporter" )) {
1017+ strophe_error (
1018+ conn -> ctx , "auth" ,
1019+ "Can't use FAST without tls-exporter" );
1020+ return ;
1021+ }
1022+
1023+ uint8_t init [41 ];
1024+ size_t binding_data_len ;
1025+ const uint8_t * cbdata =
1026+ tls_get_channel_binding_data (conn -> tls , & binding_data_len );
1027+ if (binding_data_len > 32 ) {
1028+ strophe_error (
1029+ conn -> ctx , "auth" ,
1030+ "Channel binding data is too big" );
1031+ return ;
1032+ }
1033+ memcpy (init , "Initiator" , sizeof ("Initiator" )- 1 ); // No NUL terminator
1034+ memcpy (init + sizeof ("Initiator" )- 1 , cbdata , binding_data_len );
1035+
1036+ authid = _get_authid (conn );
1037+ if (!authid ) {
1038+ disconnect_mem_error (conn );
1039+ return ;
1040+ }
1041+
1042+ const uint8_t * token = (uint8_t * )conn -> fast_token ;
1043+ uint8_t * buf = strophe_alloc (conn -> ctx ,
1044+ strlen (authid ) + 1 + SHA256_DIGEST_SIZE );
1045+ memcpy (buf , authid , strlen (authid ) + 1 ); // Copy NUL terminator too
1046+ crypto_HMAC (& scram_sha256 ,
1047+ token ,
1048+ strlen (conn -> fast_token ),
1049+ init ,
1050+ sizeof ("Initiator" ) - 1 + binding_data_len ,
1051+ buf + strlen (authid ) + 1 );
1052+
1053+ str = xmpp_base64_encode (conn -> ctx ,
1054+ buf ,
1055+ strlen (authid ) + 1 + SHA256_DIGEST_SIZE );
1056+
1057+ auth = _make_sasl_auth (conn , "HT-SHA-256-EXPR" , str , conn -> fast_count );
1058+ strophe_free (conn -> ctx , str );
1059+ strophe_free (conn -> ctx , buf );
1060+ strophe_free (conn -> ctx , authid );
1061+ if (!auth ) {
1062+ disconnect_mem_error (conn );
1063+ return ;
1064+ }
1065+
1066+ handler_add (conn , _handle_ht_challenge , sasl_ns , NULL , NULL , NULL );
1067+
1068+ send_stanza (conn , auth , XMPP_QUEUE_STROPHE );
1069+
1070+ /* FAST was tried, unset flag */
1071+ conn -> fast_support &= ~SASL_MASK_HT_SHA_256_EXPR ;
9661072 } else if (conn -> pass == NULL ) {
9671073 strophe_error (
9681074 conn -> ctx , "auth" ,
@@ -998,7 +1104,7 @@ static void _auth(xmpp_conn_t *conn)
9981104 return ;
9991105 }
10001106
1001- auth = _make_sasl_auth (conn , scram_ctx -> alg -> scram_name , str );
1107+ auth = _make_sasl_auth (conn , scram_ctx -> alg -> scram_name , str , -1 );
10021108 strophe_free (conn -> ctx , str );
10031109 if (!auth ) {
10041110 disconnect_mem_error (conn );
@@ -1013,7 +1119,7 @@ static void _auth(xmpp_conn_t *conn)
10131119 /* SASL algorithm was tried, unset flag */
10141120 conn -> sasl_support &= ~scram_ctx -> alg -> mask ;
10151121 } else if (conn -> sasl_support & SASL_MASK_DIGESTMD5 ) {
1016- auth = _make_sasl_auth (conn , "DIGEST-MD5" , NULL );
1122+ auth = _make_sasl_auth (conn , "DIGEST-MD5" , NULL , -1 );
10171123 if (!auth ) {
10181124 disconnect_mem_error (conn );
10191125 return ;
@@ -1038,7 +1144,7 @@ static void _auth(xmpp_conn_t *conn)
10381144 return ;
10391145 }
10401146
1041- auth = _make_sasl_auth (conn , "PLAIN" , str );
1147+ auth = _make_sasl_auth (conn , "PLAIN" , str , -1 );
10421148 strophe_free (conn -> ctx , str );
10431149 strophe_free (conn -> ctx , authid );
10441150 if (!auth ) {
@@ -1226,7 +1332,7 @@ static int _handle_features_compress(xmpp_conn_t *conn,
12261332 XMPP_NS_FEATURE_COMPRESSION );
12271333 if (conn -> compression .allowed && child ) {
12281334 _foreach_child (conn , child , "method" ,
1229- compression_handle_feature_children );
1335+ compression_handle_feature_children , NULL );
12301336 }
12311337
12321338 if (conn -> compression .supported ) {
0 commit comments