コード例 #1
0
        public static LogEntry For(OpenSecureChannelRequest request)
        {
            LogEntry entry = new LogEntry("OpenSecureChannelRequest");

            entry.Add("RequestHeader", For(request.RequestHeader));
            entry.Add("SecurityMode", For(request.SecurityMode));
            return(entry);
        }
コード例 #2
0
        /// <summary>
        /// Handles a reconnect request.
        /// </summary>
        public void Reconnect(
            TcpMessageSocket socket,
            uint requestId,
            uint sequenceNumber,
            X509Certificate2 clientCertificate,
            TcpChannelToken token,
            OpenSecureChannelRequest request)
        {
            if (socket == null)
            {
                throw new ArgumentNullException("socket");
            }

            lock (DataLock)
            {
                // make sure the same client certificate is being used.
                CompareCertificates(ClientCertificate, clientCertificate, false);

                // check for replay attacks.
                if (!VerifySequenceNumber(sequenceNumber, "Reconnect"))
                {
                    throw new ServiceResultException(StatusCodes.BadSequenceNumberInvalid);
                }

                try
                {
                    // replace the socket.
                    Socket = socket;
                    Utils.Trace("TCPSERVERCHANNEL SOCKET RECONNECTED: {0:X8}, ChannelId={1}", Socket.Handle, ChannelId);
                    Socket.ChangeSink(this);

                    // need to assign a new token id.
                    token.TokenId = GetNewTokenId();

                    // put channel back in open state.
                    ActivateToken(token);
                    State = TcpChannelState.Open;

                    // no need to cleanup.
                    if (m_cleanupTimer != null)
                    {
                        m_cleanupTimer.Dispose();
                        m_cleanupTimer = null;
                    }

                    // send response.
                    SendOpenSecureChannelResponse(requestId, token, request);

                    // send any queue responses.
                    ThreadPool.QueueUserWorkItem(new WaitCallback(OnChannelReconnected), m_queuedResponses);
                    m_queuedResponses = new SortedDictionary <uint, IServiceResponse>();
                }
                catch (Exception e)
                {
                    SendServiceFault(token, requestId, ServiceResult.Create(e, StatusCodes.BadTcpInternalError, "Unexpected error processing request."));
                }
            }
        }
コード例 #3
0
 /// <inheritdoc/>
 public void ReportAuditOpenSecureChannelEvent(
     string globalChannelId,
     EndpointDescription endpointDescription,
     OpenSecureChannelRequest request,
     X509Certificate2 clientCertificate,
     Exception exception)
 {
     // trigger the reporting of AuditOpenSecureChannelEventType
     ServerForContext?.ReportAuditOpenSecureChannelEvent(globalChannelId, endpointDescription, request, clientCertificate, exception);
 }
コード例 #4
0
 /// <summary>
 /// Binds a new socket to an existing channel.
 /// </summary>
 public bool ReconnectToExistingChannel(
     IMessageSocket socket,
     uint requestId,
     uint sequenceNumber,
     uint channelId,
     X509Certificate2 clientCertificate,
     ChannelToken token,
     OpenSecureChannelRequest request)
 {
     return(true);
 }
コード例 #5
0
        /// <summary>
        /// Handles a reconnect request.
        /// </summary>
        public override void Reconnect(
            IMessageSocket socket,
            uint requestId,
            uint sequenceNumber,
            X509Certificate2 clientCertificate,
            ChannelToken token,
            OpenSecureChannelRequest request)
        {
            if (socket == null)
            {
                throw new ArgumentNullException(nameof(socket));
            }

            lock (DataLock)
            {
                // make sure the same client certificate is being used.
                CompareCertificates(ClientCertificate, clientCertificate, false);

                // check for replay attacks.
                if (!VerifySequenceNumber(sequenceNumber, "Reconnect"))
                {
                    throw new ServiceResultException(StatusCodes.BadSequenceNumberInvalid);
                }

                try
                {
                    // replace the socket.
                    Socket = socket;
                    Utils.Trace("{0} SOCKET RECONNECTED: {1:X8}, ChannelId={2}", ChannelName, Socket.Handle, ChannelId);
                    Socket.ChangeSink(this);

                    // need to assign a new token id.
                    token.TokenId = GetNewTokenId();

                    // put channel back in open state.
                    ActivateToken(token);
                    State = TcpChannelState.Open;

                    // no need to cleanup.
                    CleanupTimer();

                    // send response.
                    SendOpenSecureChannelResponse(requestId, token, request);

                    // send any queue responses.
                    Task.Factory.StartNew(OnChannelReconnected, m_queuedResponses);
                    m_queuedResponses = new SortedDictionary <uint, IServiceResponse>();
                }
                catch (Exception e)
                {
                    SendServiceFault(token, requestId, ServiceResult.Create(e, StatusCodes.BadTcpInternalError, "Unexpected error processing request."));
                }
            }
        }
コード例 #6
0
        /// <summary>
        /// Send open secure channel service request on transport channel.
        /// </summary>
        /// <param name="request">A service request</param>
        /// <param name="token">A cancellation token</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        private async Task SendOpenSecureChannelRequestAsync(OpenSecureChannelRequest request, CancellationToken token)
        {
            var bodyStream = _streamManager.GetStream("SendOpenSecureChannelRequestAsync");

            using (var bodyEncoder = StackProfile.EncodingProvider.CreateEncoder(bodyStream, this, keepStreamOpen: false))
            {
                bodyEncoder.WriteRequest(request);
                bodyStream.Position = 0;

                var   handle = request.RequestHeader !.RequestHandle;
                await _conversation !.EncryptMessageAsync(bodyStream, MessageTypes.OPNF, handle, SendAsync, token);
            }
        }
