(* *************************************************************************
   *** OAuth 2.0 draft 22 verification				         ***
   *** 									 ***
   *** Marco De Nadai (86873) 	    	 				 ***
   *********************************************************************** *)

(* set traceBacktracking = false. *)
   
(* *************************************************************************
   * DEFINITIONS							   *
   *********************************************************************** *)
(* public channel *)
	free net:channel.
	free TLS_pass:channel [private].
	
(* Message numbers *)
	const c1, c3, c4, c5, c6:bitstring.

(* Messages *)
	const client_page_url:bitstring.
	const response_type:bitstring.
	const redirect_uri:bitstring.
	const resource_uri:bitstring.
	const grant_type:bitstring.
	const token_type:bitstring.
	const mac_algorithm:bitstring.

	type mac.
	type nonce.
	type Token.
	type RefreshToken.

	(* EXAMPLE: a registered client. Single for test *)
	free A_client_id:bitstring.
	free A_client_password:bitstring [private].

(* tables *)
	(* token-mac_keys list: simulate the communication between RS and AS  *)
	table mac_keys(Token, bitstring).
	(* Auth codes issued by AS: simulate the AS database *)
	table AuthCodes(bitstring, bitstring, bitstring).
	(* Refresh Token issued: simulate the AS database *)
	table RefreshTokens(bitstring, RefreshToken).

(* type converter *)
	fun Token_to_bitstring(Token):bitstring[data,typeConverter].
	fun RefreshToken_to_bitstring(RefreshToken):bitstring[data,typeConverter].


(* asymmetric encryption *)
	(* secret key *)
	type skey.
	(* public key *)
	type pkey.
	fun pk(skey): pkey.
	fun aenc(bitstring, pkey): bitstring.
	reduc forall m:bitstring, k: skey; adec(aenc(m, pk(k)), k) = m.

(* the cryptographic constructors *)
	(* enc for secrecy test *)
	fun senc(bitstring, bitstring):bitstring.
	reduc forall x:bitstring, y:bitstring; sdec(senc(x,y),y) = x.
	(* function for resource *)
	fun resourcecontent(bitstring):bitstring.
	(* mac for resource request *)
	fun hmac_sha_256(bitstring, bitstring): mac.
	(* encode channel *)
	fun enc(channel, bitstring): bitstring.
	reduc forall m:channel, k:bitstring; dec(enc(m,k),k) = m.

(* Resource function *)
	fun F(bitstring):bitstring.

(* events *)
	event auth_request(bitstring).
	event auth_accepted(bitstring).
	event token_request(bitstring, bitstring).
	event token_grant(bitstring, bitstring, Token, RefreshToken).
	event resource_request(Token, mac).
	event resource_accepted(Token, mac).
	event token_refresh(bitstring, RefreshToken).
	event token_refreshed(bitstring, RefreshToken).

	
(* *************************************************************************
   * QUERIES								   *
   *********************************************************************** *)

(* Secrecy queries *)
free secretMACKey, secretMACKey2, secretToken, secretTokenRefresh, secretTokenRefreshed: bitstring[private].

query	attacker(secretToken).

not attacker(TLS_pass).

(* *************************************************************************
   * USER AGENT: browser of the resource owner				   *
   *********************************************************************** *)
