private bool ProcessOpenSecureChannelResponse(uint messageType, ArraySegment<byte> messageChunk)
{
Utils.Trace("Channel {0}: ProcessOpenSecureChannelResponse()", ChannelId);
// validate the channel state.
if (State != TcpChannelState.Opening && State != TcpChannelState.Open)
{
ForceReconnect(ServiceResult.Create(StatusCodes.BadTcpMessageTypeInvalid, "Server sent an unexpected OpenSecureChannel response."));
return false;
}
// check if operation was abandoned.
if (m_handshakeOperation == null)
{
return false;
}
// parse the security header.
uint channelId = 0;
X509Certificate2 serverCertificate = null;
uint requestId = 0;
uint sequenceNumber = 0;
ArraySegment<byte> messageBody;
try
{
messageBody = ReadAsymmetricMessage(
messageChunk,
ClientCertificate,
out channelId,
out serverCertificate,
out requestId,
out sequenceNumber);
}
catch (Exception e)
{
ForceReconnect(ServiceResult.Create(e, StatusCodes.BadSecurityChecksFailed, "Could not verify security on OpenSecureChannel response."));
return false;
}
BufferCollection chunksToProcess = null;
try
{
// verify server certificate.
CompareCertificates(ServerCertificate, serverCertificate, true);
// verify sequence number.
ResetSequenceNumber(sequenceNumber);
// check if it is necessary to wait for more chunks.
if (!TcpMessageType.IsFinal(messageType))
{
SaveIntermediateChunk(requestId, messageBody);
return false;
}
// get the chunks to process.
chunksToProcess = GetSavedChunks(requestId, messageBody);
// read message body.
OpenSecureChannelResponse response = ParseResponse(chunksToProcess) as OpenSecureChannelResponse;
if (response == null)
{
throw ServiceResultException.Create(StatusCodes.BadTypeMismatch, "Server did not return a valid OpenSecureChannelResponse.");
}
// the client needs to use the creation time assigned when it sent
// the request and ignores the creation time in the response because
// the server and client clocks may not be synchronized.
// update token.
m_requestedToken.TokenId = response.SecurityToken.TokenId;
m_requestedToken.Lifetime = (int)response.SecurityToken.RevisedLifetime;
m_requestedToken.ServerNonce = response.ServerNonce;
// log security information.
if (State == TcpChannelState.Opening)
{
Opc.Ua.Security.Audit.SecureChannelCreated(
g_ImplementationString,
this.m_url.ToString(),
Utils.Format("{0}", channelId),
this.EndpointDescription,
this.ClientCertificate,
serverCertificate,
BinaryEncodingSupport.Required);
}
else
{
Opc.Ua.Security.Audit.SecureChannelRenewed(
g_ImplementationString,
Utils.Format("{0}", channelId));
}
ChannelId = m_requestedToken.ChannelId = channelId;
ActivateToken(m_requestedToken);
m_requestedToken = null;
// ready to send requests.
State = TcpChannelState.Open;
m_reconnecting = false;
// enable reconnects.
m_waitBetweenReconnects = Timeout.Infinite;
// m_waitBetweenReconnects = TcpMessageLimits.MinTimeBetweenReconnects;
// schedule reconnect before token expires.
ScheduleTokenRenewal(CurrentToken);
// connect finally complete.
m_handshakeOperation.Complete(0);
}
catch (Exception e)
{
m_handshakeOperation.Fault(e, StatusCodes.BadTcpInternalError, "Could not process OpenSecureChannelResponse.");
}
finally
{
if (chunksToProcess != null)
{
chunksToProcess.Release(BufferManager, "ProcessOpenSecureChannelResponse");
}
}
return false;
}
#endregion