握手协议的保密性和认证性
event acceptsClient(key)
:客户端接受了【使用收到的key和服务器交互】这件事。
event acceptsServer(key,pkey)
:服务器接受了【使用key和公钥为pkey的客户端交互】这件事。
event termClient(key,pkey)
:客户端认为已经完成了【使用key为会话密钥以及pkey作为客户端公钥,和服务器运行协议】这件事。
event termServer(key)
:服务器认为已经完成了【使用key作为会话密钥,和客户端运行协议】这件事。
对客户端A而言,她只想和服务器B分享自己的加密信息,所以如果他执行完协议,B对A的认证就应该保持。
对服务器B而言,他可以和很多客户端交互,所以在运行完协议之后,如果B认为A是他的对话者(pkX==pkA
),那么A对B的认证就应该保持。
关于 Correspondence assertions
query event ( evCocks ) ==> event (evRSA )
is true if and only if, for all executions of the protocol, if the event evCocks
has been executed, then the event evRSA
has also been executed before.
关于 Injective correspondence
我们刚才讨论的通信定义不足以在需要每个参与者执行的协议运行数之间的一对一
关系的情况下捕获身份验证。例如,考虑服务器请求来自客户端的支付的金融交易;对于客户端启动的每个事务,服务器应该只完成一次事务(如果不是这样的话,那么客户机可能要为多个事务收费,即使客户机只启动了一个事务。)对于访问控制和其他场景,情况类似。单射对应断言捕获一对一关系并表示为:
握手协议的保密性和认证性(例子)
(*握手协议的保密性和认证性*)
free c:channel.
type key.
fun senc(bitstring,key):bitstring.
reduc forall m:bitstring,k:key;sdec(senc(m,k),k)=m.
(*对称加密、解密*)
type skey.
type pkey.
fun pk(skey):pkey.
fun aenc(bitstring,pkey):bitstring.
reduc forall m:bitstring,k:skey;adec(aenc(m,pk(k)),k)=m.
(*非对称加密、解密*)
type sskey.
type spkey.
fun spk(sskey):spkey.
fun sign(bitstring,sskey):bitstring.
reduc forall m:bitstring,k:sskey;getmess(sign(m,k))=m.
reduc forall m:bitstring,k:sskey;checksign(sign(m,k),spk(k))=m.
(*签名、检查签名*)
free s:bitstring [private].
query attacker(s).
event acceptsClient(key).
event acceptsServer(key,pkey).
event termClient(key,pkey).
event termServer(key).
(*这里的【A认为】意思就是A所接收到的信息表明了这件事,因此可以声明如下这些事件:*)
(*客户端接受了【使用收到的key和服务器交互】这件事;*)
(*服务器接受了【使用key和公钥为pkey的客户端交互】这件事;*)
(*客户端认为已经完成了【使用key为会话密钥以及pkey作为客户端公钥,和服务器运行协议】这件事;*)
(*服务器认为已经完成了【使用key作为会话密钥,和客户端运行协议】这件事*)
query x:key,y:pkey;event(termClient(x,y))==>event(acceptsServer(x,y)).
query x:key; inj-event(termServer(x))==>inj-event(acceptsClient(x)).
(*这个意思是 ==>之后的 acceptsClient(x)的发生次数大于等于==>之前的termServer(x)的发生次数的。另外要注意, ==>之前写inj−event或者写event都行,只有箭头之后写什么才重要。*)
let clientA(pkA:pkey,skA:skey,pkB:spkey)=
out(c,pkA);
in(c,x:bitstring);
let y=adec(x,skA) in
let (=pkB,k:key)=checksign(y,pkB) in
event acceptsClient(k);
out(c,senc(s,k));
event termClient(k,pkA).
let serverB(pkB:spkey,skB:sskey,pkA:pkey)=
in(c,pkX:pkey);
new k:key;
event acceptsServer(k,pkX);
out(c,aenc(sign((pkB,k),skB),pkX));
in(c,x:bitstring);
let z=sdec(x,k) in
if pkX=pkA then event termServer(k).
process
new skA:skey;
new skB:sskey;
let pkA=pk(skA) in out(c,pkA);
let pkB=spk(skB) in out(c,pkB);
(((!clientA(pkA,skA,pkB))|(!serverB(pkB,skB,pkA))))
运行结果:
D:\proverif2.02pl1>proverif session3.pv
Process 0 (that is, the initial process):
{1}new skA: skey;
{2}new skB: sskey;
{3}let pkA: pkey = pk(skA) in
{4}out(c, pkA);
{5}let pkB: spkey = spk(skB) in
{6}out(c, pkB);
(
{7}!
{8}let skA_1: skey = skA in
{9}out(c, pkA);
{10}in(c, x: bitstring);
{11}let y: bitstring = adec(x,skA_1) in
{12}let (=pkB,k: key) = checksign(y,pkB) in
{13}event acceptsClient(k);
{14}out(c, senc(s,k));
{15}event termClient(k,pkA)
) | (
{16}!
{17}let skB_1: sskey = skB in
{18}in(c, pkX: pkey);
{19}new k_1: key;
{20}event acceptsServer(k_1,pkX);
{21}out(c, aenc(sign((pkB,k_1),skB_1),pkX));
{22}in(c, x_1: bitstring);
{23}let z: bitstring = sdec(x_1,k_1) in
{24}if (pkX = pkA) then
{25}event termServer(k_1)
)
-- Process 1 (that is, process 0, with let moved downwards):
{1}new skA: skey;
{2}new skB: sskey;
{3}let pkA: pkey = pk(skA) in
{4}out(c, pkA);
{5}let pkB: spkey = spk(skB) in
{6}out(c, pkB);
(
{7}!
{9}out(c, pkA);
{10}in(c, x: bitstring);
{8}let skA_1: skey = skA in
{11}let y: bitstring = adec(x,skA_1) in
{12}let (=pkB,k: key) = checksign(y,pkB) in
{13}event acceptsClient(k);
{14}out(c, senc(s,k));
{15}event termClient(k,pkA)
) | (
{16}!
{18}in(c, pkX: pkey);
{19}new k_1: key;
{20}event acceptsServer(k_1,pkX);
{17}let skB_1: sskey = skB in
{21}out(c, aenc(sign((pkB,k_1),skB_1),pkX));
{22}in(c, x_1: bitstring);
{23}let z: bitstring = sdec(x_1,k_1) in
{24}if (pkX = pkA) then
{25}event termServer(k_1)
)
-- Query not attacker(s[]) in process 1.
Translating the process into Horn clauses...
Completing...
Starting query not attacker(s[])
goal reachable: attacker(s[])
Derivation:
Abbreviations:
k_2 = k_1[pkX = pk(k_3),!1 = @sid]
1. The message spk(skB[]) may be sent to the attacker at output {6}.
attacker(spk(skB[])).
2. The attacker has some term k_3.
attacker(k_3).
3. By 2, the attacker may know k_3.
Using the function pk the attacker may obtain pk(k_3).
attacker(pk(k_3)).
4. The message pk(k_3) that the attacker may have by 3 may be received at input {18}.
So the message aenc(sign((spk(skB[]),k_2),skB[]),pk(k_3)) may be sent to the attacker at output {21}.
attacker(aenc(sign((spk(skB[]),k_2),skB[]),pk(k_3))).
5. By 4, the attacker may know aenc(sign((spk(skB[]),k_2),skB[]),pk(k_3)).
By 2, the attacker may know k_3.
Using the function adec the attacker may obtain sign((spk(skB[]),k_2),skB[]).
attacker(sign((spk(skB[]),k_2),skB[])).
6. By 5, the attacker may know sign((spk(skB[]),k_2),skB[]).
By 1, the attacker may know spk(skB[]).
Using the function checksign the attacker may obtain (spk(skB[]),k_2).
attacker((spk(skB[]),k_2)).
7. By 6, the attacker may know (spk(skB[]),k_2).
Using the function 2-proj-2-tuple the attacker may obtain k_2.
attacker(k_2).
8. The message pk(skA[]) may be sent to the attacker at output {4}.
attacker(pk(skA[])).
9. By 5, the attacker may know sign((spk(skB[]),k_2),skB[]).
By 8, the attacker may know pk(skA[]).
Using the function aenc the attacker may obtain aenc(sign((spk(skB[]),k_2),skB[]),pk(skA[])).
attacker(aenc(sign((spk(skB[]),k_2),skB[]),pk(skA[]))).
10. The message aenc(sign((spk(skB[]),k_2),skB[]),pk(skA[])) that the attacker may have by 9 may be received at input {10}.
So the message senc(s[],k_2) may be sent to the attacker at output {14}.
attacker(senc(s[],k_2)).
11. By 10, the attacker may know senc(s[],k_2).
By 7, the attacker may know k_2.
Using the function sdec the attacker may obtain s[].
attacker(s[]).
12. By 11, attacker(s[]).
The goal is reached, represented in the following fact:
attacker(s[]).
A more detailed output of the traces is available with
set traceDisplay = long.
new skA: skey creating skA_2 at {1}
new skB: sskey creating skB_2 at {2}
out(c, ~M) with ~M = pk(skA_2) at {4}
out(c, ~M_1) with ~M_1 = spk(skB_2) at {6}
out(c, ~M_2) with ~M_2 = pk(skA_2) at {9} in copy a
in(c, pk(a_1)) at {18} in copy a_2
new k_1: key creating k_2 at {19} in copy a_2
event acceptsServer(k_2,pk(a_1)) at {20} in copy a_2
out(c, ~M_3) with ~M_3 = aenc(sign((spk(skB_2),k_2),skB_2),pk(a_1)) at {21} in copy a_2
in(c, aenc(adec(~M_3,a_1),~M)) with aenc(adec(~M_3,a_1),~M) = aenc(sign((spk(skB_2),k_2),skB_2),pk(skA_2)) at {10} in copy a
event acceptsClient(k_2) at {13} in copy a
out(c, ~M_4) with ~M_4 = senc(s,k_2) at {14} in copy a
event termClient(k_2,pk(skA_2)) at {15} in copy a
The attacker has the message sdec(~M_4,2-proj-2-tuple(checksign(adec(~M_3,a_1),~M_1))) = s.
A trace has been found.
RESULT not attacker(s[]) is false.
-- Query event(termClient(x_2,y_1)) ==> event(acceptsServer(x_2,y_1)) in process 1.
Translating the process into Horn clauses...
Completing...
Starting query event(termClient(x_2,y_1)) ==> event(acceptsServer(x_2,y_1))
goal reachable: begin(acceptsServer(k_2,pk(k_3))) && attacker(k_3) -> end(termClient(k_2,pk(skA[])))
Abbreviations:
k_2 = k_1[pkX = pk(k_3),!1 = @sid]
Derivation:
Abbreviations:
k_2 = k_1[pkX = pk(k_3),!1 = @sid]
1. The message pk(skA[]) may be sent to the attacker at output {4}.
attacker(pk(skA[])).
2. We assume as hypothesis that
attacker(k_3).
3. By 2, the attacker may know k_3.
Using the function pk the attacker may obtain pk(k_3).
attacker(pk(k_3)).
4. The message pk(k_3) that the attacker may have by 3 may be received at input {18}.
The event acceptsServer(k_2,pk(k_3)) may be executed at {20}.
So the message aenc(sign((spk(skB[]),k_2),skB[]),pk(k_3)) may be sent to the attacker at output {21}.
attacker(aenc(sign((spk(skB[]),k_2),skB[]),pk(k_3))).
5. By 4, the attacker may know aenc(sign((spk(skB[]),k_2),skB[]),pk(k_3)).
By 2, the attacker may know k_3.
Using the function adec the attacker may obtain sign((spk(skB[]),k_2),skB[]).
attacker(sign((spk(skB[]),k_2),skB[])).
6. By 5, the attacker may know sign((spk(skB[]),k_2),skB[]).
By 1, the attacker may know pk(skA[]).
Using the function aenc the attacker may obtain aenc(sign((spk(skB[]),k_2),skB[]),pk(skA[])).
attacker(aenc(sign((spk(skB[]),k_2),skB[]),pk(skA[]))).
7. The message aenc(sign((spk(skB[]),k_2),skB[]),pk(skA[])) that the attacker may have by 6 may be received at input {10}.
So event termClient(k_2,pk(skA[])) may be executed at {15}.
end(termClient(k_2,pk(skA[]))).
8. By 7, end(termClient(k_2,pk(skA[]))).
The goal is reached, represented in the following fact:
end(termClient(k_2,pk(skA[]))).
A more detailed output of the traces is available with
set traceDisplay = long.
new skA: skey creating skA_2 at {1}
new skB: sskey creating skB_2 at {2}
out(c, ~M) with ~M = pk(skA_2) at {4}
out(c, ~M_1) with ~M_1 = spk(skB_2) at {6}
out(c, ~M_2) with ~M_2 = pk(skA_2) at {9} in copy a
in(c, pk(a_1)) at {18} in copy a_2
new k_1: key creating k_2 at {19} in copy a_2
event acceptsServer(k_2,pk(a_1)) at {20} in copy a_2
out(c, ~M_3) with ~M_3 = aenc(sign((spk(skB_2),k_2),skB_2),pk(a_1)) at {21} in copy a_2
in(c, aenc(adec(~M_3,a_1),~M)) with aenc(adec(~M_3,a_1),~M) = aenc(sign((spk(skB_2),k_2),skB_2),pk(skA_2)) at {10} in copy a
event acceptsClient(k_2) at {13} in copy a
out(c, ~M_4) with ~M_4 = senc(s,k_2) at {14} in copy a
event termClient(k_2,pk(skA_2)) at {15} in copy a (goal)
The event termClient(k_2,pk(skA_2)) is executed at {15} in copy a.
A trace has been found.
RESULT event(termClient(x_2,y_1)) ==> event(acceptsServer(x_2,y_1)) is false.
-- Query inj-event(termServer(x_2)) ==> inj-event(acceptsClient(x_2)) in process 1.
Translating the process into Horn clauses...
Completing...
Starting query inj-event(termServer(x_2)) ==> inj-event(acceptsClient(x_2))
goal reachable: begin(acceptsClient(k_2),@occ13_1) -> end(@occ25_1,termServer(k_2))
The hypothesis occurs strictly before the conclusion.
Abbreviations:
k_2 = k_1[pkX = pk(skA[]),!1 = @sid]
@occ25_1 = @occ25[x_1 = senc(s[],k_2),pkX = pk(skA[]),!1 = @sid]
@occ13_1 = @occ13[x = aenc(sign((spk(skB[]),k_2),skB[]),pk(skA[])),!1 = @sid_1]
RESULT inj-event(termServer(x_2)) ==> inj-event(acceptsClient(x_2)) is true.
--------------------------------------------------------------
Verification summary:
Query not attacker(s[]) is false.
Query event(termClient(x_2,y_1)) ==> event(acceptsServer(x_2,y_1)) is false.
Query inj-event(termServer(x_2)) ==> inj-event(acceptsClient(x_2)) is true.
--------------------------------------------------------------
-
Query not attacker(s[]) is false. 通过中间人攻击,s可能会泄露;
-
Query event(termClient(x_2,y_1)) ==> event(acceptsServer(x_2,y_1)) is
false.ClientA
认为自己已经和serverB
走完了协议流程,但和ClientA
走完流程的不一定是serverB
,因为有中间人攻击,它可以冒充serverB
。 -
Query inj-event(termServer(x_2)) ==> inj-event(acceptsClient(x_2)) is
true.serverB
认为自己和某个ClientX
走完了协议,即至少有一个
客户端和自己完成了这个协议。