コード例 #7
0
        /// <summary>
        /// Sends an OpenSecureChannel response.
        /// </summary>
        private void SendOpenSecureChannelResponse(uint requestId, TcpChannelToken token,
                                                   OpenSecureChannelRequest request)
        {
            // Utils.Trace("Channel {0}: SendOpenSecureChannelResponse()", ChannelId);

            OpenSecureChannelResponse response = new OpenSecureChannelResponse();

            response.ResponseHeader.RequestHandle = request.RequestHeader.RequestHandle;
            response.ResponseHeader.Timestamp     = DateTime.UtcNow;

            response.SecurityToken.ChannelId       = token.ChannelId;
            response.SecurityToken.TokenId         = token.TokenId;
            response.SecurityToken.CreatedAt       = token.CreatedAt;
            response.SecurityToken.RevisedLifetime = (uint)token.Lifetime;
            response.ServerNonce = token.ServerNonce;

            byte[]           buffer       = BinaryEncoder.EncodeMessage(response, Quotas.MessageContext);
            BufferCollection chunksToSend = null;

            if (ServerCertificateChain != null)
            {
                chunksToSend = WriteAsymmetricMessage(
                    TcpMessageType.Open,
                    requestId,
                    ServerCertificateChain,
                    //ServerCertificate,
                    ClientCertificate,
                    new ArraySegment <byte>(buffer, 0, buffer.Length));
            }
            else
            {
                chunksToSend = WriteAsymmetricMessage(
                    TcpMessageType.Open,
                    requestId,
                    //ServerCertificateChain,
                    ServerCertificate,
                    ClientCertificate,
                    new ArraySegment <byte>(buffer, 0, buffer.Length));
            }

            // write the message to the server.
            try {
                BeginWriteMessage(chunksToSend, Int32.MaxValue, null);
                chunksToSend = null;
            } finally {
                if (chunksToSend != null)
                {
                    chunksToSend.Release(BufferManager, "SendOpenSecureChannelResponse");
                }
            }
        }
コード例 #8
0
 /// <summary>
 /// Callback for reporting the open secure channel audit event
 /// </summary>
 private void OnReportAuditOpenSecureChannelEvent(TcpServerChannel channel, OpenSecureChannelRequest request, X509Certificate2 clientCertificate, Exception exception)
 {
     try
     {
         if (m_callback != null)
         {
             m_callback.ReportAuditOpenSecureChannelEvent(channel.GlobalChannelId, channel.EndpointDescription, request, clientCertificate, exception);
         }
     }
     catch (Exception e)
     {
         Utils.LogError(e, "TCPLISTENER - Unexpected error sending OpenSecureChannel Audit event.");
     }
 }
コード例 #9
0
 /// <inheritdoc/>
 public bool ReconnectToExistingChannel(IMessageSocket socket, uint requestId,
                                        uint sequenceNumber, uint channelId, X509Certificate2 clientCertificate,
                                        ChannelToken token, OpenSecureChannelRequest request)
 {
     if (!_channels.TryGetValue(channelId, out var channel))
     {
         throw ServiceResultException.Create(Opc.Ua.StatusCodes.BadTcpSecureChannelUnknown,
                                             "Could not find channel referenced in the OpenSecureChannel request.");
     }
     channel.Reconnect(socket, requestId, sequenceNumber, clientCertificate,
                       token, request);
     _logger.Information("Channel {channelId} reconnected", channelId);
     return(true);
 }
コード例 #10
0
        /// <summary>
        /// Binds a new socket to an existing channel.
        /// </summary>
        internal bool ReconnectToExistingChannel(
            TcpMessageSocket socket,
            uint requestId,
            uint sequenceNumber,
            uint channelId,
            X509Certificate2 clientCertificate,
            TcpChannelToken token,
            OpenSecureChannelRequest request)
        {
            TcpServerChannel channel = null;

            lock (m_lock)
            {
                if (!m_channels.TryGetValue(channelId, out channel))
                {
                    throw ServiceResultException.Create(StatusCodes.BadTcpSecureChannelUnknown, "Could not find secure channel referenced in the OpenSecureChannel request.");
                }
            }

            channel.Reconnect(socket, requestId, sequenceNumber, clientCertificate, token, request);
            return(true);
        }
コード例 #11
0
        /// <summary>
        /// Sends an OpenSecureChannel response.
        /// </summary>
        private void SendOpenSecureChannelResponse(uint requestId, TcpChannelToken token, OpenSecureChannelRequest request)
        {
            // Utils.Trace("Channel {0}: SendOpenSecureChannelResponse()", ChannelId);

            OpenSecureChannelResponse response = new OpenSecureChannelResponse();
            
            response.ResponseHeader.RequestHandle = request.RequestHeader.RequestHandle;
            response.ResponseHeader.Timestamp     = DateTime.UtcNow;

            response.SecurityToken.ChannelId = token.ChannelId;
            response.SecurityToken.TokenId = token.TokenId;
            response.SecurityToken.CreatedAt = token.CreatedAt;
            response.SecurityToken.RevisedLifetime = (uint)token.Lifetime;
            response.ServerNonce = token.ServerNonce;
            
            byte[] buffer = BinaryEncoder.EncodeMessage(response, Quotas.MessageContext); 
            
            BufferCollection chunksToSend = WriteAsymmetricMessage(
                TcpMessageType.Open,
                requestId,
                //ServerCertificateChain,
                ServerCertificate,
                ClientCertificate,
                new ArraySegment<byte>(buffer, 0, buffer.Length));

            // write the message to the server.
            try
            {
                BeginWriteMessage(chunksToSend, Int32.MaxValue, null);
                chunksToSend = null;
            }
            finally
            {
                if (chunksToSend != null)
                {
                    chunksToSend.Release(BufferManager, "SendOpenSecureChannelResponse");
                }
            }
        }      
コード例 #12
0
        /// <summary>
        /// Handles a reconnect request.
        /// </summary>
        public void Reconnect(
            TcpMessageSocket         socket, 
            uint                     requestId,
            uint                     sequenceNumber,
            X509Certificate2         clientCertificate, 
            TcpChannelToken          token,
            OpenSecureChannelRequest request)
        {      
            if (socket == null) throw new ArgumentNullException("socket");
            
            lock (DataLock)
            {
                // make sure the same client certificate is being used.     
                CompareCertificates(ClientCertificate, clientCertificate, false);

                // check for replay attacks.
                if (!VerifySequenceNumber(sequenceNumber, "Reconnect"))
                {
                    throw new ServiceResultException(StatusCodes.BadSequenceNumberInvalid);
                }

                try
                {        
                    // replace the socket.
                    Socket = socket;
                    Utils.Trace("TCPSERVERCHANNEL SOCKET RECONNECTED: {0:X8}, ChannelId={1}", Socket.Handle, ChannelId);
                    Socket.ChangeSink(this);

                    // need to assign a new token id.
                    token.TokenId = GetNewTokenId();

                    // put channel back in open state.
                    ActivateToken(token);
                    State = TcpChannelState.Open;

                    // no need to cleanup.
                    if (m_cleanupTimer != null)
                    {
                        m_cleanupTimer.Dispose();
                        m_cleanupTimer = null;
                    }

                    // send response.
                    SendOpenSecureChannelResponse(requestId, token, request);

                    // send any queue responses.
                    ThreadPool.QueueUserWorkItem(new WaitCallback(OnChannelReconnected), m_queuedResponses);
                    m_queuedResponses = new SortedDictionary<uint,IServiceResponse>();
                }
                catch (Exception e)
                {
                    SendServiceFault(token, requestId, ServiceResult.Create(e, StatusCodes.BadTcpInternalError, "Unexpected error processing request."));
                }
            }
        }
