@@ -83,7 +83,8 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
8383static int _handle_scram_challenge (xmpp_conn_t * conn ,
8484 xmpp_stanza_t * stanza ,
8585 void * userdata );
86- static char * _make_scram_init_msg (xmpp_conn_t * conn );
86+ struct scram_user_data ;
87+ static int _make_scram_init_msg (struct scram_user_data * scram );
8788
8889static int _handle_missing_features_sasl (xmpp_conn_t * conn , void * userdata );
8990static int _handle_missing_bind (xmpp_conn_t * conn , void * userdata );
@@ -250,8 +251,12 @@ _handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
250251 conn -> sasl_support |= SASL_MASK_EXTERNAL ;
251252 else if (strcasecmp (text , "DIGEST-MD5" ) == 0 )
252253 conn -> sasl_support |= SASL_MASK_DIGESTMD5 ;
254+ else if (strcasecmp (text , "SCRAM-SHA-1-PLUS" ) == 0 )
255+ conn -> sasl_support |= SASL_MASK_SCRAMSHA1_PLUS ;
253256 else if (strcasecmp (text , "SCRAM-SHA-1" ) == 0 )
254257 conn -> sasl_support |= SASL_MASK_SCRAMSHA1 ;
258+ else if (strcasecmp (text , "SCRAM-SHA-256-PLUS" ) == 0 )
259+ conn -> sasl_support |= SASL_MASK_SCRAMSHA256_PLUS ;
255260 else if (strcasecmp (text , "SCRAM-SHA-256" ) == 0 )
256261 conn -> sasl_support |= SASL_MASK_SCRAMSHA256 ;
257262 else if (strcasecmp (text , "SCRAM-SHA-512" ) == 0 )
@@ -439,7 +444,11 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
439444}
440445
441446struct scram_user_data {
447+ xmpp_conn_t * conn ;
448+ int sasl_plus ;
442449 char * scram_init ;
450+ char * channel_binding ;
451+ const char * first_bare ;
443452 const struct hash_alg * alg ;
444453};
445454
@@ -471,8 +480,9 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
471480 if (!challenge )
472481 goto err ;
473482
474- response = sasl_scram (conn -> ctx , scram_ctx -> alg , challenge ,
475- scram_ctx -> scram_init , conn -> jid , conn -> pass );
483+ response =
484+ sasl_scram (conn -> ctx , scram_ctx -> alg , scram_ctx -> channel_binding ,
485+ challenge , scram_ctx -> first_bare , conn -> jid , conn -> pass );
476486 strophe_free (conn -> ctx , challenge );
477487 if (!response )
478488 goto err ;
@@ -506,7 +516,8 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
506516 */
507517 rc = _handle_sasl_result (conn , stanza ,
508518 (void * )scram_ctx -> alg -> scram_name );
509- strophe_free (conn -> ctx , scram_ctx -> scram_init );
519+ strophe_free_and_null (conn -> ctx , scram_ctx -> channel_binding );
520+ strophe_free_and_null (conn -> ctx , scram_ctx -> scram_init );
510521 strophe_free (conn -> ctx , scram_ctx );
511522 }
512523
@@ -517,33 +528,86 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
517528err_free_response :
518529 strophe_free (conn -> ctx , response );
519530err :
520- strophe_free (conn -> ctx , scram_ctx -> scram_init );
531+ strophe_free_and_null (conn -> ctx , scram_ctx -> channel_binding );
532+ strophe_free_and_null (conn -> ctx , scram_ctx -> scram_init );
521533 strophe_free (conn -> ctx , scram_ctx );
522534 disconnect_mem_error (conn );
523535 return 0 ;
524536}
525537
526- static char * _make_scram_init_msg (xmpp_conn_t * conn )
538+ static int _make_scram_init_msg (struct scram_user_data * scram )
527539{
540+ xmpp_conn_t * conn = scram -> conn ;
528541 xmpp_ctx_t * ctx = conn -> ctx ;
529- size_t message_len ;
530- char * node ;
531- char * message ;
532- char nonce [32 ];
542+ void * binding_data ;
543+ char * node , * message , * binding_type ;
544+ size_t message_len , binding_type_len = 0 , binding_data_len ;
545+ int l , is_secured = xmpp_conn_is_secured (conn );
546+ char buf [64 ];
547+
548+ if (scram -> sasl_plus ) {
549+ if (!is_secured ) {
550+ strophe_error (
551+ conn -> ctx , "xmpp" ,
552+ "SASL: Server requested a -PLUS variant to authenticate, "
553+ "but the connection is not secured. This is an error on "
554+ "the server side we can't do anything about." );
555+ return -1 ;
556+ }
557+ if (tls_init_channel_binding (conn -> tls , & binding_type ,
558+ & binding_type_len )) {
559+ return -1 ;
560+ }
561+ /* directly account for the '=' char in 'p=<binding-type>' */
562+ binding_type_len += 1 ;
563+ }
533564
534565 node = xmpp_jid_node (ctx , conn -> jid );
535566 if (!node ) {
536- return NULL ;
567+ return -1 ;
537568 }
538- xmpp_rand_nonce (ctx -> rand , nonce , sizeof (nonce ));
539- message_len = strlen (node ) + strlen (nonce ) + 8 + 1 ;
569+ xmpp_rand_nonce (ctx -> rand , buf , sizeof (buf ));
570+ message_len = strlen (node ) + strlen (buf ) + 8 + binding_type_len + 1 ;
540571 message = strophe_alloc (ctx , message_len );
541572 if (message ) {
542- strophe_snprintf (message , message_len , "n,,n=%s,r=%s" , node , nonce );
573+ binding_type_len += 3 ;
574+ if (scram -> sasl_plus ) {
575+ l = strophe_snprintf (message , message_len , "p=%s,,n=%s,r=%s" ,
576+ binding_type , node , buf );
577+ } else {
578+ l = strophe_snprintf (message , message_len , "%c,,n=%s,r=%s" ,
579+ is_secured ? 'y' : 'n' , node , buf );
580+ }
581+ if (l < 0 || (size_t )l >= message_len ) {
582+ goto err_out ;
583+ } else {
584+ scram -> first_bare = message + binding_type_len ;
585+ memcpy (buf , message , binding_type_len );
586+ if (scram -> sasl_plus ) {
587+ binding_data =
588+ tls_get_channel_binding_data (conn -> tls , & binding_data_len );
589+ if (!binding_data ) {
590+ goto err_out ;
591+ }
592+ memcpy (& buf [binding_type_len ], binding_data , binding_data_len );
593+ binding_type_len += binding_data_len ;
594+ }
595+ if (scram -> channel_binding )
596+ strophe_free (ctx , scram -> channel_binding );
597+ scram -> channel_binding =
598+ xmpp_base64_encode (ctx , (void * )buf , binding_type_len );
599+ memset (buf , 0 , binding_type_len );
600+ }
543601 }
544602 strophe_free (ctx , node );
603+ scram -> scram_init = message ;
545604
546- return message ;
605+ return message == NULL ? -1 : 0 ;
606+ err_out :
607+ strophe_free (ctx , node );
608+ strophe_free (ctx , message );
609+ scram -> scram_init = NULL ;
610+ return -1 ;
547611}
548612
549613static xmpp_stanza_t * _make_starttls (xmpp_conn_t * conn )
@@ -636,7 +700,7 @@ static void _auth(xmpp_conn_t *conn)
636700 return ;
637701 }
638702
639- if (anonjid && conn -> sasl_support & SASL_MASK_ANONYMOUS ) {
703+ if (anonjid && ( conn -> sasl_support & SASL_MASK_ANONYMOUS ) ) {
640704 /* some crap here */
641705 auth = _make_sasl_auth (conn , "ANONYMOUS" );
642706 if (!auth ) {
@@ -703,21 +767,29 @@ static void _auth(xmpp_conn_t *conn)
703767 xmpp_disconnect (conn );
704768 } else if (conn -> sasl_support & SASL_MASK_SCRAM ) {
705769 scram_ctx = strophe_alloc (conn -> ctx , sizeof (* scram_ctx ));
706- if (conn -> sasl_support & SASL_MASK_SCRAMSHA512 )
770+ memset (scram_ctx , 0 , sizeof (* scram_ctx ));
771+ if (conn -> sasl_support & SASL_MASK_SCRAMSHA256_PLUS ) {
772+ scram_ctx -> alg = & scram_sha256_plus ;
773+ } else if (conn -> sasl_support & SASL_MASK_SCRAMSHA1_PLUS ) {
774+ scram_ctx -> alg = & scram_sha1_plus ;
775+ } else if (conn -> sasl_support & SASL_MASK_SCRAMSHA512 ) {
707776 scram_ctx -> alg = & scram_sha512 ;
708- else if (conn -> sasl_support & SASL_MASK_SCRAMSHA256 )
777+ } else if (conn -> sasl_support & SASL_MASK_SCRAMSHA256 ) {
709778 scram_ctx -> alg = & scram_sha256 ;
710- else if (conn -> sasl_support & SASL_MASK_SCRAMSHA1 )
779+ } else if (conn -> sasl_support & SASL_MASK_SCRAMSHA1 ) {
711780 scram_ctx -> alg = & scram_sha1 ;
781+ }
782+
712783 auth = _make_sasl_auth (conn , scram_ctx -> alg -> scram_name );
713784 if (!auth ) {
714785 disconnect_mem_error (conn );
715786 return ;
716787 }
717788
718- /* don't free scram_init on success */
719- scram_ctx -> scram_init = _make_scram_init_msg (conn );
720- if (!scram_ctx -> scram_init ) {
789+ scram_ctx -> conn = conn ;
790+ scram_ctx -> sasl_plus =
791+ scram_ctx -> alg -> mask & SASL_MASK_SCRAM_PLUS ? 1 : 0 ;
792+ if (_make_scram_init_msg (scram_ctx )) {
721793 strophe_free (conn -> ctx , scram_ctx );
722794 xmpp_stanza_release (auth );
723795 disconnect_mem_error (conn );
@@ -753,7 +825,7 @@ static void _auth(xmpp_conn_t *conn)
753825
754826 send_stanza (conn , auth , XMPP_QUEUE_STROPHE );
755827
756- /* SASL SCRAM-SHA-1 was tried, unset flag */
828+ /* SASL algorithm was tried, unset flag */
757829 conn -> sasl_support &= ~scram_ctx -> alg -> mask ;
758830 } else if (conn -> sasl_support & SASL_MASK_DIGESTMD5 ) {
759831 auth = _make_sasl_auth (conn , "DIGEST-MD5" );
0 commit comments