let UserAgent() =

	(* request client's page *)
		out(net, client_page_url);

	(* get client's page *)
		in(net, (authserver_pkey:pkey, client_id:bitstring, client_redirect_uri:bitstring));

	(* TLS: establish connection *)
		in(TLS_pass, TLSchannel1:channel);

	(* authorization request *)
		event auth_request(client_id);
		out(TLSchannel1, (response_type, client_id, client_redirect_uri, c1));
	
	(* authorization response *)
		in(net, code:bitstring);

	(* I pass the authorization code to the client *)
		out(net, code);

	(* I get the resource *)
		in(net, resource:bitstring);


	0.

	
(* *************************************************************************
   * CLIENT: for example a third part application			   			   *
   *********************************************************************** *)
let client(pkS:pkey, TLSchannel2:channel, TLSchannel3:channel) =

	(* get client's page request *)
		in(net, =client_page_url);

	(* authorization endpoint *)
		(* pkS is the AS server *)
		out(net, (pkS, A_client_id, redirect_uri));
	
	(* I get the authorization code from the UserAgent *)
		in(net, code:bitstring);

	(* token request *)
		event token_request(A_client_id, code);
		out(TLSchannel2, (grant_type, A_client_id, A_client_password, code, redirect_uri, c3));

	(* token response *)
		in(TLSchannel2, (token_code:Token, =token_type, mac_key:bitstring, =mac_algorithm, refresh_token:RefreshToken, =c4));
		
	(* resource request *)
		new N:nonce;
		(* I build the normalized string for HMAC generation *)
		let(normalized_string:bitstring) = (N, resource_uri) in
	
		let mac_string = hmac_sha_256(normalized_string, mac_key) in 
		event resource_request(token_code, mac_string);
		out(net, (resource_uri, token_code, N, mac_string));

	(* resource response *)
		in(net, resource:bitstring);

	(* send resource to the useragent *)
		out(net, F(resource));

	(* refreshToken request *)
		event token_refresh(A_client_id, refresh_token);
		out(TLSchannel3, (grant_type, A_client_id, A_client_password, refresh_token, c5));
	
	(* refreshToken response *)
		in(TLSchannel3, (token_code2:Token, =token_type, mac_key2:bitstring, =mac_algorithm, refresh_token2:RefreshToken, =c6));

	(* test secrecy *)
		out(net, senc(secretToken, Token_to_bitstring(token_code)));
		out(net, senc(secretTokenRefresh, RefreshToken_to_bitstring(refresh_token)));
		(* out(net, senc(secretTokenRefreshed, Token_to_bitstring(token_code2)));*)
		out(net, senc(secretMACKey, mac_key));
		out(net, senc(secretMACKey2, mac_key2));

		
	0.

	
(* *************************************************************************
   * AUTHORIZATION SERVER: grants authorization and token codes		   	   *
   *********************************************************************** *)
	
	
let authserver_AuthCode(skS:skey, pkS:pkey, AuthCode_secret:bitstring) =

	(* TLS: establish connection *)
		new TLSchannel1: channel;
		out(TLS_pass, TLSchannel1);
	
	(* authorization request *)
		in(TLSchannel1, (=response_type, client_id:bitstring, client_redirect_uri:bitstring, =c1));
		(* check authorized clients *)
		if client_id = A_client_id then
		event auth_accepted(client_id);

	(* authorization response *)
		new auth_code:bitstring;
		out(net, auth_code);	
		insert AuthCodes(auth_code, client_id, client_redirect_uri);
		
	0.


let authserver_TokenCode(TLSchannel2:channel, AuthCode_secret:bitstring) =

	(* token request *)
		in(TLSchannel2, (=grant_type, client_id:bitstring, client_password:bitstring, auth_code:bitstring, client_redirect_uri:bitstring, =c3));
		(* check authorized clients *)
		if client_id = A_client_id && client_password = A_client_password then
		get AuthCodes(=auth_code, =client_id, =client_redirect_uri) in
	
	(* token response *)
		new token_code:Token;
		new refreshToken_code:RefreshToken;
		new mac_key: bitstring;

		event token_grant(client_id, auth_code, token_code, refreshToken_code);
		out(TLSchannel2, (token_code, token_type, mac_key, mac_algorithm, refreshToken_code, c4));
	
		(* mac_key exchange between authserver and resourceserver *)
		insert mac_keys(token_code, mac_key);
		insert RefreshTokens(client_id, refreshToken_code);

	0.


let authserver_TokenCodeRefresh(TLSchannel3:channel) =

	(* refreshToken request *)
		in(TLSchannel3, (grant:bitstring, client_id:bitstring, client_password:bitstring, refreshToken_code_old:RefreshToken, =c5));
		(* check authorized clients *)
		if client_id = A_client_id && client_password = A_client_password then
		get RefreshTokens(=client_id, =refreshToken_code_old) in

	(* refreshToken response *)
		new token_code:Token;
		new mac_key: bitstring;

		event token_refreshed(client_id, refreshToken_code_old);
		out(TLSchannel3, (token_code, token_type, mac_key, mac_algorithm, refreshToken_code_old, c6));
	
		(* mac_key exchange between authserver and resourceserver *)
		insert mac_keys(token_code, mac_key);
		(*insert RefreshTokens(client_id, refreshToken_code);*)
	
	0.

let authserver(skS:skey, pkS:pkey, TLSchannel2:channel, TLSchannel3:channel) = 
	
	(* generate the Authorization Code secret *)
	new AuthCode_secret:bitstring;
	
	((authserver_AuthCode(skS, pkS, AuthCode_secret)) | (authserver_TokenCode(TLSchannel2, AuthCode_secret)) | (authserver_TokenCodeRefresh(TLSchannel3)))
	
	.

(* *************************************************************************
   * RESOURCE SERVER: a server that hosts a resource			   		   *
   *********************************************************************** *)
let resourceserver() =

	(* resource request *)
		in(net, (resource_url:bitstring, token_code:Token, N:nonce, mac_string:mac));
		(* I build the normalized string for HMAC generation *)
		let(normalized_string:bitstring) = (N, resource_url) in

		get mac_keys(=token_code, mac_key) in
		(* mac_key exchange between authserver and resourceserver *)

		(* check of mac code *)
		let (=mac_string) = hmac_sha_256(normalized_string, mac_key) in 
		event resource_accepted(token_code, mac_string);	
		out(net, resourcecontent(resource_url));
		
	0.


 process
	
	new TLSchannel2: channel;
	new TLSchannel3: channel;

	(* key pair for authserver *)
	new skS:skey;
	let pkS = pk(skS) in

	( (!UserAgent()) | (!authserver(skS, pkS, TLSchannel2, TLSchannel3)) | (!client(pkS, TLSchannel2, TLSchannel3)) | (!resourceserver()) )