コード例 #13
0
 /// <summary>
 /// Handles a reconnect request.
 /// </summary>
 public virtual void Reconnect(IMessageSocket socket, uint requestId, uint sequenceNumber, X509Certificate2 clientCertificate, ChannelToken token, OpenSecureChannelRequest request)
 {
     throw new NotImplementedException();
 }
コード例 #14
0
        /// <summary>
        /// Processes an OpenSecureChannel request message.
        /// </summary>
        private bool ProcessOpenSecureChannelRequest(uint messageType, ArraySegment <byte> messageChunk)
        {
            // validate the channel state.
            if (State != TcpChannelState.Opening && State != TcpChannelState.Open)
            {
                ForceChannelFault(StatusCodes.BadTcpMessageTypeInvalid, "Client sent an unexpected OpenSecureChannel message.");
                return(false);
            }

            // parse the security header.
            uint             channelId         = 0;
            X509Certificate2 clientCertificate = null;
            uint             requestId         = 0;
            uint             sequenceNumber    = 0;

            ArraySegment <byte> messageBody;

            try
            {
                messageBody = ReadAsymmetricMessage(
                    messageChunk,
                    ServerCertificate,
                    out channelId,
                    out clientCertificate,
                    out requestId,
                    out sequenceNumber);

                // check for replay attacks.
                if (!VerifySequenceNumber(sequenceNumber, "ProcessOpenSecureChannelRequest"))
                {
                    throw new ServiceResultException(StatusCodes.BadSequenceNumberInvalid);
                }
            }
            catch (Exception e)
            {
                ServiceResultException innerException = e.InnerException as ServiceResultException;

                // If the certificate structre, signature and trust list checks pass, we return the other specific validation errors instead of BadSecurityChecksFailed
                if (innerException != null)
                {
                    if (innerException.StatusCode == StatusCodes.BadCertificateUntrusted ||
                        innerException.StatusCode == StatusCodes.BadCertificateChainIncomplete ||
                        innerException.StatusCode == StatusCodes.BadCertificateRevoked ||
                        innerException.StatusCode == StatusCodes.BadCertificateInvalid ||
                        (innerException.InnerResult != null && innerException.InnerResult.StatusCode == StatusCodes.BadCertificateUntrusted))
                    {
                        ForceChannelFault(StatusCodes.BadSecurityChecksFailed, e.Message);
                        return(false);
                    }
                    else if (innerException.StatusCode == StatusCodes.BadCertificateTimeInvalid ||
                             innerException.StatusCode == StatusCodes.BadCertificateIssuerTimeInvalid ||
                             innerException.StatusCode == StatusCodes.BadCertificateHostNameInvalid ||
                             innerException.StatusCode == StatusCodes.BadCertificateUriInvalid ||
                             innerException.StatusCode == StatusCodes.BadCertificateUseNotAllowed ||
                             innerException.StatusCode == StatusCodes.BadCertificateIssuerUseNotAllowed ||
                             innerException.StatusCode == StatusCodes.BadCertificateRevocationUnknown ||
                             innerException.StatusCode == StatusCodes.BadCertificateIssuerRevocationUnknown ||
                             innerException.StatusCode == StatusCodes.BadCertificateIssuerRevoked)
                    {
                        ForceChannelFault(innerException, innerException.StatusCode, e.Message);
                        return(false);
                    }
                }

                ForceChannelFault(e, StatusCodes.BadSecurityChecksFailed, "Could not verify security on OpenSecureChannel request.");
                return(false);
            }

            BufferCollection chunksToProcess = null;

            try
            {
                bool firstCall = ClientCertificate == null;

                // must ensure the same certificate was used.
                if (ClientCertificate != null)
                {
                    CompareCertificates(ClientCertificate, clientCertificate, false);
                }
                else
                {
                    ClientCertificate = clientCertificate;
                }

                // check if it is necessary to wait for more chunks.
                if (!TcpMessageType.IsFinal(messageType))
                {
                    SaveIntermediateChunk(requestId, messageBody);
                    return(false);
                }

                // create a new token.
                ChannelToken token = CreateToken();

                token.TokenId     = GetNewTokenId();
                token.ServerNonce = CreateNonce();

                // get the chunks to process.
                chunksToProcess = GetSavedChunks(requestId, messageBody);

                OpenSecureChannelRequest request = (OpenSecureChannelRequest)BinaryDecoder.DecodeMessage(
                    new ArraySegmentStream(chunksToProcess),
                    typeof(OpenSecureChannelRequest),
                    Quotas.MessageContext);

                if (request == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadStructureMissing, "Could not parse OpenSecureChannel request body.");
                }

                // check the security mode.
                if (request.SecurityMode != SecurityMode)
                {
                    ReviseSecurityMode(firstCall, request.SecurityMode);
                }

                // check the client nonce.
                token.ClientNonce = request.ClientNonce;

                if (!ValidateNonce(token.ClientNonce))
                {
                    throw ServiceResultException.Create(StatusCodes.BadNonceInvalid, "Client nonce is not the correct length or not random enough.");
                }

                // choose the lifetime.
                int lifetime = (int)request.RequestedLifetime;

                if (lifetime < TcpMessageLimits.MinSecurityTokenLifeTime)
                {
                    lifetime = TcpMessageLimits.MinSecurityTokenLifeTime;
                }

                if (lifetime > 0 && lifetime < token.Lifetime)
                {
                    token.Lifetime = lifetime;
                }

                // check the request type.
                SecurityTokenRequestType requestType = request.RequestType;

                if (requestType == SecurityTokenRequestType.Issue && State != TcpChannelState.Opening)
                {
                    throw ServiceResultException.Create(StatusCodes.BadRequestTypeInvalid, "Cannot request a new token for an open channel.");
                }

                if (requestType == SecurityTokenRequestType.Renew && State != TcpChannelState.Open)
                {
                    // may be reconnecting to a dropped channel.
                    if (State == TcpChannelState.Opening)
                    {
                        // tell the listener to find the channel that can process the request.
                        Listener.ReconnectToExistingChannel(
                            Socket,
                            requestId,
                            sequenceNumber,
                            channelId,
                            ClientCertificate,
                            token,
                            request);

                        Utils.Trace(
                            "{0} ReconnectToExistingChannel Socket={0:X8}, ChannelId={1}, TokenId={2}",
                            ChannelName,
                            (Socket != null) ? Socket.Handle : 0,
                            (CurrentToken != null) ? CurrentToken.ChannelId : 0,
                            (CurrentToken != null) ? CurrentToken.TokenId : 0);

                        // close the channel.
                        ChannelClosed();

                        // nothing more to do.
                        return(false);
                    }

                    throw ServiceResultException.Create(StatusCodes.BadRequestTypeInvalid, "Cannot request to renew a token for a channel that has not been opened.");
                }

                // check the channel id.
                if (requestType == SecurityTokenRequestType.Renew && channelId != ChannelId)
                {
                    throw ServiceResultException.Create(StatusCodes.BadTcpSecureChannelUnknown, "Do not recognize the secure channel id provided.");
                }

                // log security information.
                if (requestType == SecurityTokenRequestType.Issue)
                {
                    Opc.Ua.Security.Audit.SecureChannelCreated(
                        m_ImplementationString,
                        Listener.EndpointUrl.ToString(),
                        Utils.Format("{0}", ChannelId),
                        EndpointDescription,
                        ClientCertificate,
                        ServerCertificate,
                        BinaryEncodingSupport.Required);
                }
                else
                {
                    Opc.Ua.Security.Audit.SecureChannelRenewed(
                        m_ImplementationString,
                        Utils.Format("{0}", ChannelId));
                }

                if (requestType == SecurityTokenRequestType.Renew)
                {
                    SetRenewedToken(token);
                }
                else
                {
                    ActivateToken(token);
                }

                State = TcpChannelState.Open;

                // send the response.
                SendOpenSecureChannelResponse(requestId, token, request);

                // notify reverse
                CompleteReverseHello(null);

                // notify any monitors.
                NotifyMonitors(ServiceResult.Good, false);

                return(false);
            }
            catch (Exception e)
            {
                SendServiceFault(requestId, ServiceResult.Create(e, StatusCodes.BadTcpInternalError, "Unexpected error processing OpenSecureChannel request."));
                CompleteReverseHello(e);
                return(false);
            }
            finally
            {
                if (chunksToProcess != null)
                {
                    chunksToProcess.Release(BufferManager, "ProcessOpenSecureChannelRequest");
                }
            }
        }
