/// <summary>This is SecureData that needs to get to an SA.</summary> protected void HandleData(MemBlock b, ISender return_path) { SecurityDataMessage sdm = new SecurityDataMessage(b); Dictionary <ISender, PeerSecAssociation> sender_to_sa = null; PeerSecAssociation sa = null; try { sender_to_sa = _spi[sdm.SPI]; sa = sender_to_sa[return_path]; sa.HandleData(b, return_path, null); } catch { if (sender_to_sa == null && !SecurityPolicy.Supports(sdm.SPI)) { throw new Exception("Invalid SPI: " + sdm.SPI); } else if (sa == null) { NoSuchSA(sdm.SPI, return_path); throw new Exception("No SA for: " + return_path); } else if (sa.Closed) { throw new Exception("SA has been closed."); } else { throw; } } }
/// <summary>This (idempotently) returns a new SecurityAssociation for the /// specified sender using the specified SA.</summary> protected PeerSecAssociation CreateSecurityAssociation(ISender Sender, int SPI, bool start) { if (!SecurityPolicy.Supports(SPI)) { throw new Exception("Unsupported SPI"); } PeerSecAssociation sa = null; lock (_sync) { Dictionary <ISender, PeerSecAssociation> sender_to_sa = null; if (_spi.ContainsKey(SPI)) { sender_to_sa = _spi[SPI]; } else { sender_to_sa = new Dictionary <ISender, PeerSecAssociation>(); _spi[SPI] = sender_to_sa; } if (sender_to_sa.ContainsKey(Sender)) { sa = sender_to_sa[Sender]; } else { sa = new PeerSecAssociation(Sender, _ch, SPI); sa.Subscribe(this, null); sa.StateChangeEvent += SAStateChange; sa.RequestUpdate += SARequestUpdate; sender_to_sa[Sender] = sa; } } if (start && sa.State != SecurityAssociation.States.Active) { StartSA(sa); } return(sa); }
/// <summary>This is SecureData that needs to get to an SA.</summary> protected void HandleData(MemBlock b, ISender return_path) { SecurityDataMessage sdm = new SecurityDataMessage(b); Dictionary <ISender, PeerSecAssociation> sender_to_sa = null; PeerSecAssociation sa = null; try { sender_to_sa = _spi[sdm.SPI]; sa = sender_to_sa[return_path]; sa.HandleData(b, return_path, null); } catch (Exception e) { if (sender_to_sa == null && !SecurityPolicy.Supports(sdm.SPI)) { ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format( "Unsupported SPI, from {0}, message: {1}", return_path, sdm)); } else { if (sa == null) { ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format( "No SA, from {0}, message: {1}", return_path, sdm)); } else if (sa.Closed) { ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format( "SA, {0}, has been closed, from {1}, message: {2}.", sa, return_path, sdm)); } else { ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format( "SA, {0}, from {1}, message: {2}, causes unhandled exception : {3}", sa, return_path, sdm, e)); } NoSuchSA(sdm.SPI, return_path); } } }
/// <summary>This is the control state machine. There are three paths in /// the state machine, iniator, receiver, and bidirectional. The /// bidirectional case occurs when two remote ISenders that are matched /// together initiate a handshake at the same time, otherwise the initiator /// /receiver pattern is followed. The high level overview for the states /// are: /// 1a) Send a Cookie /// 1b) Receive a Cookie which responds with a CookieResponse /// 2a) Receive a CookieResponse that contains a list of CAs, if you have /// a Certificate that supports one of the CAs send it along with a DHE /// and a list of your supported CAs in a DHEWithCertificateAndCAs. /// 2b) Receive a DHEWithCertificateAndCAs, verify the certificate and attempt /// to find a matching Certificate for the list of CAs, if you find one, /// finish the DHE handshake and send the certificate via a DHEWithCertificate /// 3a) Receive a DHEWithCertificate, verify the certificate and DHE and /// send a Confirm that you are ready to Verify the stack and start the /// system. /// 3b) Receive a Confirm, verify the entire stack and send a Confirm /// 4a)Receive a Confirm, verify the entire stack and all set to go /// </summary> protected void HandleControl(MemBlock b, ISender return_path) { ISender low_level_sender = return_path; if (low_level_sender is ReqrepManager.ReplyState) { low_level_sender = ((ReqrepManager.ReplyState)low_level_sender).ReturnPath; } SecurityControlMessage scm = new SecurityControlMessage(b); MemBlock calc_cookie = CalculateCookie(low_level_sender); if (scm.Version != Version) { throw new Exception("Invalid version: " + scm.Version); } else if (!SecurityPolicy.Supports(scm.SPI)) { throw new Exception("No support for SPI: " + scm.SPI); } else if (!scm.RemoteCookie.Equals(calc_cookie)) { if (scm.Type != SecurityControlMessage.MessageType.Cookie && scm.Type != SecurityControlMessage.MessageType.NoSuchSA) { throw new Exception("Invalid cookie!"); } } SecurityControlMessage scm_reply = new SecurityControlMessage(); scm_reply.Version = Version; scm_reply.SPI = scm.SPI; PeerSecAssociation sa = null; // This can be in a try statement since this is best effort anyway try { Dictionary <ISender, PeerSecAssociation> sender_to_sa = _spi[scm.SPI]; sa = sender_to_sa[low_level_sender]; } catch { } if (sa != null) { sa.Reset(); if (sa.Closed) { throw new Exception("SA closed!"); } else if (sa.State == SecurityAssociation.States.Active) { return; } } try { switch (scm.Type) { case SecurityControlMessage.MessageType.NoSuchSA: HandleControlNoSuchSA(sa); break; case SecurityControlMessage.MessageType.Cookie: HandleControlCookie(sa, calc_cookie, scm, scm_reply, return_path, low_level_sender); break; case SecurityControlMessage.MessageType.CookieResponse: HandleControlCookieResponse(sa, scm, scm_reply, return_path, low_level_sender); break; case SecurityControlMessage.MessageType.DHEWithCertificateAndCAs: HandleControlDHEWithCertificateAndCAs(sa, scm, scm_reply, return_path, low_level_sender); break; case SecurityControlMessage.MessageType.DHEWithCertificate: HandleControlDHEWithCertificates(sa, scm, scm_reply, return_path, low_level_sender); break; case SecurityControlMessage.MessageType.Confirm: HandleControlConfirm(sa, scm, scm_reply, return_path, low_level_sender); break; default: throw new Exception("Invalid message!"); } } catch { if (sa != null && sa.Closed) { throw new Exception("SA closed."); } else { throw; } } }
/// <summary>This is the control state machine. There are three paths in /// the state machine, iniator, receiver, and bidirectional. The /// bidirectional case occurs when two remote ISenders that are matched /// together initiate a handshake at the same time, otherwise the initiator /// /receiver pattern is followed. The high level overview for the states /// are: /// 1a) Send a Cookie /// 1b) Receive a Cookie which responds with a CookieResponse /// 2a) Receive a CookieResponse that contains a list of CAs, if you have /// a Certificate that supports one of the CAs send it along with a DHE /// and a list of your supported CAs in a DHEWithCertificateAndCAs. /// 2b) Receive a DHEWithCertificateAndCAs, verify the certificate and attempt /// to find a matching Certificate for the list of CAs, if you find one, /// finish the DHE handshake and send the certificate via a DHEWithCertificate /// 3a) Receive a DHEWithCertificate, verify the certificate and DHE and /// send a Confirm that you are ready to Verify the stack and start the /// system. /// 3b) Receive a Confirm, verify the entire stack and send a Confirm /// 4a)Receive a Confirm, verify the entire stack and all set to go /// </summary> protected void HandleControl(MemBlock b, ISender return_path) { ISender low_level_sender = return_path; if (low_level_sender is ReqrepManager.ReplyState) { low_level_sender = ((ReqrepManager.ReplyState)low_level_sender).ReturnPath; } SecurityControlMessage scm = new SecurityControlMessage(b); MemBlock calc_cookie = CalculateCookie(low_level_sender); if (scm.Version != Version) { ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format( "Invalid version expected {0}, found {1}, from {2}, message: {3}", Version, scm.Version, low_level_sender, scm)); return; } else if (!SecurityPolicy.Supports(scm.SPI)) { ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format( "Unsupported SPI, from {0}, message: {1}", low_level_sender, scm)); return; } else if ((scm.Type != SecurityControlMessage.MessageType.Cookie && scm.Type != SecurityControlMessage.MessageType.NoSuchSA) && !scm.RemoteCookie.Equals(calc_cookie)) { ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format( "Invalid cookie, Expected {0}, Found {1}, From {2}, Message {3}", calc_cookie, scm.RemoteCookie, low_level_sender, scm)); return; } SecurityControlMessage scm_reply = new SecurityControlMessage(); scm_reply.Version = Version; scm_reply.SPI = scm.SPI; PeerSecAssociation sa = null; // This can be in a try statement since this is best effort anyway try { Dictionary <ISender, PeerSecAssociation> sender_to_sa = _spi[scm.SPI]; sa = sender_to_sa[low_level_sender]; } catch { } if (sa != null) { // Reset cases where no state has been set yet or state is attempting // to be re-established, if other message types arrive, they will // expect pre-set state and will fail. The mechanisms instilled thus // far should prevent this, but this makes it explicit. Now only // wayward messages will arrive to other states. if (scm.Type == SecurityControlMessage.MessageType.NoSuchSA || scm.Type == SecurityControlMessage.MessageType.Cookie || scm.Type == SecurityControlMessage.MessageType.CookieResponse || scm.Type == SecurityControlMessage.MessageType.DHEWithCertificateAndCAs) { sa.TryReset(); } if (sa.Closed) { ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, GetHashCode() + " SA closed, clearing SA state! " + sa); sa = null; } else if (sa.State == SecurityAssociation.States.Active && // Two nodes can demand a confirm at the same time, if this // message doesn't pass, then one side will close due to timeout scm.Type != SecurityControlMessage.MessageType.Confirm) { ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format( "{0}, {1}: {2}", GetHashCode(), "SA Active, received message", scm.Type)); return; } } try { switch (scm.Type) { case SecurityControlMessage.MessageType.NoSuchSA: HandleControlNoSuchSA(sa); break; case SecurityControlMessage.MessageType.Cookie: HandleControlCookie(sa, calc_cookie, scm, scm_reply, return_path, low_level_sender); break; case SecurityControlMessage.MessageType.CookieResponse: HandleControlCookieResponse(sa, scm, scm_reply, return_path, low_level_sender); break; case SecurityControlMessage.MessageType.DHEWithCertificateAndCAs: HandleControlDHEWithCertificateAndCAs(sa, scm, scm_reply, return_path, low_level_sender); break; case SecurityControlMessage.MessageType.DHEWithCertificate: HandleControlDHEWithCertificate(sa, scm, scm_reply, return_path, low_level_sender); break; case SecurityControlMessage.MessageType.Confirm: HandleControlConfirm(sa, scm, scm_reply, return_path, low_level_sender); break; default: throw new Exception("Invalid message!"); } } catch (Exception e) { if (scm.Type == SecurityControlMessage.MessageType.DHEWithCertificateAndCAs || scm.Type == SecurityControlMessage.MessageType.DHEWithCertificate || scm.Type == SecurityControlMessage.MessageType.Confirm) { NoSuchSA(scm.SPI, return_path); } if (sa != null && sa.Closed) { ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, GetHashCode() + " SA closed! " + sa); return; } ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, String.Format( "Error in {0}, unhandled exception from {1}, message: {2}, exception: {3}", GetHashCode(), low_level_sender, scm, e)); } }