Protocol agent services for Larks and other lightweights
AgentImpl.mesa
Dan Swinehart June 14, 1984 9:53:12 am PDT
DIRECTORY
Agent USING [ Authentication, AuthenticationRecord,
Authenticator, AuthenticatorLayout, Frob, FrobRecord, Principal ],
AgentRpcControl USING [ ExportInterface, InterfaceName ],
DESFace USING [ Block, Blocks, CBCCheckEncrypt, CorrectParity,
EncryptBlock, GetRandomKey, Key, nullKey ],
IO,
Log USING [ Report, Problem ],
Names USING [ CurrentPasskey, InstanceFromNetAddress ],
NamesGV USING [ AttributeSeq, GVGetAttribute, GVGetAttributeSeq, GVIsAuthenticated ],
PupDefs USING [ GetPupAddress, PupAddress ],
PupTypes USING [ PupHostID, PupNetID ],
Rope USING [ Concat, Equal, Length, Flatten, ROPE ],
RPC USING [ EncryptionKey, matchAllVersions, ShortROPE, VersionRange ],
RPCPkt USING [ Machine ],
RPCSecurity USING [ CopyPrincipal ],
UserProfile USING [ Token ]
;
AgentImpl: CEDAR PROGRAM
IMPORTS AgentRpcControl, DESFace, IO, Log, Names, NamesGV, PupDefs, Rope, RPCSecurity, UserProfile
EXPORTS Agent SHARES RPCSecurity = {
OPEN IO;
Authentication
blockSize: NAT = SIZE[DESFace.Block];
larkRegistry: Rope.ROPE ← ".Lark";
defaultServerInstance: Rope.ROPE
UserProfile.Token[key: "ThrushServerInstance", default: "Morley.Lark"];
Authenticate: PUBLIC PROC [ nonceId: LONG INTEGER, a, b: Agent.Principal ]
RETURNS [ an: Agent.Frob,
ar: Agent.Frob ] = TRUSTED {
ka, kb: DESFace.Key ← DESFace.nullKey -- !!! --;
kx, ky, ck: DESFace.Key;
aLen: NAT=a.Length[];
bLen: NAT=b.Length[];
authenticator: Agent.Authenticator;
authentication: Agent.Authentication;
nBlks: NAT ← DESBlocks[SIZE[Agent.AuthenticatorLayout[aLen]]];
IF a=NIL OR b=NIL OR aLen=0 OR bLen=0 THEN {
Log.Problem["Authenticate: Null arguments", $System]; RETURN[NIL, NIL]; };
ar ← NEW[Agent.FrobRecord[nBlks*blockSize]];
authenticator ← LOOPHOLE[@ar[0]];
a ← a.Flatten[];
b ← b.Flatten[];
DESFace.CorrectParity[@ka];
DESFace.CorrectParity[@kb];
kx ← DESFace.GetRandomKey[];
ky ← DESFace.GetRandomKey[];
ck ← DESFace.GetRandomKey[];
-- Build and encrypt Authenticator --
DESFace.EncryptBlock[key: kb, from: Blk[LONG[@ky]], to: Blk[@authenticator.ky ]];
DESFace.EncryptBlock[key: kb, from: Blk[LONG[@ck]], to: Blk[@authenticator.ck ]];
authenticator.time ← 0;
RPCSecurity.CopyPrincipal[from: a, to: @(authenticator.a)];
DESFace.CBCCheckEncrypt[key: ky, nBlks: nBlks-2, from: Blks[@authenticator.ck],
to: Blks[@authenticator.ck], seed: [0,0,0,0] ];
Encrypt the whole thing for a's benefit
DESFace.CBCCheckEncrypt[key: kx, nBlks: nBlks, from: Blks[@authenticator.ky],
to: Blks[@authenticator.ky], seed: [0,0,0,0] ];
Build and encrypt Authentication
nBlks ← DESBlocks[SIZE[Agent.AuthenticationRecord[bLen]]];
an ← NEW[Agent.FrobRecord[nBlks*blockSize]];
authentication ← LOOPHOLE[@an[0]];
authentication.nonceId ← nonceId;
DESFace.EncryptBlock[key: ka, from: Blk[LONG[@kx]],to: Blk[@authentication.kx] ];
DESFace.EncryptBlock[key: ka, from: Blk[LONG[@ck]], to: Blk[@authentication.ck ]];
RPCSecurity.CopyPrincipal[from: b, to: @authentication.b];
DESFace.CBCCheckEncrypt[key: kx, nBlks: nBlks-2, from: Blks[@authentication.ck],
to: Blks[@authentication.ck], seed: [0,0,0,0] ];
Log.Report[IO.PutFR["Authenticate[%s, to; %s]", rope[a], rope[b]], $System];
};
DESBlocks: PROC[len: NAT] RETURNS [nBlks: NAT] = { RETURN [
(len + blockSize - 1) / blockSize ]; };
Blk: PROC[p: LONG POINTER] RETURNS [LONG POINTER TO DESFace.Block] =
TRUSTED INLINE { RETURN [LOOPHOLE[p]]; };
Blks: PROC[p: LONG POINTER] RETURNS [DESFace.Blocks] =
TRUSTED INLINE { RETURN [LOOPHOLE[p]]; };
Binding
Vitae: PUBLIC PROC[
clientMachine: RPCPkt.Machine,
range: RPC.VersionRange←RPC.matchAllVersions,
interfaceType: RPC.ShortROPE ]
RETURNS [
serverMachine: RPCPkt.Machine←[[0],[0]],
clientRname: Agent.Principal,
clientInstance: RPC.ShortROPE←NIL,
serverInstance: RPC.ShortROPE←NIL
] = TRUSTED {
Implements everything but range check
serverMachineRope: RPC.ShortROPE;
clientMachineRName: RPC.ShortROPE;
pa: PupDefs.PupAddress;
interfaceSeq: NamesGV.AttributeSeq;
comment: Rope.ROPENIL;
clientInstance ← Names.InstanceFromNetAddress[clientMachine, "0"];
clientMachineRName ← Names.InstanceFromNetAddress[clientMachine, larkRegistry];
SELECT NamesGV.GVIsAuthenticated[clientMachineRName] FROM
bogus, nonexistent, unknown => comment ← "RName is unknown or invalid. ";
authentic, perhaps => {
clientRname ← NamesGV.GVGetAttribute[clientMachineRName, $owner, NIL];
interfaceSeq ← NamesGV.GVGetAttributeSeq[clientMachineRName, $interface];
An interface is "type, instance, versionStart, versionEnd"
IF interfaceSeq#NIL THEN {
IF ~interfaceType.Equal[interfaceSeq[0].attributeValue, FALSE] THEN
comment ← comment.Concat[IO.PutFR["GV interface type is %s. ", rope[interfaceSeq[0].attributeValue]]];
serverInstance ← interfaceSeq[1].attributeValue;
};
IF serverInstance=NIL THEN serverInstance ← defaultServerInstance;
serverMachineRope ← NamesGV.GVGetAttribute[ serverInstance, $connect, NIL ];
IF serverMachineRope#NIL THEN {
pa ← PupDefs.GetPupAddress[[0,0], serverMachineRope];
serverMachine ← [net: pa.net, host: pa.host];
}
ELSE
comment ← comment.Concat["Instance has not been exported. "];
};
ENDCASE=>ERROR;
Log.Report[
IO.PutFR["Vitae[lark: %b, type: %s] -> [ rName: %s, client: %s, server: %s]",
card[clientMachine.host], rope[interfaceType], rope[clientRname], rope[clientInstance],
rope[serverInstance]], $System];
IF comment#NIL THEN Log.Report[IO.PutFR[" (%s)", rope[comment]], $System];
};
Initialization
myName: AgentRpcControl.InterfaceName = [
type: "Agent.Lark",
instance: UserProfile.Token[key: "AgentInstance", default: "Michaelson.Lark"]];
serverPassword: RPC.EncryptionKey = Names.CurrentPasskey[UserProfile.Token[
key: "AgentPassword", default: "MFLFLX"]];
AgentRpcControl.ExportInterface[
interfaceName: myName,
user: myName.instance,
password: serverPassword];
Log.Report[IO.PutFR["Agent exported as %s", rope[myName.instance]], $System];
}.