コード例 #15
0
ファイル: TcpClientChannel.cs プロジェクト: zryska/UA-.NET
        /// <summary>
        /// Sends an OpenSecureChannel request.
        /// </summary>
        private void SendOpenSecureChannelRequest(bool renew)
        {
            // create a new token.
            TcpChannelToken token = CreateToken();
            token.ClientNonce = CreateNonce();
             
            // construct the request.
            OpenSecureChannelRequest request = new OpenSecureChannelRequest();
            request.RequestHeader.Timestamp = DateTime.UtcNow;

            request.RequestType       = (renew)?SecurityTokenRequestType.Renew:SecurityTokenRequestType.Issue;
            request.SecurityMode      = SecurityMode;
            request.ClientNonce       = token.ClientNonce;
            request.RequestedLifetime = (uint)Quotas.SecurityTokenLifetime;
            
            // encode the request.            
            byte[] buffer = BinaryEncoder.EncodeMessage(request, Quotas.MessageContext); 

            // write the asymmetric message.
            BufferCollection chunksToSend = WriteAsymmetricMessage(
                TcpMessageType.Open,
                m_handshakeOperation.RequestId,
                //ClientCertificateChain,
                ClientCertificate,
                ServerCertificate,
                new ArraySegment<byte>(buffer, 0, buffer.Length));

            // save token.
            m_requestedToken = token;
            
            // write the message to the server.
            try
            {
                BeginWriteMessage(chunksToSend, Int32.MaxValue, m_handshakeOperation);
                chunksToSend = null;
            }
            finally
            {
                if (chunksToSend != null)
                {
                    chunksToSend.Release(BufferManager, "SendOpenSecureChannelRequest");
                }
            }
        }             
