Commit 8c75ed5d authored by Antoine Cellerier's avatar Antoine Cellerier

Check the server's reply upon successful authentication and validate it (just...

Check the server's reply upon successful authentication and validate it (just to make sure that no one is spoofing the server's reply). This will probably fail if qop=auth-int (code needs to be fixed).
parent daf0c78f
......@@ -209,6 +209,8 @@ static void AuthParseHeader( access_t *p_access, const char *psz_header,
http_auth_t *p_auth );
static void AuthReply( access_t *p_acces, const char *psz_prefix,
vlc_url_t *p_url, http_auth_t *p_auth );
static int AuthCheckReply( access_t *p_access, const char *psz_header,
vlc_url_t *p_url, http_auth_t *p_auth );
static void AuthReset( http_auth_t *p_auth );
/*****************************************************************************
......@@ -1360,8 +1362,15 @@ static int Request( access_t *p_access, int64_t i_tell )
}
else if( !strcasecmp( psz, "authentication-info" ) )
{
msg_Dbg( p_access, "Authentication info: %s", p );
/* FIXME: use */
msg_Dbg( p_access, "Authentication Info header: %s", p );
if( AuthCheckReply( p_access, p, &p_sys->url, &p_sys->auth ) )
goto error;
}
else if( !strcasecmp( psz, "proxy-authentication-info" ) )
{
msg_Dbg( p_access, "Proxy Authentication Info header: %s", p );
if( AuthCheckReply( p_access, p, &p_sys->proxy, &p_sys->proxy_auth ) )
goto error;
}
free( psz );
......@@ -1600,17 +1609,113 @@ static void AuthParseHeader( access_t *p_access, const char *psz_header,
psz_header );
}
}
static char *AuthAlgoMD5( const char *psz_data )
static char *AuthDigest( access_t *p_access, vlc_url_t *p_url,
http_auth_t *p_auth, const char *psz_method )
{
(void)p_access;
const char *psz_username = p_url->psz_username ?: "";
const char *psz_password = p_url->psz_password ?: "";
char *psz_HA1 = NULL;
char *psz_HA2 = NULL;
char *psz_response = NULL;
struct md5_s md5;
char *psz_md5;
/* H(A1) */
if( p_auth->psz_HA1 )
{
psz_HA1 = strdup( p_auth->psz_HA1 );
if( !psz_HA1 ) goto error;
}
else
{
InitMD5( &md5 );
AddMD5( &md5, psz_username, strlen( psz_username ) );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, p_auth->psz_realm, strlen( p_auth->psz_realm ) );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, psz_password, strlen( psz_password ) );
EndMD5( &md5 );
psz_HA1 = psz_md5_hash( &md5 );
if( !psz_HA1 ) goto error;
if( p_auth->psz_algorithm
&& !strcmp( p_auth->psz_algorithm, "MD5-sess" ) )
{
InitMD5( &md5 );
AddMD5( &md5, psz_HA1, 32 );
free( psz_HA1 );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, p_auth->psz_nonce, strlen( p_auth->psz_nonce ) );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, p_auth->psz_cnonce, strlen( p_auth->psz_cnonce ) );
EndMD5( &md5 );
psz_HA1 = psz_md5_hash( &md5 );
if( !psz_HA1 ) goto error;
p_auth->psz_HA1 = strdup( psz_HA1 );
if( !p_auth->psz_HA1 ) goto error;
}
}
/* H(A2) */
InitMD5( &md5 );
if( *psz_method )
AddMD5( &md5, psz_method, strlen( psz_method ) );
AddMD5( &md5, ":", 1 );
if( p_url->psz_path )
AddMD5( &md5, p_url->psz_path, strlen( p_url->psz_path ) );
else
AddMD5( &md5, "/", 1 );
if( p_auth->psz_qop && !strcmp( p_auth->psz_qop, "auth-int" ) )
{
char *psz_ent;
struct md5_s ent;
InitMD5( &ent );
AddMD5( &ent, "", 0 ); /* XXX: entity-body. should be ok for GET */
EndMD5( &ent );
psz_ent = psz_md5_hash( &ent );
if( !psz_ent ) goto error;
AddMD5( &md5, ":", 1 );
AddMD5( &md5, psz_ent, 32 );
free( psz_ent );
}
EndMD5( &md5 );
psz_HA2 = psz_md5_hash( &md5 );
if( !psz_HA2 ) goto error;
/* Request digest */
InitMD5( &md5 );
AddMD5( &md5, psz_data, strlen( psz_data ) );
AddMD5( &md5, psz_HA1, 32 );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, p_auth->psz_nonce, strlen( p_auth->psz_nonce ) );
AddMD5( &md5, ":", 1 );
if( p_auth->psz_qop
&& ( !strcmp( p_auth->psz_qop, "auth" )
|| !strcmp( p_auth->psz_qop, "auth-int" ) ) )
{
char psz_inonce[9];
snprintf( psz_inonce, 9, "%08x", p_auth->i_nonce );
AddMD5( &md5, psz_inonce, 8 );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, p_auth->psz_cnonce, strlen( p_auth->psz_cnonce ) );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, p_auth->psz_qop, strlen( p_auth->psz_qop ) );
AddMD5( &md5, ":", 1 );
}
AddMD5( &md5, psz_HA2, 32 );
EndMD5( &md5 );
psz_md5 = psz_md5_hash( &md5 );
return psz_md5;
psz_response = psz_md5_hash( &md5 );
error:
free( psz_HA1 );
free( psz_HA2 );
return psz_response;
}
static void AuthReply( access_t *p_access, const char *psz_prefix,
vlc_url_t *p_url, http_auth_t *p_auth )
{
......@@ -1623,10 +1728,7 @@ static void AuthReply( access_t *p_access, const char *psz_prefix,
if( p_auth->psz_nonce )
{
/* Digest Access Authentication */
char *psz_HA1 = NULL;
char *psz_HA2 = NULL;
char *psz_response = NULL;
struct md5_s md5;
char *psz_response;
if( p_auth->psz_algorithm
&& strcmp( p_auth->psz_algorithm, "MD5" )
......@@ -1646,92 +1748,8 @@ static void AuthReply( access_t *p_access, const char *psz_prefix,
}
p_auth->i_nonce ++;
/* H(A1) */
if( p_auth->psz_HA1 )
{
psz_HA1 = strdup( p_auth->psz_HA1 );
if( !psz_HA1 ) goto error;
}
else
{
InitMD5( &md5 );
AddMD5( &md5, psz_username, strlen( psz_username ) );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, p_auth->psz_realm, strlen( p_auth->psz_realm ) );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, psz_password, strlen( psz_password ) );
EndMD5( &md5 );
psz_HA1 = psz_md5_hash( &md5 );
if( !psz_HA1 ) goto error;
if( p_auth->psz_algorithm
&& !strcmp( p_auth->psz_algorithm, "MD5-sess" ) )
{
InitMD5( &md5 );
AddMD5( &md5, psz_HA1, 32 );
free( psz_HA1 );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, p_auth->psz_nonce, strlen( p_auth->psz_nonce ) );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, p_auth->psz_cnonce, strlen( p_auth->psz_cnonce ) );
EndMD5( &md5 );
psz_HA1 = psz_md5_hash( &md5 );
if( !psz_HA1 ) goto error;
p_auth->psz_HA1 = strdup( psz_HA1 );
if( !p_auth->psz_HA1 ) goto error;
}
}
/* H(A2) */
InitMD5( &md5 );
AddMD5( &md5, "GET", 3 ); /* FIXME ? */
AddMD5( &md5, ":", 1 );
if( p_url->psz_path )
AddMD5( &md5, p_url->psz_path, strlen( p_url->psz_path ) );
else
AddMD5( &md5, "/", 1 );
if( p_auth->psz_qop && !strcmp( p_auth->psz_qop, "auth-int" ) )
{
char *psz_ent;
struct md5_s ent;
InitMD5( &ent );
AddMD5( &ent, "", 0 ); /* XXX: entity-body. should be ok for GET */
EndMD5( &ent );
psz_ent = psz_md5_hash( &ent );
if( !psz_ent ) goto error;
AddMD5( &md5, ":", 1 );
AddMD5( &md5, psz_ent, 32 );
free( psz_ent );
}
EndMD5( &md5 );
psz_HA2 = psz_md5_hash( &md5 );
if( !psz_HA2 ) goto error;
/* Request digest */
InitMD5( &md5 );
AddMD5( &md5, psz_HA1, 32 );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, p_auth->psz_nonce, strlen( p_auth->psz_nonce ) );
AddMD5( &md5, ":", 1 );
if( p_auth->psz_qop
&& ( !strcmp( p_auth->psz_qop, "auth" )
|| !strcmp( p_auth->psz_qop, "auth-int" ) ) )
{
char psz_inonce[9];
snprintf( psz_inonce, 9, "%08x", p_auth->i_nonce );
AddMD5( &md5, psz_inonce, 8 );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, p_auth->psz_cnonce, strlen( p_auth->psz_cnonce ) );
AddMD5( &md5, ":", 1 );
AddMD5( &md5, p_auth->psz_qop, strlen( p_auth->psz_qop ) );
AddMD5( &md5, ":", 1 );
}
AddMD5( &md5, psz_HA2, 32 );
EndMD5( &md5 );
psz_response = psz_md5_hash( &md5 );
if( !psz_response ) goto error;
psz_response = AuthDigest( p_access, p_url, p_auth, "GET" );
if( !psz_response ) return;
net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs,
"%sAuthorization: Digest "
......@@ -1773,10 +1791,6 @@ static void AuthReply( access_t *p_access, const char *psz_prefix,
p_auth->i_nonce ? "\"" : "\""
);
error:
free( psz_HA1 );
free( psz_HA2 );
free( psz_response );
}
else
......@@ -1797,6 +1811,69 @@ static void AuthReply( access_t *p_access, const char *psz_prefix,
}
}
static int AuthCheckReply( access_t *p_access, const char *psz_header,
vlc_url_t *p_url, http_auth_t *p_auth )
{
int i_ret = VLC_EGENERIC;
char *psz_nextnonce = AuthGetParam( psz_header, "nextnonce" );
char *psz_qop = AuthGetParamNoQuotes( psz_header, "qop" );
char *psz_rspauth = AuthGetParam( psz_header, "rspauth" );
char *psz_cnonce = AuthGetParam( psz_header, "cnonce" );
char *psz_nc = AuthGetParamNoQuotes( psz_header, "nc" );
if( psz_cnonce )
{
char *psz_digest;
if( strcmp( psz_cnonce, p_auth->psz_cnonce ) )
{
msg_Err( p_access, "HTTP Digest Access Authentication: server replied with a different client nonce value." );
goto error;
}
if( psz_nc )
{
int i_nonce;
i_nonce = strtol( psz_nc, NULL, 16 );
if( i_nonce != p_auth->i_nonce )
{
msg_Err( p_access, "HTTP Digest Access Authentication: server replied with a different nonce count value." );
goto error;
}
}
if( psz_qop && p_auth->psz_qop && strcmp( psz_qop, p_auth->psz_qop ) )
msg_Warn( p_access, "HTTP Digest Access Authentication: server replied using a different 'quality of protection' option" );
/* All the clear text values match, let's now check the response
* digest */
psz_digest = AuthDigest( p_access, p_url, p_auth, "" );
if( strcmp( psz_digest, psz_rspauth ) )
{
msg_Err( p_access, "HTTP Digest Access Authentication: server replied with an invalid response digest (expected value: %s).", psz_digest );
free( psz_digest );
goto error;
}
free( psz_digest );
}
if( psz_nextnonce )
{
free( p_auth->psz_nonce );
p_auth->psz_nonce = psz_nextnonce;
psz_nextnonce = NULL;
}
i_ret = VLC_SUCCESS;
error:
free( psz_nextnonce );
free( psz_qop );
free( psz_rspauth );
free( psz_cnonce );
return i_ret;
}
static void AuthReset( http_auth_t *p_auth )
{
FREENULL( p_auth->psz_realm );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment