/// <summary cref="ChannelFactoryBase{T}.OnCreateChannel" /> protected override IRequestSessionChannel OnCreateChannel(EndpointAddress address, Uri via) { X509Certificate2 clientCertificate = null; if (m_credentials.ClientCertificate.Certificate != null) { clientCertificate = m_credentials.ClientCertificate.Certificate; } X509Certificate2 serverCertificate = null; if (m_endpointDescription != null) { serverCertificate = CertificateFactory.Create(m_endpointDescription.ServerCertificate, true); } UaTcpRequestChannel channel = new UaTcpRequestChannel( this, m_id, address, via, m_bufferManager, m_quotas, clientCertificate, serverCertificate, m_endpointDescription); return(channel); }
/// <summary> /// Initializes the listener from a binding element. /// </summary> internal UaTcpChannelListener(UaTcpTransportBindingElement bindingElement, BindingContext context) : base(context.Binding) { // assign a unique guid to the listener. m_listenerId = Guid.NewGuid().ToString(); SetUri(context.ListenUriBaseAddress, context.ListenUriRelativeAddress); m_descriptions = bindingElement.Descriptions; m_configuration = bindingElement.Configuration; m_quotas = new TcpChannelQuotas(); m_quotas.MaxBufferSize = m_configuration.MaxBufferSize; m_quotas.MaxMessageSize = m_configuration.MaxMessageSize; m_quotas.ChannelLifetime = m_configuration.ChannelLifetime; m_quotas.SecurityTokenLifetime = m_configuration.SecurityTokenLifetime; m_quotas.MessageContext = bindingElement.MessageContext; foreach (object parameter in context.BindingParameters) { ServiceCredentials credentials = parameter as ServiceCredentials; if (credentials != null) { // TBD - paste the cert with the private key with the additional chain. m_serverCertificate = CertificateFactory.Create(credentials.ServiceCertificate.Certificate, credentials.ServiceCertificate.Certificate); m_quotas.CertificateValidator = credentials.ClientCertificate.Authentication.CustomCertificateValidator; } } m_bufferManager = new BufferManager("Server", (int)bindingElement.MaxBufferPoolSize, m_quotas.MaxBufferSize); m_channels = new Dictionary <uint, TcpServerChannel>(); m_channelQueue = new Queue <UaTcpReplyChannel>(); m_acceptQueue = new Queue <TcpAsyncOperation <IReplySessionChannel> >(); // link the channel directly to the server. // this is a hack designed to work around a bug in the WCF framework that results in lost requests during stress testing. if (bindingElement.ServiceHost != null) { if (bindingElement.ServiceHost.Server is DiscoveryServerBase) { m_callback = new DiscoveryEndpoint(bindingElement.ServiceHost); } else { m_callback = new SessionEndpoint(bindingElement.ServiceHost); } } }
/// <summary> /// Displays the dialog. /// </summary> public bool ShowDialog(EndpointDescription endpoint) { if (endpoint == null) { throw new ArgumentNullException("endpoint"); } EndpointTB.Text = endpoint.EndpointUrl; ServerNameTB.Text = endpoint.Server.ApplicationName.Text; ServerUriTB.Text = endpoint.Server.ApplicationUri; try { X509Certificate2 certificate = CertificateFactory.Create(endpoint.ServerCertificate, true); ServerCertificateTB.Text = String.Format("{0}", certificate.Subject); } catch { ServerCertificateTB.Text = "<bad certificate>"; } SecurityModeTB.Text = String.Format("{0}", endpoint.SecurityMode);; SecurityPolicyUriTB.Text = String.Format("{0}", endpoint.SecurityPolicyUri); UserIdentityTypeTB.Text = ""; foreach (UserTokenPolicy policy in endpoint.UserIdentityTokens) { UserIdentityTypeTB.Text += String.Format("{0} ", policy.TokenType); } if (ShowDialog() != DialogResult.OK) { return(false); } return(true); }
/// <summary> /// Validates the identity token supplied by the client. /// </summary> private UserIdentityToken ValidateUserIdentityToken( ExtensionObject identityToken, SignatureData userTokenSignature, out UserTokenPolicy policy) { policy = null; // check for empty token. if (identityToken == null || identityToken.Body == null) { // not changing the token if already activated. if (m_activated) { return(null); } // check if an anonymous login is permitted. if (m_endpoint.UserIdentityTokens != null && m_endpoint.UserIdentityTokens.Count > 0) { bool found = false; for (int ii = 0; ii < m_endpoint.UserIdentityTokens.Count; ii++) { if (m_endpoint.UserIdentityTokens[ii].TokenType == UserTokenType.Anonymous) { found = true; policy = m_endpoint.UserIdentityTokens[ii]; break; } } if (!found) { throw ServiceResultException.Create(StatusCodes.BadUserAccessDenied, "Anonymous user token policy not supported."); } } // create an anonymous token to use for subsequent validation. AnonymousIdentityToken anonymousToken = new AnonymousIdentityToken(); anonymousToken.PolicyId = policy.PolicyId; return(anonymousToken); } UserIdentityToken token = null; // check for unrecognized token. if (!typeof(UserIdentityToken).IsInstanceOfType(identityToken.Body)) { //handle the use case when the UserIdentityToken is binary encoded over xml message encoding if (identityToken.Encoding == ExtensionObjectEncoding.Binary && typeof(byte[]).IsInstanceOfType(identityToken.Body)) { UserIdentityToken newToken = BaseVariableState.DecodeExtensionObject(null, typeof(UserIdentityToken), identityToken, false) as UserIdentityToken; if (newToken == null) { throw ServiceResultException.Create(StatusCodes.BadUserAccessDenied, "Invalid user identity token provided."); } policy = m_endpoint.FindUserTokenPolicy(newToken.PolicyId); if (policy == null) { throw ServiceResultException.Create(StatusCodes.BadUserAccessDenied, "User token policy not supported.", "Opc.Ua.Server.Session.ValidateUserIdentityToken"); } switch (policy.TokenType) { case UserTokenType.Anonymous: token = BaseVariableState.DecodeExtensionObject(null, typeof(AnonymousIdentityToken), identityToken, true) as AnonymousIdentityToken; break; case UserTokenType.UserName: token = BaseVariableState.DecodeExtensionObject(null, typeof(UserNameIdentityToken), identityToken, true) as UserNameIdentityToken; break; case UserTokenType.Certificate: token = BaseVariableState.DecodeExtensionObject(null, typeof(X509IdentityToken), identityToken, true) as X509IdentityToken; break; case UserTokenType.IssuedToken: token = BaseVariableState.DecodeExtensionObject(null, typeof(IssuedIdentityToken), identityToken, true) as IssuedIdentityToken; break; default: throw ServiceResultException.Create(StatusCodes.BadUserAccessDenied, "Invalid user identity token provided."); } } else { throw ServiceResultException.Create(StatusCodes.BadUserAccessDenied, "Invalid user identity token provided."); } } else { // get the token. token = (UserIdentityToken)identityToken.Body; } // find the user token policy. policy = m_endpoint.FindUserTokenPolicy(token.PolicyId); if (policy == null) { throw ServiceResultException.Create(StatusCodes.BadIdentityTokenInvalid, "User token policy not supported."); } // determine the security policy uri. string securityPolicyUri = policy.SecurityPolicyUri; if (String.IsNullOrEmpty(securityPolicyUri)) { securityPolicyUri = m_endpoint.SecurityPolicyUri; } if (ServerBase.RequireEncryption(m_endpoint)) { // decrypt the token. if (m_serverCertificate == null) { m_serverCertificate = CertificateFactory.Create(m_endpoint.ServerCertificate, true); // check for valid certificate. if (m_serverCertificate == null) { throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "ApplicationCertificate cannot be found."); } } try { token.Decrypt(m_serverCertificate, m_serverNonce, securityPolicyUri); } catch (Exception e) { if (e is ServiceResultException) { throw; } throw ServiceResultException.Create(StatusCodes.BadIdentityTokenInvalid, e, "Could not decrypt identity token."); } // verify the signature. if (securityPolicyUri != SecurityPolicies.None) { byte[] dataToSign = Utils.Append(m_serverCertificate.RawData, m_serverNonce); if (!token.Verify(dataToSign, userTokenSignature, securityPolicyUri)) { throw new ServiceResultException(StatusCodes.BadUserSignatureInvalid, "Invalid user signature!"); } } } // validate user identity token. return(token); }
protected void ReadAsymmetricMessageHeader( BinaryDecoder decoder, X509Certificate2 receiverCertificate, out uint secureChannelId, out X509Certificate2 senderCertificate, out string securityPolicyUri) { senderCertificate = null; uint messageType = decoder.ReadUInt32(null); uint messageSize = decoder.ReadUInt32(null); // decode security header. byte[] certificateData = null; byte[] thumbprintData = null; try { secureChannelId = decoder.ReadUInt32(null); securityPolicyUri = decoder.ReadString(null, TcpMessageLimits.MaxSecurityPolicyUriSize); certificateData = decoder.ReadByteString(null, TcpMessageLimits.MaxCertificateSize); thumbprintData = decoder.ReadByteString(null, TcpMessageLimits.CertificateThumbprintSize); } catch (Exception e) { throw ServiceResultException.Create( StatusCodes.BadSecurityChecksFailed, e, "The asymmetric security header could not be parsed."); } // verify sender certificate. if (certificateData != null && certificateData.Length > 0) { senderCertificate = CertificateFactory.Create(certificateData, true); try { string thumbprint = senderCertificate.Thumbprint; if (thumbprint == null) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "Invalid certificate thumbprint."); } } catch (Exception e) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, e, "The sender's certificate could not be parsed."); } } else { if (securityPolicyUri != SecurityPolicies.None) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "The sender's certificate was not specified."); } } // verify receiver thumbprint. if (thumbprintData != null && thumbprintData.Length > 0) { if (receiverCertificate.Thumbprint.ToUpperInvariant() != GetThumbprintString(thumbprintData)) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "The receiver's certificate thumbprint is not valid."); } } else { if (securityPolicyUri != SecurityPolicies.None) { throw ServiceResultException.Create(StatusCodes.BadCertificateInvalid, "The receiver's certificate thumbprint was not specified."); } } }
/// <summary> /// Runs the testcases against the endpoint. /// </summary> /// <param name="endpoint">The endpoint to test.</param> /// <param name="testcases">The testcases to run.</param> public void Run(ConfiguredEndpoint endpoint, ServerTestConfiguration testConfiguration) { // save the test configuration. m_testConfiguration = testConfiguration; m_stopped = false; // create the binding factory. m_bindingFactory = BindingFactory.Create(m_configuration, m_messageContext); while (!m_stopped) { try { Report("Test run started."); // update from server. if (endpoint.UpdateBeforeConnect) { endpoint.UpdateFromServer(m_bindingFactory); Report("Updated endpoint from the discovery endpoint."); } // validate the server certificate. byte[] certificateData = endpoint.Description.ServerCertificate; try { X509Certificate2 certificate = CertificateFactory.Create(certificateData, true); m_configuration.CertificateValidator.Validate(certificate); } catch (ServiceResultException e) { if (e.StatusCode != StatusCodes.BadCertificateUntrusted) { throw new ServiceResultException(e, StatusCodes.BadCertificateInvalid); } // automatically trust the certificate if it is untrusted. m_configuration.CertificateValidator.Update(m_configuration.SecurityConfiguration); } m_defaultEndpoint = endpoint; // fetch all endpoints from the server. m_endpoints = GetEndpoints(endpoint); Report("Fetched all endpoints supported by the server."); } catch (Exception e) { Report(e, "Could not connect to server"); return; } m_endpointCount = 0; m_totalEndpointCount = 0; m_testCount = 0; m_failedTestCount = 0; m_iterationCount = 0; m_totalIterationCount = 0; uint totalCount = 0; uint failedCount = 0; uint endpointCount = 0; if (m_testConfiguration.EndpointSelection != EndpointSelection.Single) { EndpointSelection selection = m_testConfiguration.EndpointSelection; foreach (ConfiguredEndpoint current in m_endpoints.Endpoints) { if (IsEndpointSelected(current, selection, false)) { m_totalEndpointCount++; } if (current.Description.EncodingSupport == BinaryEncodingSupport.Optional) { if (IsEndpointSelected(current, selection, true)) { m_totalEndpointCount++; } } } foreach (ConfiguredEndpoint current in m_endpoints.Endpoints) { if (IsEndpointSelected(current, selection, false)) { m_endpointCount++; // check if test stopped. if (m_stopped) { break; } DoTestForEndpoint(current, ref totalCount, ref failedCount); endpointCount++; } if (current.Description.EncodingSupport == BinaryEncodingSupport.Optional) { if (IsEndpointSelected(current, selection, true)) { m_endpointCount++; // check if test stopped. if (m_stopped) { break; } current.Configuration.UseBinaryEncoding = !current.Configuration.UseBinaryEncoding; DoTestForEndpoint(current, ref totalCount, ref failedCount); endpointCount++; } } } } else { m_endpointCount++; m_totalEndpointCount = 1; DoTestForEndpoint(m_defaultEndpoint, ref totalCount, ref failedCount); endpointCount++; } if (failedCount > 0) { Report("WARNING: {0} tests failed. {1} tests run.", failedCount, totalCount); } else { Report("{0} tests completed successfully for {1} endpoints.", totalCount, endpointCount); DumpPerfData(); } if (!m_testConfiguration.Continuous) { break; } } }
/// <summary> /// Validates the identity token supplied by the client. /// </summary> /// <param name="identityToken"></param> /// <param name="userTokenSignature"></param> /// <returns></returns> private bool ValidateUserIdentityToken(ExtensionObject identityToken, SignatureData userTokenSignature) { UserIdentityToken token = null; UserTokenPolicy policy; if (identityToken == null || identityToken.Body == null) { if (_activated) { // not changing the token if already activated. return(false); } policy = Endpoint.UserIdentityTokens? .FirstOrDefault(t => t.TokenType == UserTokenType.Anonymous); if (policy == null) { throw ServiceResultException.Create(StatusCodes.BadUserAccessDenied, "Anonymous user token policy not supported."); } // create an anonymous token to use for subsequent validation. token = new AnonymousIdentityToken { PolicyId = policy.PolicyId }; } else if (!typeof(UserIdentityToken).IsInstanceOfType(identityToken.Body)) { // Decode identity token from binary. token = DecodeUserIdentityToken(identityToken, out policy); } else { token = (UserIdentityToken)identityToken.Body; // find the user token policy. policy = Endpoint.FindUserTokenPolicy(token.PolicyId); if (policy == null) { throw ServiceResultException.Create(StatusCodes.BadIdentityTokenInvalid, "User token policy not supported."); } } // determine the security policy uri. var securityPolicyUri = policy.SecurityPolicyUri; if (string.IsNullOrEmpty(securityPolicyUri)) { securityPolicyUri = Endpoint.SecurityPolicyUri; } if (securityPolicyUri != SecurityPolicies.None) { // decrypt the user identity token. if (_serverCertificate == null) { _serverCertificate = CertificateFactory.Create( Endpoint.ServerCertificate, true); // check for valid certificate. if (_serverCertificate == null) { throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "ApplicationCertificate cannot be found."); } } try { token.Decrypt(_serverCertificate, _serverNonce, securityPolicyUri); } catch (ServiceResultException) { throw; } catch (Exception e) { throw ServiceResultException.Create(StatusCodes.BadIdentityTokenInvalid, e, "Could not decrypt identity token."); } // ... and verify the signature if any. VerifyUserTokenSignature(userTokenSignature, token, securityPolicyUri); } // We have a valid token - validate it through the handler chain. var arg = new UserIdentityHandlerArgs { CurrentIdentities = Identities, Token = token }; _validator?.Invoke(this, arg); if (arg.ValidationException != null) { throw arg.ValidationException; } if (arg.NewIdentities != null) { Identities = arg.NewIdentities; return(true); } return(false); // No new identities }