コード例 #16
0
        private async Task OnRenewAsync(CancellationToken token)
        {
            var openSecureChannelRequest = new OpenSecureChannelRequest
            {
                ClientProtocolVersion = ProtocolVersion,
                RequestType = SecurityTokenRequestType.Renew,
                SecurityMode = this.RemoteEndpoint.SecurityMode,
                ClientNonce = this.symIsSigned ? this.GetNextNonce() : null,
                RequestedLifetime = TokenRequestedLifetime
            };
            var openSecureChannelResponse = (OpenSecureChannelResponse)await this.RequestAsync(openSecureChannelRequest).ConfigureAwait(false);
            if (openSecureChannelResponse.ServerProtocolVersion < ProtocolVersion)
            {
                throw new ServiceResultException(StatusCodes.BadProtocolVersionUnsupported);
            }

            await this.sendingSemaphore.WaitAsync(token).ConfigureAwait(false);
            try
            {
                this.ChannelId = openSecureChannelResponse.SecurityToken.ChannelId;
                this.TokenId = openSecureChannelResponse.SecurityToken.TokenId;
                this.tokenRenewalTime = DateTime.UtcNow.AddMilliseconds(0.75 * openSecureChannelResponse.SecurityToken.RevisedLifetime);
                if (this.symIsSigned)
                {
                    var clientNonce = openSecureChannelRequest.ClientNonce;
                    var serverNonce = openSecureChannelResponse.ServerNonce;

                    // (re)create client security keys for encrypting the next message sent
                    var clientSecurityKey = CalculatePSHA(serverNonce, clientNonce, this.symSignatureKeySize + this.symEncryptionKeySize + this.symEncryptionBlockSize, this.asymSignatureHashAlgorithmName);
                    Buffer.BlockCopy(clientSecurityKey, 0, this.clientSigningKey, 0, this.symSignatureKeySize);
                    Buffer.BlockCopy(clientSecurityKey, this.symSignatureKeySize, this.clientEncryptingKey, 0, this.symEncryptionKeySize);
                    Buffer.BlockCopy(clientSecurityKey, this.symSignatureKeySize + this.symEncryptionKeySize, this.clientInitializationVector, 0, this.symEncryptionBlockSize);

                    // (re)create server security keys for decrypting the next message received that has a new TokenId
                    var serverSecurityKey = CalculatePSHA(clientNonce, serverNonce, this.symSignatureKeySize + this.symEncryptionKeySize + this.symEncryptionBlockSize, this.asymSignatureHashAlgorithmName);
                    Buffer.BlockCopy(serverSecurityKey, 0, this.serverSigningKey, 0, this.symSignatureKeySize);
                    Buffer.BlockCopy(serverSecurityKey, this.symSignatureKeySize, this.serverEncryptingKey, 0, this.symEncryptionKeySize);
                    Buffer.BlockCopy(serverSecurityKey, this.symSignatureKeySize + this.symEncryptionKeySize, this.serverInitializationVector, 0, this.symEncryptionBlockSize);
                }
            }
            finally
            {
                this.sendingSemaphore.Release();
            }
        }
コード例 #17
0
ファイル: TcpListener.cs プロジェクト: yuriik83/UA-.NET
        /// <summary>
        /// Binds a new socket to an existing channel.
        /// </summary>
        internal bool ReconnectToExistingChannel(
            TcpMessageSocket         socket, 
            uint                     requestId,
            uint                     sequenceNumber,
            uint                     channelId,
            X509Certificate2         clientCertificate, 
            TcpChannelToken          token,
            OpenSecureChannelRequest request)
        {            
            TcpServerChannel channel = null;

            lock (m_lock)
            {
                if (!m_channels.TryGetValue(channelId, out channel))
                {
                    throw ServiceResultException.Create(StatusCodes.BadTcpSecureChannelUnknown, "Could not find secure channel referenced in the OpenSecureChannel request.");
                }
            }
                       
            channel.Reconnect(socket, requestId, sequenceNumber, clientCertificate, token, request);
            // Utils.Trace("Channel {0} reconnected", channelId);
            return true;
        }
コード例 #18
0
ファイル: Opc.Ua.Messages.cs プロジェクト: yuriik83/UA-.NET
 /// <summary>
 /// Initializes the message with the body.
 /// </summary>
 public OpenSecureChannelMessage(OpenSecureChannelRequest OpenSecureChannelRequest)
 {
     this.OpenSecureChannelRequest = OpenSecureChannelRequest;
 }
コード例 #19
0
 bool ITcpChannelListener.ReconnectToExistingChannel(IMessageSocket socket, uint requestId, uint sequenceNumber, uint channelId, X509Certificate2 clientCertificate, ChannelToken token, OpenSecureChannelRequest request)
 {
     throw new NotImplementedException();
 }
