<> <> <<>> <> <<>> DIRECTORY AuthenticationP14V2 USING [AuthenticationError, CallError, CallProblem, ChangeSimpleKey, ChangeStrongKey, CheckSimpleCredentials, CreateSimpleKey, CreateStrongKey, CredentialsPackage, DeleteSimpleKey, DeleteStrongKey, GetStrongCredentials, HashedPassword, Problem, SeqWords, SeqWordsObject, StrongCredentials, StrongVerifier, Which], Basics USING [BITXOR, LongNumber, ShortNumber], BasicTime USING [earliestGMT, FromNSTime, GetClockPulses, GMT, latestGMT, Now, OutOfRange, Period, TimeNotKnown, ToNSTime, Unpack, Unpacked, Update], Booting USING [RegisterProcs, RollbackProc], CrRPC USING [CreateClientHandle, DestroyClientHandle, Error, Handle, MarshalledROPEHWords], DESFace USING [Block, Blocks, CBCCheckDecrypt, CBCCheckEncrypt, CorrectParity, EncryptBlock, Key, nullKey], Process USING [Detach, Pause, priorityBackground, SecondsToTicks, SetPriority], RefText USING [InlineAppendChar, ObtainScratch, ReleaseScratch], Rope USING [Equal, FromRefText, InlineFetch, Length, ROPE], SafeStorage USING [CantEstablishFinalization, EnableFinalization, EstablishFinalization, FinalizationQueue, FQNext, NewFQ, ReEstablishFinalization], TimeP15V2 USING [Time], XNS USING [Address, GetThisHost, Host, unknownHost, unknownSocket], XNSAuth USING [Credentials, CredentialsType, HashedPassword, Key, Name, Verifier], XNSRouter USING [GetHops, Hops], XNSServerLocation USING [EachAddressProc, LocateServers, StopBroadcast], XNSWKS USING [authenticationInfo] ; XNSAuthImpl: CEDAR MONITOR LOCKS lock USING lock: Lock IMPORTS AuthenticationP14V2, Basics, BasicTime, Booting, CrRPC, DESFace, Process, RefText, Rope, SafeStorage, XNS, XNSRouter, XNSServerLocation EXPORTS XNSAuth ~ { OPEN Auth: AuthenticationP14V2, Time: TimeP15V2; authPgmNum: CARD ~ 14; authVersionNum: CARDINAL ~ 2; SeqWords: TYPE ~ Auth.SeqWords; SeqWordsObject: TYPE ~ Auth.SeqWordsObject; GMT: TYPE ~ BasicTime.GMT; Block: TYPE ~ DESFace.Block; ROPE: TYPE ~ Rope.ROPE; NSTime: TYPE ~ Time.Time; Credentials: TYPE ~ XNSAuth.Credentials; CredentialsType: TYPE ~ XNSAuth.CredentialsType; HashedPassword: TYPE ~ XNSAuth.HashedPassword; Key: TYPE ~ XNSAuth.Key; Name: TYPE ~ XNSAuth.Name; Verifier: TYPE ~ XNSAuth.Verifier; HostNumber: TYPE ~ XNS.Host; myHostNumber: HostNumber _ XNS.GetThisHost[]; authSvcName: Name _ ["CHServers", "CHServers", "Authentication Service"]; initialStrongVerifier: Auth.StrongVerifier ~ [BasicTime.ToNSTime[BasicTime.earliestGMT], 0]; oneMinuteOfSeconds: INT ~ 60; oneHourOfSeconds: INT ~ 30*oneMinuteOfSeconds; oneDayOfSeconds: INT ~ LONG[24]*oneHourOfSeconds; oneWeekOfSeconds: INT ~ LONG[7]*oneDayOfSeconds; strongCredentialsLifetime: INT ~ oneDayOfSeconds; -- one day of seconds secondsBetweenSweeps: INT ~ 3*oneMinuteOfSeconds; strongVerifierTimeout: INT ~ oneMinuteOfSeconds; unknownTime: GMT _ BasicTime.Update[BasicTime.earliestGMT, oneWeekOfSeconds]; Now: PROC RETURNS [now: GMT] ~ INLINE { now _ BasicTime.Now[ ! BasicTime.TimeNotKnown => { now _ unknownTime; CONTINUE } ] }; AuthenticationError: PUBLIC ERROR [problem: Auth.Problem] _ Auth.AuthenticationError; CallError: PUBLIC ERROR[problem: Auth.CallProblem, whichArg: Auth.Which] _ Auth.CallError; MarshallError: PRIVATE ERROR ~ CODE; CantContactAuthServer: PROC ~ { ERROR }; Lock: TYPE ~ REF LockObject; LockObject: TYPE ~ MONITORED RECORD []; <> <> SimpleIdentity: TYPE ~ REF SimpleIdentityObject; SimpleIdentityObject: TYPE ~ RECORD [ name: Name, password: ROPE, valid: BOOL _ TRUE, credentials: Credentials, verifier: Verifier ]; StrongIdentity: TYPE ~ REF StrongIdentityObject; StrongIdentityObject: TYPE ~ RECORD [ next: StrongIdentity, conversations: StrongConversation, name: Name, password: ROPE, -- optional, if present must agree with key valid: BOOL _ TRUE, key: Key ]; Identity: TYPE ~ REF; -- SimpleIdentityObject initiatorCacheLock: Lock ~ NEW[LockObject _ []]; strongIdentities: StrongIdentity _ NIL; AddNewStrongIdentity: ENTRY PROC [lock: Lock _ initiatorCacheLock, newID: StrongIdentity] ~ { newID.next _ strongIdentities; strongIdentities _ newID }; RemoveOldStrongIdentity: ENTRY PROC [lock: Lock _ initiatorCacheLock, oldID: StrongIdentity] ~ { p, prev: StrongIdentity; p _ strongIdentities; prev _ NIL; WHILE (p # NIL) AND (p # oldID) DO prev _ p; p _ p.next ENDLOOP; IF p # NIL THEN { IF prev # NIL THEN prev.next _ p.next ELSE strongIdentities _ p.next }; }; strongIdentityFinalizerQueue: SafeStorage.FinalizationQueue; droppedStrongIdentities: CARD _ 0; StrongIdentityFinalizer: PROC ~ { Process.SetPriority[Process.priorityBackground]; DO strongID: StrongIdentity _ NARROW[SafeStorage.FQNext[strongIdentityFinalizerQueue]]; RemoveOldStrongIdentity[oldID~strongID]; droppedStrongIdentities _ droppedStrongIdentities.SUCC; ENDLOOP; }; StartStrongIdentityFinalizer: PROC ~ { established: BOOL; strongIdentityFinalizerQueue _ SafeStorage.NewFQ[20]; established _ TRUE; SafeStorage.EstablishFinalization[type~CODE[StrongIdentityObject], npr~1, fq~strongIdentityFinalizerQueue ! SafeStorage.CantEstablishFinalization => { established _ FALSE; CONTINUE }]; IF NOT established THEN { established _ TRUE; SafeStorage.ReEstablishFinalization[type~CODE[StrongIdentityObject], npr~1, fq~strongIdentityFinalizerQueue ! SafeStorage.CantEstablishFinalization => { established _ FALSE; CONTINUE }]; }; IF NOT established THEN ERROR; TRUSTED { Process.Detach[FORK StrongIdentityFinalizer[]]; }; }; MakeIdentity: PUBLIC PROC[name: Name, password: ROPE, credentialsType: CredentialsType _ strong, check: BOOL _ TRUE] RETURNS [identity: Identity] ~ { SELECT credentialsType FROM simple => { simpleID: SimpleIdentity; simpleID _ NEW[SimpleIdentityObject _ [name~name, password~password, credentials~CredentialsFromName[name], verifier~VerifierFromHashedPassword[SimpleKeyFromPassword[password]]]]; identity _ simpleID; IF check THEN CheckSimple[simpleID.credentials, simpleID.verifier]; }; strong => { strongID: StrongIdentity _ NEW[StrongIdentityObject _ [name~name, password~password, key~StrongKeyFromPassword[password]]]; AddNewStrongIdentity[newID~strongID]; SafeStorage.EnableFinalization[strongID]; identity _ strongID; IF check THEN Terminate[Initiate[identity, authSvcName, 60]]; }; ENDCASE => ERROR; }; MakeStrongIdentityUsingKey: PUBLIC PROC[name: Name, key: Key, check: BOOL _ TRUE] RETURNS [identity: Identity] ~ { strongID: StrongIdentity; TRUSTED { DESFace.CorrectParity[LOOPHOLE[LONG[@key]]] }; strongID _ NEW[StrongIdentityObject _ [name~name, password~NIL, key~key]]; AddNewStrongIdentity[newID~strongID]; SafeStorage.EnableFinalization[strongID]; identity _ strongID; IF check THEN Terminate[Initiate[identity, authSvcName, 60]]; }; DestroyIdentity: PUBLIC PROC [identity: Identity] ~ { IF identity = NIL THEN RETURN; WITH identity SELECT FROM simpleID: SimpleIdentity => { simpleID.valid _ FALSE; simpleID.password _ NIL; simpleID.verifier _ VerifierFromHashedPassword[SimpleKeyFromPassword[NIL]]; }; strongID: StrongIdentity => { strongID.valid _ FALSE; strongID.conversations _ NIL; strongID.password _ NIL; strongID.key _ StrongKeyFromPassword[NIL]; }; ENDCASE => ERROR; }; nullIdentity: Identity _ NIL; nullIdentityLock: Lock ~ NEW[LockObject _ []]; GetNullIdentity: PUBLIC PROC RETURNS [Identity] ~ { RETURN [EntryGetNullIdentity[]] }; EntryGetNullIdentity: ENTRY PROC [lock: Lock _ nullIdentityLock] RETURNS [Identity] ~ { IF nullIdentity = NIL THEN nullIdentity _ MakeIdentity[name~["", "", ""], password~"", credentialsType~simple, check~FALSE]; RETURN [nullIdentity] }; <> SimpleConversation: TYPE ~ REF SimpleConversationObject; SimpleConversationObject: TYPE ~ RECORD [ initiatorID: SimpleIdentity, recipientName: Name ]; StrongConversation: TYPE ~ REF StrongConversationObject; StrongConversationObject: TYPE ~ RECORD [ next: StrongConversation, initiatorID: StrongIdentity, timeStamp: GMT, referenced: BOOL _ TRUE, recipientName: Name, recipientHostNumber: HostNumber, credentials: Credentials, conversationKey: Key, lastStrongVerifier: Auth.StrongVerifier ]; Conversation: TYPE ~ REF; -- SimpleConversationObject <> StrongConversationCacheGet: ENTRY PROC[lock: Lock _ initiatorCacheLock, id: StrongIdentity, name: Name] RETURNS[StrongConversation] ~ { ENABLE UNWIND => NULL; p, prev: StrongConversation; prev _ NIL; p _ id.conversations; WHILE (p # NIL) AND (NOT EqualNames[name, p.recipientName]) DO prev _ p; p _ p.next; ENDLOOP; IF p # NIL THEN { IF prev # NIL THEN prev.next _ p.next ELSE id.conversations _ p.next; p.next _ NIL }; RETURN [p] }; StrongConversationCachePut: ENTRY PROC[lock: Lock _ initiatorCacheLock, c: StrongConversation, id: StrongIdentity] ~ { ENABLE UNWIND => NULL; c.next _ id.conversations; id.conversations _ c }; SweepStrongConversationCache: ENTRY PROC[lock: Lock _ initiatorCacheLock] ~ { ENABLE UNWIND => NULL; p, prev: StrongConversation; now: GMT ~ Now[]; FOR strongID: StrongIdentity _ strongIdentities, strongID.next WHILE strongID # NIL DO p _ strongID.conversations; prev _ NIL; WHILE p # NIL DO IF NOT p.referenced THEN -- delete the entry -- { p _ p.next; IF prev = NIL THEN strongID.conversations _ p ELSE prev.next _ p } ELSE -- leave the entry alone -- { p.referenced _ FALSE; prev _ p; p _ p.next }; ENDLOOP; ENDLOOP; }; <> Initiate: PUBLIC PROC [identity: Identity, recipientName: Name, seconds: CARD] RETURNS [conversation: Conversation] ~ { IF identity = NIL THEN ERROR; WITH identity SELECT FROM simpleID: SimpleIdentity => { c: SimpleConversation _ NEW[SimpleConversationObject _ [initiatorID~simpleID, recipientName~recipientName]]; conversation _ c }; strongID: StrongIdentity => { c: StrongConversation; c _ StrongConversationCacheGet[id~strongID, name~recipientName]; IF c = NIL THEN c _ NEW[StrongConversationObject _ [timeStamp~BasicTime.earliestGMT, recipientName~recipientName, recipientHostNumber~XNS.unknownHost, credentials~[strong,NIL], conversationKey~, lastStrongVerifier~initialStrongVerifier]]; c.initiatorID _ strongID; c.referenced _ TRUE; Refresh[c, seconds]; conversation _ c }; ENDCASE => ERROR; }; Refresh: PUBLIC PROC [conversation: Conversation, seconds: CARD] ~ { IF conversation = NIL THEN ERROR; WITH conversation SELECT FROM simpleC: SimpleConversation => { NULL }; strongC: StrongConversation => { seqWords: SeqWords; credentialsPackage: Auth.CredentialsPackage; nonce: CARD; DoGetStrongCredentials: PROC [h: CrRPC.Handle, host: HostNumber] ~ { seqWords _ Auth.GetStrongCredentials[h, strongC.initiatorID.name, strongC.recipientName, nonce] }; IF (BasicTime.Period[from~strongC.timeStamp, to~Now[]] + INT[seconds]) <= strongCredentialsLifetime THEN RETURN; nonce _ BasicTime.GetClockPulses[]; CallRemote[DoGetStrongCredentials]; seqWords _ DecryptSeqWords[strongC.initiatorID.key, seqWords]; [cp~credentialsPackage] _ FetchCredentialsPackageFromSeqWords[seqWords, 0 ! MarshallError => GOTO Bad]; IF credentialsPackage.nonce # nonce THEN GOTO Bad; strongC.recipientName _ credentialsPackage.recipient; strongC.credentials _ credentialsPackage.credentials; strongC.conversationKey _ credentialsPackage.conversationKey; strongC.lastStrongVerifier _ initialStrongVerifier; strongC.timeStamp _ Now[]; EXITS Bad => ERROR AuthenticationError[credentialsInvalid]; }; ENDCASE => ERROR; }; Terminate: PUBLIC PROC [conversation: Conversation] ~ { IF conversation = NIL THEN ERROR; WITH conversation SELECT FROM simpleC: SimpleConversation => { NULL }; strongC: StrongConversation => { strongID: StrongIdentity ~ strongC.initiatorID; strongC.initiatorID _ NIL; StrongConversationCachePut[c~strongC, id~strongID] }; ENDCASE => ERROR; }; GetCredentials: PUBLIC PROC [conversation: Conversation] RETURNS [credentials: Credentials] ~ { IF conversation = NIL THEN ERROR; WITH conversation SELECT FROM simpleC: SimpleConversation => { credentials _ simpleC.initiatorID.credentials }; strongC: StrongConversation => { credentials _ strongC.credentials }; ENDCASE => ERROR; }; SetRecipientHostNumber: PUBLIC PROC [conversation: Conversation, recipientHostNumber: HostNumber] ~ { IF conversation = NIL THEN ERROR; WITH conversation SELECT FROM simpleC: SimpleConversation => { NULL }; strongC: StrongConversation => { strongC.recipientHostNumber _ recipientHostNumber }; ENDCASE => ERROR; }; GetNextVerifier: PUBLIC PROC [conversation: Conversation] RETURNS [verifier: Verifier] ~ { IF conversation = NIL THEN ERROR; WITH conversation SELECT FROM simpleC: SimpleConversation => { verifier _ simpleC.initiatorID.verifier }; strongC: StrongConversation => { now: GMT ~ Now[]; IF BasicTime.Period[ from~BasicTime.FromNSTime[strongC.lastStrongVerifier.timeStamp], to~now ] > 0 THEN strongC.lastStrongVerifier _ [timeStamp~BasicTime.ToNSTime[now], ticks~0] ELSE strongC.lastStrongVerifier _ IncrementStrongVerifier[strongC.lastStrongVerifier]; verifier _ EncryptedVerifierFromStrongVerifier[strongC.conversationKey, LOOPHOLE[strongC.recipientHostNumber], strongC.lastStrongVerifier]; }; ENDCASE => ERROR; }; ReplyVerifierChecks: PUBLIC PROC [conversation: Conversation, verifier: Verifier] RETURNS [ok: BOOL] ~ { IF conversation = NIL THEN ERROR; WITH conversation SELECT FROM simpleC: SimpleConversation => { ERROR AuthenticationError[inappropriateCredentials] }; strongC: StrongConversation => { ENABLE MarshallError => { ok _ FALSE; CONTINUE }; sV: Auth.StrongVerifier ~ StrongVerifierFromEncryptedVerifier[ strongC.conversationKey, LOOPHOLE[strongC.recipientHostNumber], verifier]; ok _ (sV = IncrementStrongVerifier[strongC.lastStrongVerifier]); IF ok THEN strongC.lastStrongVerifier _ sV }; ENDCASE => ERROR; }; <> <> RSimpleConversation: TYPE ~ REF RSimpleConversationObject; RSimpleConversationObject: TYPE ~ RECORD [ next: RSimpleConversation, referenced: BOOL _ TRUE, initiatorName: Name, credentials: Credentials, verifier: Verifier ]; rSimpleConversationCacheLock: Lock _ NEW[LockObject _ []]; rSimpleConversationCache: RSimpleConversation _ NIL; RSimpleConversationCacheGet: ENTRY PROC [ lock: Lock _ rSimpleConversationCacheLock, credentials: Credentials] RETURNS [RSimpleConversation] ~ { ENABLE UNWIND => NULL; p, prev: RSimpleConversation; IF credentials.type # simple THEN ERROR; prev _ NIL; p _ rSimpleConversationCache; WHILE (p # NIL) AND (NOT EqualSeqWords[credentials.value, p.credentials.value]) DO prev _ p; p _ p.next; ENDLOOP; IF p # NIL THEN { IF prev # NIL THEN prev.next _ p.next ELSE rSimpleConversationCache _ p.next; p.next _ NIL; p.referenced _ TRUE }; RETURN [p] }; RSimpleConversationCachePut: ENTRY PROC[ lock: Lock _ rSimpleConversationCacheLock, conversation: RSimpleConversation] ~ { ENABLE UNWIND => NULL; conversation.next _ rSimpleConversationCache; rSimpleConversationCache _ conversation }; SweepRSimpleConversationCache: ENTRY PROC[lock: Lock _ rSimpleConversationCacheLock] ~ { ENABLE UNWIND => NULL; p, prev: RSimpleConversation; p _ rSimpleConversationCache; prev _ NIL; WHILE p # NIL DO IF p.referenced THEN { p.referenced _ FALSE; prev _ p; p _ p.next } ELSE { p _ p.next; IF prev = NIL THEN rSimpleConversationCache _ p ELSE prev.next _ p }; ENDLOOP; }; <> RStrongConversation: TYPE ~ REF RStrongConversationObject; RStrongConversationObject: TYPE ~ RECORD [ next: RStrongConversation, referenced: BOOL _ TRUE, credentials: Credentials, decryptedStrongCredentials: Auth.StrongCredentials, lastStrongVerifier: Auth.StrongVerifier ]; rStrongConversationCacheLock: Lock _ NEW[LockObject _ []]; rStrongConversationCache: RStrongConversation _ NIL; RStrongConversationCacheGet: ENTRY PROC [ lock: Lock _ rStrongConversationCacheLock, credentials: Credentials] RETURNS [RStrongConversation] ~ { ENABLE UNWIND => NULL; p, prev: RStrongConversation; IF credentials.type # strong THEN ERROR; prev _ NIL; p _ rStrongConversationCache; WHILE (p # NIL) AND (NOT EqualSeqWords[credentials.value, p.credentials.value]) DO prev _ p; p _ p.next; ENDLOOP; IF p # NIL THEN { IF prev # NIL THEN prev.next _ p.next ELSE rStrongConversationCache _ p.next; p.next _ NIL; p.referenced _ TRUE }; RETURN [p] }; RStrongConversationCachePut: ENTRY PROC[ lock: Lock _ rStrongConversationCacheLock, conversation: RStrongConversation] ~ { ENABLE UNWIND => NULL; conversation.next _ rStrongConversationCache; rStrongConversationCache _ conversation }; SweepRStrongConversationCache: ENTRY PROC[lock: Lock _ rStrongConversationCacheLock] ~ { ENABLE UNWIND => NULL; p, prev: RStrongConversation; p _ rStrongConversationCache; prev _ NIL; WHILE p # NIL DO IF p.referenced THEN { p.referenced _ FALSE; prev _ p; p _ p.next } ELSE { p _ p.next; IF prev = NIL THEN rStrongConversationCache _ p ELSE prev.next _ p }; ENDLOOP; }; <> InvalidateRecipientCaches: Booting.RollbackProc ~ { rSimpleConversationCache _ NIL; rStrongConversationCache _ NIL; }; <> Authenticate: PUBLIC PROC [myIdentity: Identity, hisCredentials: Credentials, hisVerifier: Verifier, allowSimpleCredentials: BOOL, useExpiredCredentials: BOOL] RETURNS [hisName: Name] ~ { IF myIdentity = NIL THEN ERROR; SELECT hisCredentials.type FROM simple => { IF NOT allowSimpleCredentials THEN ERROR AuthenticationError[inappropriateCredentials]; hisName _ AuthenticateSimple[hisCredentials, hisVerifier] }; strong => { [hisName~hisName] _ AuthenticateStrong[myIdentity~myIdentity, hisCredentials~hisCredentials, hisVerifier~hisVerifier, useExpiredCredentials~useExpiredCredentials, computeReplyVerifier~FALSE] }; ENDCASE => ERROR; }; AuthenticateAndReply: PUBLIC PROC [myIdentity: Identity, hisCredentials: Credentials, hisVerifier: Verifier, useExpiredCredentials: BOOL] RETURNS [hisName: Name, replyVerifier: Verifier] ~ { IF myIdentity = NIL THEN ERROR; SELECT hisCredentials.type FROM simple => { ERROR AuthenticationError[inappropriateCredentials]; }; strong => { [hisName, replyVerifier] _ AuthenticateStrong[myIdentity~myIdentity, hisCredentials~hisCredentials, hisVerifier~hisVerifier, useExpiredCredentials~useExpiredCredentials, computeReplyVerifier~TRUE]; }; ENDCASE => ERROR; }; <> AuthenticateSimple: PROC [hisCredentials: Credentials, hisVerifier: Verifier] RETURNS [hisName: Name] ~ { rSimpleC: RSimpleConversation; rSimpleC _ RSimpleConversationCacheGet[credentials~hisCredentials]; IF (rSimpleC = NIL) OR (NOT EqualSeqWords[hisVerifier, rSimpleC.verifier]) THEN { CheckSimple[hisCredentials, hisVerifier]; rSimpleC _ NEW[RSimpleConversationObject _ [initiatorName~FetchNameFromSeqWords[hisCredentials.value, 0].name, credentials~hisCredentials, verifier~hisVerifier]]; }; hisName _ rSimpleC.initiatorName; RSimpleConversationCachePut[conversation~rSimpleC]; }; verifierTimeout: INT ~ 60; AuthenticateStrong: PROC [myIdentity: Identity, hisCredentials: Credentials, hisVerifier: Verifier, useExpiredCredentials: BOOL _ FALSE, computeReplyVerifier: BOOL _ FALSE] RETURNS [hisName: Name, replyVerifier: Verifier _ NIL] ~ { rStrongC: RStrongConversation; WITH myIdentity SELECT FROM myStrongID: StrongIdentity => { rStrongC _ RStrongConversationCacheGet[credentials~hisCredentials]; IF rStrongC = NIL THEN { ENABLE MarshallError => CONTINUE; temp: SeqWords _ DecryptSeqWords[key~myStrongID.key, seqWords~hisCredentials.value]; rStrongC _ NEW[RStrongConversationObject _ [credentials~hisCredentials, decryptedStrongCredentials~FetchStrongCredentialsFromSeqWords[temp,0].sc, lastStrongVerifier~initialStrongVerifier]]; }; IF rStrongC = NIL THEN ERROR AuthenticationError[credentialsInvalid]; IF NOT useExpiredCredentials THEN { expired: BOOL ~ (BasicTime.Period[ from~Now[], to~BasicTime.FromNSTime[rStrongC.decryptedStrongCredentials.expirationTime ]] <= 0); IF expired THEN ERROR AuthenticationError[credentialsExpired] }; { ENABLE MarshallError, BasicTime.OutOfRange => GOTO Bad; temp: Auth.StrongVerifier _ StrongVerifierFromEncryptedVerifier[ rStrongC.decryptedStrongCredentials.conversationKey, LOOPHOLE[myHostNumber], hisVerifier]; IF NOT StrongVerifierGT[new~temp, old~rStrongC.lastStrongVerifier] THEN ERROR AuthenticationError[verifierReused]; IF StrongVerifierExpired[temp] THEN ERROR AuthenticationError[verifierExpired]; IF computeReplyVerifier THEN { rStrongC.lastStrongVerifier _ IncrementStrongVerifier[temp]; replyVerifier _ EncryptedVerifierFromStrongVerifier[ rStrongC.decryptedStrongCredentials.conversationKey, LOOPHOLE[myHostNumber], rStrongC.lastStrongVerifier] } ELSE { rStrongC.lastStrongVerifier _ temp }; EXITS Bad => ERROR AuthenticationError[verifierInvalid]; }; hisName _ rStrongC.decryptedStrongCredentials.initiator; RStrongConversationCachePut[conversation: rStrongC]; }; mySimpleID: SimpleIdentity => { ERROR AuthenticationError[inappropriateCredentials] }; ENDCASE => ERROR; }; CheckSimple: PROC[credentials: Credentials, verifier: Verifier] ~ { <> okay: BOOL _ FALSE; DoCheckSimple: PROC [h: CrRPC.Handle, host: HostNumber] ~ { okay _ Auth.CheckSimpleCredentials[h, credentials, verifier] }; CallRemote[DoCheckSimple]; IF NOT okay -- can this happen? -- THEN ERROR AuthenticationError[problem~credentialsInvalid]; }; <> ChangeMyPasswords: PUBLIC PROC [myIdentity: Identity, newPassword: ROPE, changeStrong: BOOL _ TRUE, changeSimple: BOOL _ TRUE] ~ { IF changeStrong THEN { newKey: Key _ StrongKeyFromPassword[newPassword]; ChangeMyStrongKey[myIdentity, newKey] }; IF changeSimple THEN { newKey: HashedPassword _ SimpleKeyFromPassword[newPassword]; ChangeMySimpleKey[myIdentity, newKey] }; }; CreateStrongKey: PUBLIC PROC [myIdentity: Identity, name: Name, newKey: Key] ~ { c: Conversation; DoIt: PROC [h: CrRPC.Handle, host: HostNumber] ~ { SetRecipientHostNumber[c, host]; Auth.CreateStrongKey[h, GetCredentials[c], GetNextVerifier[c], name, newKey] }; IF myIdentity = NIL THEN ERROR; c _ Initiate[myIdentity, authSvcName, oneMinuteOfSeconds]; { ENABLE UNWIND => Terminate[c]; CallRemote[DoIt] }; Terminate[c]; }; ChangeMyStrongKey: PUBLIC PROC [myIdentity: Identity, newKey: Key] ~ { c: Conversation; DoIt: PROC [h: CrRPC.Handle, host: HostNumber] ~ { SetRecipientHostNumber[c, host]; Auth.ChangeStrongKey[h, GetCredentials[c], GetNextVerifier[c], newKey] }; IF myIdentity = NIL THEN ERROR; c _ Initiate[myIdentity, authSvcName, oneMinuteOfSeconds]; { ENABLE UNWIND => Terminate[c]; CallRemote[DoIt] }; Terminate[c]; }; DeleteStrongKey: PUBLIC PROC [myIdentity: Identity, name: Name] ~ { c: Conversation; DoIt: PROC [h: CrRPC.Handle, host: HostNumber] ~ { SetRecipientHostNumber[c, host]; Auth.DeleteStrongKey[h, GetCredentials[c], GetNextVerifier[c], name] }; IF myIdentity = NIL THEN ERROR; c _ Initiate[myIdentity, authSvcName, oneMinuteOfSeconds]; { ENABLE UNWIND => Terminate[c]; CallRemote[DoIt] }; Terminate[c]; }; CreateSimpleKey: PUBLIC PROC [myIdentity: Identity, name: Name, newKey: HashedPassword] ~ { c: Conversation; DoIt: PROC [h: CrRPC.Handle, host: HostNumber] ~ { SetRecipientHostNumber[c, host]; Auth.CreateSimpleKey[h, GetCredentials[c], GetNextVerifier[c], name, newKey] }; IF myIdentity = NIL THEN ERROR; c _ Initiate[myIdentity, authSvcName, oneMinuteOfSeconds]; { ENABLE UNWIND => Terminate[c]; CallRemote[DoIt] }; Terminate[c]; }; ChangeMySimpleKey: PUBLIC PROC [myIdentity: Identity, newKey: HashedPassword] ~ { c: Conversation; DoIt: PROC [h: CrRPC.Handle, host: HostNumber] ~ { SetRecipientHostNumber[c, host]; Auth.ChangeSimpleKey[h, GetCredentials[c], GetNextVerifier[c], newKey] }; IF myIdentity = NIL THEN ERROR; c _ Initiate[myIdentity, authSvcName, oneMinuteOfSeconds]; { ENABLE UNWIND => Terminate[c]; CallRemote[DoIt] }; Terminate[c]; }; DeleteSimpleKey: PUBLIC PROC [myIdentity: Identity, name: Name] ~ { c: Conversation; DoIt: PROC [h: CrRPC.Handle, host: HostNumber] ~ { SetRecipientHostNumber[c, host]; Auth.DeleteSimpleKey[h, GetCredentials[c], GetNextVerifier[c], name] }; IF myIdentity = NIL THEN ERROR; c _ Initiate[myIdentity, authSvcName, oneMinuteOfSeconds]; { ENABLE UNWIND => Terminate[c]; CallRemote[DoIt] }; Terminate[c]; }; <> StrongKeyFromPassword: PUBLIC PROC [password: ROPE] RETURNS [key: Key] ~ { index: INT; passwordLen: INT ~ Rope.Length[password]; ki: DESFace.Key _ DESFace.nullKey; bi: Block; biPlus1: Block; FOR index _ 0, index + 4 WHILE index < passwordLen DO len: INT ~ MIN[4, passwordLen-index]; TRUSTED { StoreSubropeInBlock[password, index, len, @bi, TRUE]; DESFace.CorrectParity[@ki]; <> DESFace.EncryptBlock[key~ki, from~@bi, to~@biPlus1]; ki _ LOOPHOLE[biPlus1] }; ENDLOOP; TRUSTED { DESFace.CorrectParity[@ki] }; RETURN [ LOOPHOLE[ki] ]; }; SimpleKeyFromPassword: PUBLIC PROC [password: ROPE] RETURNS [hashVal: HashedPassword _ 0] ~ { c: CHAR; acc: Basics.LongNumber; FOR i: INT IN [0 .. Rope.Length[password]) DO c _ Rope.InlineFetch[password, i]; SELECT c FROM IN ['A .. 'Z] => c _ 'a + (c - 'A); ENDCASE; acc.hi _ hashVal; acc.lo _ ORD[c]; hashVal _ acc.lc MOD 65357; ENDLOOP; }; GetCredentialsType: PUBLIC PROC [credentials: Credentials] RETURNS [CredentialsType] ~ { RETURN [credentials.type] }; GetConversationDetails: PUBLIC PROC [conversation: Conversation] RETURNS [ recipientName: Name, recipientHostNumber: HostNumber, credentials: Credentials, conversationKey: Key, owner: Identity] ~ { IF conversation = NIL THEN ERROR; WITH conversation SELECT FROM simpleC: SimpleConversation => { recipientName _ simpleC.recipientName; recipientHostNumber _ XNS.unknownHost; credentials _ simpleC.initiatorID.credentials; conversationKey _ ALL[0]; owner _ simpleC.initiatorID }; strongC: StrongConversation => { recipientName _ strongC.recipientName; recipientHostNumber _ strongC.recipientHostNumber; credentials _ strongC.credentials; conversationKey _ strongC.conversationKey; owner _ strongC.initiatorID }; ENDCASE => ERROR; }; GetIdentityDetails: PUBLIC PROC [identity: Identity] RETURNS [ name: Name, password: ROPE, credentialsType: CredentialsType] ~ { IF identity = NIL THEN ERROR; WITH identity SELECT FROM simpleI: SimpleIdentity => { name _ simpleI.name; password _ simpleI.password; credentialsType _ simple }; strongI: StrongIdentity => { name _ strongI.name; password _ strongI.password; credentialsType _ strong }; ENDCASE => ERROR; }; GetCredentialsDetails: PUBLIC PROC [myKey: Key, hisCredentials: Credentials] RETURNS [ok: BOOL, credentialsType: CredentialsType, conversationKey: Key, expirationTime: GMT, hisName: Name] ~ { ok _ FALSE; SELECT hisCredentials.type FROM simple => { ENABLE MarshallError => CONTINUE; credentialsType _ simple; conversationKey _ ALL[0]; expirationTime _ BasicTime.latestGMT; hisName _ FetchNameFromSeqWords[hisCredentials.value, 0].name; ok _ TRUE; }; strong => { ENABLE MarshallError => CONTINUE; rStrongC: RStrongConversation; sC: Auth.StrongCredentials; credentialsType _ strong; rStrongC _ RStrongConversationCacheGet[credentials~hisCredentials]; IF rStrongC # NIL THEN { sC _ rStrongC.decryptedStrongCredentials; RStrongConversationCachePut[conversation: rStrongC] } ELSE { temp: SeqWords _ DecryptSeqWords[key~myKey, seqWords~hisCredentials.value]; [sc~sC] _ FetchStrongCredentialsFromSeqWords[temp,0] }; conversationKey _ sC.conversationKey; expirationTime _ BasicTime.FromNSTime[sC.expirationTime]; hisName _ sC.initiator; ok _ TRUE; }; ENDCASE => ERROR; }; <> Daemon: PROC ~ { DO Process.Pause[Process.SecondsToTicks[secondsBetweenSweeps]]; SweepStrongConversationCache[]; SweepRStrongConversationCache[]; ENDLOOP; }; <> EqualNames: PROC [a: Name, b: Name] RETURNS [BOOL] ~ { RETURN[Rope.Equal[a.organization, b.organization, FALSE] AND Rope.Equal[a.domain, b.domain, FALSE] AND Rope.Equal[a.object, b.object, FALSE]] }; EqualSeqWords: PROC [a, b: SeqWords] RETURNS [BOOL] ~ { IF a.length # b.length THEN RETURN [FALSE]; FOR i: CARDINAL IN [0..a.length) DO IF a.body[i] # b.body[i] THEN RETURN [FALSE]; ENDLOOP; RETURN [TRUE] }; IncrementStrongVerifier: PROC [v: Auth.StrongVerifier] RETURNS [result: Auth.StrongVerifier] ~ { result.timeStamp _ v.timeStamp; IF (result.ticks _ v.ticks + 1) = 0 THEN result.timeStamp _ result.timeStamp + 1; }; StrongVerifierGT: PROC [new, old: Auth.StrongVerifier] RETURNS [gt: BOOL] ~ { deltaT: INT ~ BasicTime.Period[from~BasicTime.FromNSTime[old.timeStamp], to~BasicTime.FromNSTime[new.timeStamp]]; SELECT deltaT FROM > 0 => RETURN [TRUE]; < 0 => RETURN [FALSE]; 0 => RETURN [new.ticks > old.ticks]; ENDCASE; }; StrongVerifierExpired: PROC [v: Auth.StrongVerifier] RETURNS [expired: BOOL] ~ { deltaT: INT ~ BasicTime.Period[from~BasicTime.FromNSTime[v.timeStamp], to~Now[]]; RETURN [ deltaT > strongVerifierTimeout ] }; FetchRopeFromSeqWords: PROC [s: SeqWords, where: CARDINAL] RETURNS [newWhere: CARDINAL, r: ROPE] ~ { i, count, seqLen: CARDINAL; w: Basics.ShortNumber; buf: REF TEXT; seqLen _ s.length; IF where >= seqLen THEN ERROR MarshallError; count _ s.body[where]; where _ where + 1; buf _ RefText.ObtainScratch[count]; i _ 0; WHILE i < count DO IF where >= seqLen THEN ERROR MarshallError; w.lc _ s.body[where]; where _ where + 1; buf _ RefText.InlineAppendChar[buf, VAL[w.hi]]; i _ i + 1; IF i < count THEN { buf _ RefText.InlineAppendChar[buf, VAL[w.lo]]; i _ i + 1 }; ENDLOOP; newWhere _ where; r _ Rope.FromRefText[buf]; RefText.ReleaseScratch[buf] }; StoreRopeInSeqWords: PROC [r: ROPE, s: SeqWords, where: CARDINAL] RETURNS [newWhere: CARDINAL] ~ { i, length, seqLen: CARDINAL; w: Basics.ShortNumber; length _ Rope.Length[r]; seqLen _ s.length; IF where >= seqLen THEN ERROR MarshallError; s.body[where] _ length; where _ where + 1; i _ 0; WHILE i < length DO w.hi _ ORD[Rope.InlineFetch[r,i]]; i _ i + 1; w.lo _ (IF i < length THEN ORD[Rope.InlineFetch[r,i]] ELSE 0); i _ i + 1; IF where >= seqLen THEN ERROR MarshallError; s.body[where] _ LOOPHOLE[w]; where _ where + 1; ENDLOOP; RETURN [where] }; FetchSeqWordsFromSeqWords: PROC [s: SeqWords, where: CARDINAL] RETURNS [newWhere: CARDINAL, result: SeqWords] ~ { n, seqLen: CARDINAL; seqLen _ s.length; IF where >= seqLen THEN ERROR MarshallError; n _ s.body[where]; where _ where + 1; IF (n+where) >= seqLen THEN ERROR MarshallError; result _ NEW[SeqWordsObject[n]]; FOR i: CARDINAL IN [0..n) DO result.body[i] _ s.body[where]; where _ where + 1; ENDLOOP; newWhere _ where; }; StoreSeqWordsInSeqWords: PROC [s: SeqWords, arg: SeqWords, where: CARDINAL] RETURNS [newWhere: CARDINAL] ~ { n: CARDINAL ~ arg.length; seqLen: CARDINAL ~ s.length; IF (where+n+1) >= seqLen THEN ERROR MarshallError; s.body[where] _ n; where _ where + 1; FOR i: CARDINAL IN [0..n) DO s.body[where] _ arg.body[i]; where _ where + 1; ENDLOOP; newWhere _ where; }; FetchBlockFromSeqWords: PROC [s: SeqWords, where: CARDINAL] RETURNS [newWhere: CARDINAL, block: Block] ~ { IF (newWhere _ where+4) >= s.length THEN ERROR MarshallError; block[0] _ s.body[where]; block[1] _ s.body[where+1]; block[2] _ s.body[where+2]; block[3] _ s.body[where+3]; }; StoreBlockInSeqWords: PROC [s: SeqWords, block: Block, where: CARDINAL] RETURNS [newWhere: CARDINAL] ~ { IF (newWhere _ where+4) >= s.length THEN ERROR MarshallError; s.body[where] _ block[0]; s.body[where+1] _ block[1]; s.body[where+2] _ block[2]; s.body[where+3] _ block[3]; }; FetchCredentialsFromSeqWords: PROC [s: SeqWords, where: CARDINAL] RETURNS [newWhere: CARDINAL, c: Credentials] ~ { type: CARDINAL; IF where >= s.length THEN ERROR MarshallError; type _ s.body[where]; where _ where + 1; SELECT type FROM ORD[CredentialsType.strong] => c.type _ strong; ORD[CredentialsType.simple] => c.type _ simple; ENDCASE => ERROR MarshallError; [newWhere~newWhere, result~c.value] _ FetchSeqWordsFromSeqWords[s, where]; }; FetchCARDFromSeqWords: PROC [s: SeqWords, where: CARDINAL] RETURNS [newWhere: CARDINAL, result: CARD] ~ { n: Basics.LongNumber; IF(newWhere _ where+2) >= s.length THEN ERROR MarshallError; n.hi _ s.body[where]; n.lo _ s.body[where+1]; result _ n.lc }; FetchCredentialsPackageFromSeqWords: PROC [s: SeqWords, where: CARDINAL] RETURNS [newWhere: CARDINAL, cp: Auth.CredentialsPackage] ~ { [where, cp.credentials] _ FetchCredentialsFromSeqWords[s, where]; IF cp.credentials.type # strong THEN ERROR AuthenticationError[inappropriateCredentials]; [where, cp.nonce] _ FetchCARDFromSeqWords[s, where]; [where, cp.recipient] _ FetchNameFromSeqWords[s, where]; [where, cp.conversationKey] _ FetchBlockFromSeqWords[s, where]; newWhere _ where }; FetchStrongCredentialsFromSeqWords: PROC [s: SeqWords, where: CARDINAL] RETURNS [newWhere: CARDINAL, sc: Auth.StrongCredentials] ~ { [where, sc.conversationKey] _ FetchBlockFromSeqWords[s, where]; [where, sc.expirationTime] _ FetchCARDFromSeqWords[s, where]; [where, sc.initiator] _ FetchNameFromSeqWords[s, where]; newWhere _ where }; StoreSubropeInBlock: PROC [r: ROPE, index, len: INT, to: LONG POINTER TO Block, mapCase: BOOL _ TRUE] ~ { <> c: CHAR; blockIndex: INT _ 0; WHILE blockIndex < len DO c _ Rope.InlineFetch[r, index]; IF mapCase THEN SELECT c FROM IN ['A .. 'Z] => c _ 'a + (c - 'A); ENDCASE; TRUSTED { to[blockIndex] _ ORD[c] }; index _ index + 1; blockIndex _ blockIndex + 1; ENDLOOP; WHILE blockIndex < 4 DO TRUSTED { to[blockIndex] _ 0 }; blockIndex _ blockIndex + 1; ENDLOOP; }; FetchNameFromSeqWords: PROC [s: SeqWords, where: CARDINAL] RETURNS [newWhere: CARDINAL, name: Name] ~ { [where, name.organization] _ FetchRopeFromSeqWords[s, where]; [where, name.domain] _ FetchRopeFromSeqWords[s, where]; [where, name.object] _ FetchRopeFromSeqWords[s, where]; newWhere _ where }; StoreNameInSeqWords: PROC [name: Name, s: SeqWords, where: CARDINAL] RETURNS [newWhere: CARDINAL] ~ { where _ StoreRopeInSeqWords[name.organization, s, where]; where _ StoreRopeInSeqWords[name.domain, s, where]; where _ StoreRopeInSeqWords[name.object, s, where]; RETURN [where] }; MarshalledNameHWORDs: PROC [name: Name] RETURNS [hWords: CARDINAL] ~ { RETURN [CrRPC.MarshalledROPEHWords[name.organization] + CrRPC.MarshalledROPEHWords[name.domain] + CrRPC.MarshalledROPEHWords[name.object]] }; SeqWordsFromName: PROC [name: Name] RETURNS [SeqWords] ~ { s: SeqWords _ NEW[SeqWordsObject[MarshalledNameHWORDs[name]]]; [] _ StoreNameInSeqWords[name, s, 0]; RETURN [s] }; CredentialsFromName: PROC [name: Name] RETURNS [credentials: Credentials] ~ { RETURN[ [type~simple, value~SeqWordsFromName[name]] ] }; VerifierFromHashedPassword: PROC [hashedPassword: HashedPassword] RETURNS [verifier: Verifier] ~ { <> verifier _ NEW[SeqWordsObject[1]]; verifier.body[0] _ hashedPassword }; EncryptSeqWords: PROC [key: Key, seqWords: SeqWords] RETURNS [result: SeqWords] ~ { <> nBlocks: CARDINAL _ (seqWords.length + SIZE[Block] - 1) / SIZE[Block]; roundedLength: CARDINAL _ nBlocks * SIZE[Block]; result _ NEW[SeqWordsObject[roundedLength]]; IF roundedLength # seqWords.length THEN { FOR i: CARDINAL IN [0..seqWords.length) DO result.body[i] _ seqWords.body[i] ENDLOOP; FOR i: CARDINAL IN [seqWords.length..roundedLength) DO result.body[i] _ 0 ENDLOOP; seqWords _ result }; TRUSTED { blocksFrom: DESFace.Blocks ~ LOOPHOLE[ LOOPHOLE[seqWords, LONG POINTER] + SIZE[SeqWordsObject[0]] ]; blocksTo: DESFace.Blocks ~ LOOPHOLE[ LOOPHOLE[result, LONG POINTER] + SIZE[SeqWordsObject[0]] ]; DESFace.CBCCheckEncrypt[LOOPHOLE[key], nBlocks, blocksFrom, blocksTo, ALL[0]]; }; }; DecryptSeqWords: PROC [key: Key, seqWords: SeqWords] RETURNS [result: SeqWords] ~ { <> nBlocks: CARDINAL ~ seqWords.length / SIZE[Block]; roundedLength: CARDINAL _ nBlocks * SIZE[Block]; IF seqWords.length # roundedLength THEN ERROR MarshallError; result _ NEW[SeqWordsObject[roundedLength]]; TRUSTED { blocksFrom: DESFace.Blocks ~ LOOPHOLE[ LOOPHOLE[seqWords, LONG POINTER] + SIZE[SeqWordsObject[0]] ]; blocksTo: DESFace.Blocks ~ LOOPHOLE[ LOOPHOLE[result, LONG POINTER] + SIZE[SeqWordsObject[0]] ]; DESFace.CBCCheckDecrypt[LOOPHOLE[key], nBlocks, blocksFrom, blocksTo, ALL[0]]; }; }; EncryptedVerifierFromStrongVerifier: PROC [conversationKey: Key, hostNumber: MACHINE DEPENDENT RECORD [a, b, c: WORD], strongVerifier: Auth.StrongVerifier] RETURNS [verifier: Verifier] ~ { seqWords: SeqWords ~ NEW[SeqWordsObject[SIZE[Auth.StrongVerifier]]]; TRUSTED { p: LONG POINTER TO Auth.StrongVerifier _ LOOPHOLE[ LOOPHOLE[seqWords, LONG POINTER] + SIZE[SeqWordsObject[0]] ]; p^ _ strongVerifier }; seqWords.body[0] _ Basics.BITXOR[seqWords.body[0], hostNumber.a]; seqWords.body[1] _ Basics.BITXOR[seqWords.body[1], hostNumber.b]; seqWords.body[2] _ Basics.BITXOR[seqWords.body[2], hostNumber.c]; verifier _ EncryptSeqWords[key~LOOPHOLE[conversationKey], seqWords~seqWords]; }; StrongVerifierFromEncryptedVerifier: PROC [conversationKey: Key, hostNumber: MACHINE DEPENDENT RECORD [a, b, c: WORD], verifier: Verifier] RETURNS [strongVerifier: Auth.StrongVerifier] ~ { IF verifier.length # SIZE[Auth.StrongVerifier] THEN ERROR MarshallError; verifier _ DecryptSeqWords[key~LOOPHOLE[conversationKey], seqWords~verifier]; verifier.body[0] _ Basics.BITXOR[verifier.body[0], hostNumber.a]; verifier.body[1] _ Basics.BITXOR[verifier.body[1], hostNumber.b]; verifier.body[2] _ Basics.BITXOR[verifier.body[2], hostNumber.c]; TRUSTED { p: LONG POINTER TO Auth.StrongVerifier _ LOOPHOLE[ LOOPHOLE[verifier, LONG POINTER] + SIZE[SeqWordsObject[0]] ]; strongVerifier _ p^ }; }; <> ServerInfo: TYPE ~ REF ServerInfoObject; ServerInfoObject: TYPE ~ RECORD [ next: ServerInfo, address: XNS.Address, hops: XNSRouter.Hops ]; serverInfoLock: Lock _ NEW[LockObject _ []]; serverBroadcastLock: Lock _ NEW[LockObject _ []]; serverInfo: ServerInfo _ NIL; serverInfoTimestamp: GMT; defaultServerHops: XNSRouter.Hops ~ 3; maxServerHops: XNSRouter.Hops ~ 6; secondsBetweenBroadcasts: INT ~ 600; DeleteServer: ENTRY PROC [lock: Lock _ serverInfoLock, it: ServerInfo] ~ { ENABLE UNWIND => NULL; IF it = serverInfo THEN { serverInfo _ it.next; RETURN }; FOR p: ServerInfo _ serverInfo, p.next WHILE p # NIL DO IF p.next = it THEN { p.next _ it.next; RETURN }; ENDLOOP; }; AddServerAddress: ENTRY PROC [lock: Lock _ serverInfoLock, addr: XNS.Address, hops: XNSRouter.Hops] ~ { ENABLE UNWIND => NULL; p, prev, new: ServerInfo; <> prev _ NIL; p _ serverInfo; WHILE (p # NIL) AND (p.address # addr) DO { prev _ p; p _ p.next } ENDLOOP; IF p = NIL THEN { new _ NEW[ServerInfoObject _ [next~NIL, address~addr, hops~hops]] } ELSE { IF prev # NIL THEN prev.next _ p.next ELSE serverInfo _ p.next; new _ p; new.hops _ hops }; <> prev _ NIL; p _ serverInfo; WHILE (p # NIL) AND (p.hops < hops) DO { prev _ p; p _ p.next } ENDLOOP; new.next _ p; IF prev # NIL THEN prev.next _ new ELSE serverInfo _ new; }; BroadcastForServers: ENTRY PROC [lock: Lock _ serverBroadcastLock, maxHops: CARDINAL, nWanted: CARDINAL _ 0, tryLimit: CARDINAL _ 0] ~ { ENABLE UNWIND => NULL; nGot: CARDINAL _ 0; EachAddress: XNSServerLocation.EachAddressProc -- [addr: XNS.Address] -- ~ { hops: XNSRouter.Hops; addr.socket _ XNS.unknownSocket; hops _ XNSRouter.GetHops[addr.net]; AddServerAddress[addr~addr, hops~hops]; IF (nGot _ nGot.SUCC) = nWanted THEN ERROR XNSServerLocation.StopBroadcast[] }; XNSServerLocation.LocateServers[eachAddress~EachAddress, socket~XNSWKS.authenticationInfo, remotePgm~authPgmNum, remotePgmVersion~authVersionNum, maxHops~maxHops, tryLimit~tryLimit]; serverInfoTimestamp _ Now[]; }; GetBestServer: PROC RETURNS [ServerInfo] ~ { DO p: ServerInfo _ serverInfo; -- ATOMIC currentHops: XNSRouter.Hops; SELECT TRUE FROM (p = NIL) => { BroadcastForServers[maxHops~maxServerHops, nWanted~1]; p _ serverInfo; TRUSTED { Process.Detach[ FORK BroadcastForServers[maxHops~defaultServerHops, tryLimit~1] ] }; }; ((currentHops _ XNSRouter.GetHops[p.address.net]) # p.hops) => { DeleteServer[it~p]; AddServerAddress[addr~p.address, hops~currentHops]; LOOP }; ((p.hops > 0) AND (BasicTime.Period[from~serverInfoTimestamp, to~Now[]] > secondsBetweenBroadcasts)) => TRUSTED { Process.Detach[ FORK BroadcastForServers[maxHops~MIN[(p.hops-1), defaultServerHops], tryLimit~1] ] }; ENDCASE; RETURN [p]; ENDLOOP; }; CallRemote: PROC [proc: PROC [CrRPC.Handle, HostNumber]] ~ { h: CrRPC.Handle _ NIL; p: ServerInfo; maxTries: CARDINAL ~ 10; CleanUp: PROC ~ { IF h # NIL THEN { CrRPC.DestroyClientHandle[h]; h _ NIL }}; FOR try: CARDINAL IN [1..maxTries] DO BEGIN ENABLE { UNWIND => CleanUp[]; CrRPC.Error => { CleanUp[]; DeleteServer[it~p]; LOOP }}; IF (p _ GetBestServer[]) = NIL THEN EXIT; h _ CrRPC.CreateClientHandle[class~$SPP, remote~p.address]; proc[h, p.address.host]; CleanUp[]; RETURN; END; ENDLOOP; CleanUp[]; CantContactAuthServer[]; }; <> GetStrongCredentialsLifetime: PROC [name: Name, password: ROPE] RETURNS [ok: BOOL _ FALSE, seconds: INT _ 0, from, to: BasicTime.Unpacked] ~ { ENABLE CallError, AuthenticationError => CONTINUE; id: Identity; c: Conversation; t1, t2, tExp: GMT; myKey: Key; hisCredentials: Credentials; id _ MakeIdentity[name, password, strong, FALSE]; t1 _ Now[]; c _ Initiate[id, name, 3600]; t2 _ Now[]; myKey _ StrongKeyFromPassword[password]; [credentials~hisCredentials] _ GetConversationDetails[c]; [ok~ok, expirationTime~tExp] _ GetCredentialsDetails[myKey~myKey, hisCredentials~hisCredentials]; IF ok THEN { seconds _ (BasicTime.Period[from~t1, to~tExp] + BasicTime.Period[from~t2, to~tExp] + 1) / 2; from _ BasicTime.Unpack[t1]; to _ BasicTime.Unpack[tExp]; }; Terminate[c]; }; AuthenticateToSelf: PROC [name: Name, password: ROPE, howMany: CARDINAL] ~ { count: CARDINAL _ 0; id: Identity; c: Conversation; credentials: Credentials; verifier: Verifier; replyVerifier: Verifier; myHostNumber: HostNumber; id _ MakeIdentity[name, password, strong, FALSE]; c _ Initiate[id, name, 3600]; myHostNumber _ XNS.GetThisHost[]; SetRecipientHostNumber[c, myHostNumber]; WHILE count < howMany DO credentials _ GetCredentials[c]; verifier _ GetNextVerifier[c]; [replyVerifier~replyVerifier] _ AuthenticateAndReply[id, credentials, verifier, FALSE]; IF NOT ReplyVerifierChecks[c, replyVerifier] THEN ERROR AuthenticationError[verifierInvalid]; count _ count + 1; ENDLOOP; Terminate[c]; }; <
> StartStrongIdentityFinalizer[]; Booting.RegisterProcs[r~InvalidateRecipientCaches]; TRUSTED { Process.Detach[ FORK Daemon[]] }; TRUSTED { Process.Detach[ FORK BroadcastForServers[maxHops~defaultServerHops, nWanted~2]] }; }.