コード例 #20
0
        protected override async Task OnOpenAsync(CancellationToken token)
        {
            await base.OnOpenAsync(token).ConfigureAwait(false);
            token.ThrowIfCancellationRequested();
            this.sendBuffer = new byte[this.LocalSendBufferSize];
            this.receiveBuffer = new byte[this.LocalReceiveBufferSize];
            if (this.LocalCertificate != null)
            {
                this.localCertificateBlob = this.LocalCertificate.RawData;
            }

            this.remoteCertificateBlob = this.RemoteEndpoint.ServerCertificate;
            if (this.remoteCertificateBlob != null)
            {
                this.RemoteCertificate = new X509Certificate2(this.remoteCertificateBlob);
            }

            if (this.RemoteEndpoint.SecurityMode == MessageSecurityMode.SignAndEncrypt)
            {
                if (this.LocalCertificate == null)
                {
                    throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "LocalCertificate is null.");
                }

                if (this.RemoteCertificate == null)
                {
                    throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "RemoteCertificate is null.");
                }

                this.LocalPrivateKey = this.LocalCertificate.GetRSAPrivateKey();
                this.RemotePublicKey = this.RemoteCertificate.GetRSAPublicKey();

                switch (this.RemoteEndpoint.SecurityPolicyUri)
                {
                    case SecurityPolicyUris.Basic128Rsa15:

                        this.asymEncryptionPadding = RSAEncryptionPadding.Pkcs1;
                        this.asymSignatureHashAlgorithmName = HashAlgorithmName.SHA1;
                        this.symSigner = new HMACSHA1();
                        this.symVerifier = new HMACSHA1();
                        this.symEncryptionAlgorithm = Aes.Create();
                        this.symEncryptionAlgorithm.Mode = CipherMode.CBC;
                        this.symEncryptionAlgorithm.Padding = PaddingMode.None;
                        this.asymLocalKeySize = this.LocalPrivateKey.KeySize;
                        this.asymRemoteKeySize = this.RemotePublicKey.KeySize;
                        this.asymLocalPlainTextBlockSize = Math.Max((this.asymLocalKeySize / 8) - 11, 1);
                        this.asymRemotePlainTextBlockSize = Math.Max((this.asymRemoteKeySize / 8) - 11, 1);
                        this.symSignatureSize = 20;
                        this.symSignatureKeySize = 16;
                        this.symEncryptionBlockSize = 16;
                        this.symEncryptionKeySize = 16;
                        break;

                    case SecurityPolicyUris.Basic256:

                        this.asymEncryptionPadding = RSAEncryptionPadding.OaepSHA1;
                        this.asymSignatureHashAlgorithmName = HashAlgorithmName.SHA1;
                        this.symSigner = new HMACSHA1();
                        this.symVerifier = new HMACSHA1();
                        this.symEncryptionAlgorithm = Aes.Create();
                        this.symEncryptionAlgorithm.Mode = CipherMode.CBC;
                        this.symEncryptionAlgorithm.Padding = PaddingMode.None;
                        this.asymLocalKeySize = this.LocalPrivateKey.KeySize;
                        this.asymRemoteKeySize = this.RemotePublicKey.KeySize;
                        this.asymLocalPlainTextBlockSize = Math.Max((this.asymLocalKeySize / 8) - 42, 1);
                        this.asymRemotePlainTextBlockSize = Math.Max((this.asymRemoteKeySize / 8) - 42, 1);
                        this.symSignatureSize = 20;
                        this.symSignatureKeySize = 24;
                        this.symEncryptionBlockSize = 16;
                        this.symEncryptionKeySize = 32;
                        break;

                    case SecurityPolicyUris.Basic256Sha256:

                        this.asymEncryptionPadding = RSAEncryptionPadding.OaepSHA1;
                        this.asymSignatureHashAlgorithmName = HashAlgorithmName.SHA256;
                        this.symSigner = new HMACSHA256();
                        this.symVerifier = new HMACSHA256();
                        this.symEncryptionAlgorithm = Aes.Create();
                        this.symEncryptionAlgorithm.Mode = CipherMode.CBC;
                        this.symEncryptionAlgorithm.Padding = PaddingMode.None;
                        this.asymLocalKeySize = this.LocalPrivateKey.KeySize;
                        this.asymRemoteKeySize = this.RemotePublicKey.KeySize;
                        this.asymLocalPlainTextBlockSize = Math.Max((this.asymLocalKeySize / 8) - 42, 1);
                        this.asymRemotePlainTextBlockSize = Math.Max((this.asymRemoteKeySize / 8) - 42, 1);
                        this.symSignatureSize = 32;
                        this.symSignatureKeySize = 32;
                        this.symEncryptionBlockSize = 16;
                        this.symEncryptionKeySize = 32;
                        break;

                    default:
                        throw new ServiceResultException(StatusCodes.BadSecurityPolicyRejected);
                }

                this.asymIsSigned = this.asymIsEncrypted = true;
                this.symIsSigned = true;
                this.symIsEncrypted = true;
                this.asymLocalSignatureSize = this.asymLocalKeySize / 8;
                this.asymLocalCipherTextBlockSize = Math.Max(this.asymLocalKeySize / 8, 1);
                this.asymRemoteSignatureSize = this.asymRemoteKeySize / 8;
                this.asymRemoteCipherTextBlockSize = Math.Max(this.asymRemoteKeySize / 8, 1);
                this.clientSigningKey = new byte[this.symSignatureKeySize];
                this.clientEncryptingKey = new byte[this.symEncryptionKeySize];
                this.clientInitializationVector = new byte[this.symEncryptionBlockSize];
                this.serverSigningKey = new byte[this.symSignatureKeySize];
                this.serverEncryptingKey = new byte[this.symEncryptionKeySize];
                this.serverInitializationVector = new byte[this.symEncryptionBlockSize];
                this.encryptionBuffer = new byte[this.LocalSendBufferSize];
            }
            else if (this.RemoteEndpoint.SecurityMode == MessageSecurityMode.Sign)
            {
                if (this.LocalCertificate == null)
                {
                    throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "LocalCertificate is null.");
                }

                if (this.RemoteCertificate == null)
                {
                    throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "RemoteCertificate is null.");
                }

                this.LocalPrivateKey = this.LocalCertificate.GetRSAPrivateKey();
                this.RemotePublicKey = this.RemoteCertificate.GetRSAPublicKey();

                switch (this.RemoteEndpoint.SecurityPolicyUri)
                {
                    case SecurityPolicyUris.Basic128Rsa15:

                        this.asymEncryptionPadding = RSAEncryptionPadding.Pkcs1;
                        this.asymSignatureHashAlgorithmName = HashAlgorithmName.SHA1;
                        this.symSigner = new HMACSHA1();
                        this.symVerifier = new HMACSHA1();
                        this.asymLocalKeySize = this.LocalPrivateKey.KeySize;
                        this.asymRemoteKeySize = this.RemotePublicKey.KeySize;
                        this.asymLocalPlainTextBlockSize = Math.Max((this.asymLocalKeySize / 8) - 11, 1);
                        this.asymRemotePlainTextBlockSize = Math.Max((this.asymRemoteKeySize / 8) - 11, 1);
                        this.symSignatureSize = 20;
                        this.symSignatureKeySize = 16;
                        this.symEncryptionBlockSize = 16;
                        this.symEncryptionKeySize = 16;
                        break;

                    case SecurityPolicyUris.Basic256:

                        this.asymEncryptionPadding = RSAEncryptionPadding.OaepSHA1;
                        this.asymSignatureHashAlgorithmName = HashAlgorithmName.SHA1;
                        this.symSigner = new HMACSHA1();
                        this.symVerifier = new HMACSHA1();
                        this.asymLocalKeySize = this.LocalPrivateKey.KeySize;
                        this.asymRemoteKeySize = this.RemotePublicKey.KeySize;
                        this.asymLocalPlainTextBlockSize = Math.Max((this.asymLocalKeySize / 8) - 42, 1);
                        this.asymRemotePlainTextBlockSize = Math.Max((this.asymRemoteKeySize / 8) - 42, 1);
                        this.symSignatureSize = 20;
                        this.symSignatureKeySize = 24;
                        this.symEncryptionBlockSize = 16;
                        this.symEncryptionKeySize = 32;
                        break;

                    case SecurityPolicyUris.Basic256Sha256:

                        this.asymEncryptionPadding = RSAEncryptionPadding.OaepSHA1;
                        this.asymSignatureHashAlgorithmName = HashAlgorithmName.SHA256;
                        this.symSigner = new HMACSHA256();
                        this.symVerifier = new HMACSHA256();
                        this.asymLocalKeySize = this.LocalPrivateKey.KeySize;
                        this.asymRemoteKeySize = this.RemotePublicKey.KeySize;
                        this.asymLocalPlainTextBlockSize = Math.Max((this.asymLocalKeySize / 8) - 42, 1);
                        this.asymRemotePlainTextBlockSize = Math.Max((this.asymRemoteKeySize / 8) - 42, 1);
                        this.symSignatureSize = 32;
                        this.symSignatureKeySize = 32;
                        this.symEncryptionBlockSize = 16;
                        this.symEncryptionKeySize = 32;
                        break;

                    default:
                        throw new ServiceResultException(StatusCodes.BadSecurityPolicyRejected);
                }

                this.asymIsSigned = this.asymIsEncrypted = true;
                this.symIsSigned = true;
                this.symIsEncrypted = false;
                this.asymLocalSignatureSize = this.asymLocalKeySize / 8;
                this.asymLocalCipherTextBlockSize = Math.Max(this.asymLocalKeySize / 8, 1);
                this.asymRemoteSignatureSize = this.asymRemoteKeySize / 8;
                this.asymRemoteCipherTextBlockSize = Math.Max(this.asymRemoteKeySize / 8, 1);
                this.clientSigningKey = new byte[this.symSignatureKeySize];
                this.clientEncryptingKey = new byte[this.symEncryptionKeySize];
                this.clientInitializationVector = new byte[this.symEncryptionBlockSize];
                this.serverSigningKey = new byte[this.symSignatureKeySize];
                this.serverEncryptingKey = new byte[this.symEncryptionKeySize];
                this.serverInitializationVector = new byte[this.symEncryptionBlockSize];
                this.encryptionBuffer = new byte[this.LocalSendBufferSize];
            }
            else if (this.RemoteEndpoint.SecurityMode == MessageSecurityMode.None)
            {
                this.asymIsSigned = this.asymIsEncrypted = false;
                this.symIsSigned = this.symIsEncrypted = false;
                this.asymLocalKeySize = 0;
                this.asymRemoteKeySize = 0;
                this.asymLocalSignatureSize = 0;
                this.asymLocalCipherTextBlockSize = 1;
                this.asymRemoteSignatureSize = 0;
                this.asymRemoteCipherTextBlockSize = 1;
                this.asymLocalPlainTextBlockSize = 1;
                this.asymRemotePlainTextBlockSize = 1;
                this.symSignatureSize = 0;
                this.symSignatureKeySize = 0;
                this.symEncryptionBlockSize = 1;
                this.symEncryptionKeySize = 0;
                this.encryptionBuffer = null;
            }
            else
            {
                throw new ServiceResultException(StatusCodes.BadSecurityModeRejected);
            }

            this.sendRequestsTask = Task.Run(() => this.SendRequestsAsync(this.channelCts.Token));
            this.receiveResponsesTask = Task.Run(() => this.ReceiveResponsesAsync(this.channelCts.Token));

            var openSecureChannelRequest = new OpenSecureChannelRequest
            {
                ClientProtocolVersion = ProtocolVersion,
                RequestType = SecurityTokenRequestType.Issue,
                SecurityMode = this.RemoteEndpoint.SecurityMode,
                ClientNonce = this.symIsSigned ? this.GetNextNonce() : null,
                RequestedLifetime = TokenRequestedLifetime
            };
            var openSecureChannelResponse = (OpenSecureChannelResponse)await this.RequestAsync(openSecureChannelRequest).ConfigureAwait(false);
            if (openSecureChannelResponse.ServerProtocolVersion < ProtocolVersion)
            {
                throw new ServiceResultException(StatusCodes.BadProtocolVersionUnsupported);
            }

            await this.sendingSemaphore.WaitAsync(token).ConfigureAwait(false);
            try
            {
                this.ChannelId = openSecureChannelResponse.SecurityToken.ChannelId;
                this.TokenId = openSecureChannelResponse.SecurityToken.TokenId;
                this.tokenRenewalTime = DateTime.UtcNow.AddMilliseconds(0.75 * openSecureChannelResponse.SecurityToken.RevisedLifetime);
                if (this.symIsSigned)
                {
                    var clientNonce = openSecureChannelRequest.ClientNonce;
                    var serverNonce = openSecureChannelResponse.ServerNonce;

                    // (re)create client security keys for encrypting the next message sent
                    var clientSecurityKey = CalculatePSHA(serverNonce, clientNonce, this.symSignatureKeySize + this.symEncryptionKeySize + this.symEncryptionBlockSize, this.asymSignatureHashAlgorithmName);

                    Buffer.BlockCopy(clientSecurityKey, 0, this.clientSigningKey, 0, this.symSignatureKeySize);
                    Buffer.BlockCopy(clientSecurityKey, this.symSignatureKeySize, this.clientEncryptingKey, 0, this.symEncryptionKeySize);
                    Buffer.BlockCopy(clientSecurityKey, this.symSignatureKeySize + this.symEncryptionKeySize, this.clientInitializationVector, 0, this.symEncryptionBlockSize);

                    // (re)create server security keys for decrypting the next message received that has a new TokenId
                    var serverSecurityKey = CalculatePSHA(clientNonce, serverNonce, this.symSignatureKeySize + this.symEncryptionKeySize + this.symEncryptionBlockSize, this.asymSignatureHashAlgorithmName);
                    Buffer.BlockCopy(serverSecurityKey, 0, this.serverSigningKey, 0, this.symSignatureKeySize);
                    Buffer.BlockCopy(serverSecurityKey, this.symSignatureKeySize, this.serverEncryptingKey, 0, this.symEncryptionKeySize);
                    Buffer.BlockCopy(serverSecurityKey, this.symSignatureKeySize + this.symEncryptionKeySize, this.serverInitializationVector, 0, this.symEncryptionBlockSize);
                }
            }
            finally
            {
                this.sendingSemaphore.Release();
            }
        }
コード例 #21
0
        private async Task SendOpenSecureChannelRequestAsync(OpenSecureChannelRequest request, CancellationToken token)
        {
            var bodyStream = SerializableBytes.CreateWritableStream();
            var bodyEncoder = new BinaryEncoder(bodyStream, this);
            try
            {
                bodyEncoder.WriteNodeId(null, OpenSecureChannelRequestNodeId);
                request.Encode(bodyEncoder);
                bodyStream.Position = 0;
                if (bodyStream.Length > this.RemoteMaxMessageSize)
                {
                    throw new ServiceResultException(StatusCodes.BadEncodingLimitsExceeded);
                }

                // write chunks
                int chunkCount = 0;
                int bodyCount = (int)(bodyStream.Length - bodyStream.Position);
                while (bodyCount > 0)
                {
                    chunkCount++;
                    if (this.RemoteMaxChunkCount > 0 && chunkCount > this.RemoteMaxChunkCount)
                    {
                        throw new ServiceResultException(StatusCodes.BadEncodingLimitsExceeded);
                    }

                    var stream = new MemoryStream(this.sendBuffer, 0, (int)this.RemoteReceiveBufferSize, true, true);
                    var encoder = new BinaryEncoder(stream, this);
                    try
                    {
                        // header
                        encoder.WriteUInt32(null, UaTcpMessageTypes.OPNF);
                        encoder.WriteUInt32(null, 0u);
                        encoder.WriteUInt32(null, this.ChannelId);

                        // asymmetric security header
                        encoder.WriteString(null, this.RemoteEndpoint.SecurityPolicyUri);
                        if (this.RemoteEndpoint.SecurityMode != MessageSecurityMode.None)
                        {
                            encoder.WriteByteString(null, this.localCertificateBlob);
                            encoder.WriteByteString(null, this.RemoteCertificate.GetCertHash());
                        }
                        else
                        {
                            encoder.WriteByteString(null, null);
                            encoder.WriteByteString(null, null);
                        }

                        int plainHeaderSize = encoder.Position;

                        // sequence header
                        encoder.WriteUInt32(null, this.GetNextSequenceNumber());
                        encoder.WriteUInt32(null, request.RequestHeader.RequestHandle);

                        // body
                        int paddingHeaderSize;
                        int maxBodySize;
                        int bodySize;
                        int paddingSize;
                        int chunkSize;
                        if (this.asymIsEncrypted)
                        {
                            paddingHeaderSize = this.asymRemoteCipherTextBlockSize > 256 ? 2 : 1;
                            maxBodySize = ((((int)this.RemoteReceiveBufferSize - plainHeaderSize - this.asymLocalSignatureSize - paddingHeaderSize) / this.asymRemoteCipherTextBlockSize) * this.asymRemotePlainTextBlockSize) - SequenceHeaderSize;
                            if (bodyCount < maxBodySize)
                            {
                                bodySize = bodyCount;
                                paddingSize = (this.asymRemotePlainTextBlockSize - ((SequenceHeaderSize + bodySize + paddingHeaderSize + this.asymLocalSignatureSize) % this.asymRemotePlainTextBlockSize)) % this.asymRemotePlainTextBlockSize;
                            }
                            else
                            {
                                bodySize = maxBodySize;
                                paddingSize = 0;
                            }

                            chunkSize = plainHeaderSize + (((SequenceHeaderSize + bodySize + paddingSize + paddingHeaderSize + this.asymLocalSignatureSize) / this.asymRemotePlainTextBlockSize) * this.asymRemoteCipherTextBlockSize);
                        }
                        else
                        {
                            paddingHeaderSize = 0;
                            paddingSize = 0;
                            maxBodySize = (int)this.RemoteReceiveBufferSize - plainHeaderSize - this.asymLocalSignatureSize - SequenceHeaderSize;
                            if (bodyCount < maxBodySize)
                            {
                                bodySize = bodyCount;
                            }
                            else
                            {
                                bodySize = maxBodySize;
                            }

                            chunkSize = plainHeaderSize + SequenceHeaderSize + bodySize + this.asymLocalSignatureSize;
                        }

                        bodyStream.Read(this.sendBuffer, encoder.Position, bodySize);
                        encoder.Position += bodySize;
                        bodyCount -= bodySize;

                        // padding
                        if (this.asymIsEncrypted)
                        {
                            byte paddingByte = (byte)(paddingSize & 0xFF);
                            encoder.WriteByte(null, paddingByte);
                            for (int i = 0; i < paddingSize; i++)
                            {
                                encoder.WriteByte(null, paddingByte);
                            }

                            if (paddingHeaderSize == 2)
                            {
                                byte extraPaddingByte = (byte)((paddingSize >> 8) & 0xFF);
                                encoder.WriteByte(null, extraPaddingByte);
                            }
                        }

                        // update message type and (encrypted) length
                        var position = encoder.Position;
                        encoder.Position = 3;
                        encoder.WriteByte(null, bodyCount > 0 ? (byte)'C' : (byte)'F');
                        encoder.WriteUInt32(null, (uint)chunkSize);
                        encoder.Position = position;

                        // sign
                        if (this.asymIsSigned)
                        {
                            // sign with local private key.
                            byte[] signature = this.LocalPrivateKey.SignData(this.sendBuffer, 0, position, this.asymSignatureHashAlgorithmName, RSASignaturePadding.Pkcs1);
                            Debug.Assert(signature.Length == this.asymLocalSignatureSize, nameof(this.asymLocalSignatureSize));
                            encoder.Write(signature, 0, this.asymLocalSignatureSize);
                        }

                        // encrypt
                        if (this.asymIsEncrypted)
                        {
                            position = encoder.Position;
                            Buffer.BlockCopy(this.sendBuffer, 0, this.encryptionBuffer, 0, plainHeaderSize);
                            byte[] plainText = new byte[this.asymRemotePlainTextBlockSize];
                            int jj = plainHeaderSize;
                            for (int ii = plainHeaderSize; ii < position; ii += this.asymRemotePlainTextBlockSize)
                            {
                                Buffer.BlockCopy(this.sendBuffer, ii, plainText, 0, this.asymRemotePlainTextBlockSize);

                                // encrypt with remote public key.
                                byte[] cipherText = this.RemotePublicKey.Encrypt(plainText, this.asymEncryptionPadding);
                                Debug.Assert(cipherText.Length == this.asymRemoteCipherTextBlockSize, nameof(this.asymRemoteCipherTextBlockSize));
                                Buffer.BlockCopy(cipherText, 0, this.encryptionBuffer, jj, this.asymRemoteCipherTextBlockSize);
                                jj += this.asymRemoteCipherTextBlockSize;
                            }

                            await this.SendAsync(this.encryptionBuffer, 0, jj, token).ConfigureAwait(false);
                            return;
                        }

                        // pass buffer to transport
                        await this.SendAsync(this.sendBuffer, 0, encoder.Position, token).ConfigureAwait(false);
                    }
                    finally
                    {
                        encoder.Dispose();
                    }
                }
            }
            finally
            {
                bodyEncoder.Dispose();
            }
        }