Ejemplo n.º 1
0
            /// <summary>
            /// Formats the numeric range as a string.
            /// </summary>
            /// <param name="format">(Unused) Always pass null</param>
            /// <param name="formatProvider">(Unused) Always pass null</param>
            /// <exception cref="FormatException">Thrown if non-null parameters are passed</exception>
            public string ToString(string format, IFormatProvider formatProvider)
            {
                if (format == null)
                {
                    StringBuilder path = new StringBuilder();

                    // write the reference type component.
                    switch (m_elementType)
                    {
                    case ElementType.AnyHierarchical:
                    {
                        path.Append('/');
                        break;
                    }

                    case ElementType.AnyComponent:
                    {
                        path.Append('.');
                        break;
                    }

                    case ElementType.ForwardReference:
                    case ElementType.InverseReference:
                    {
                        if (m_referenceTypeName != null && !String.IsNullOrEmpty(m_referenceTypeName.Name))
                        {
                            path.Append('<');

                            if (!m_includeSubtypes)
                            {
                                path.Append('#');
                            }

                            if (m_elementType == ElementType.InverseReference)
                            {
                                path.Append('!');
                            }

                            if (m_referenceTypeName.NamespaceIndex != 0)
                            {
                                path.AppendFormat("{0}:", m_referenceTypeName.NamespaceIndex);
                            }

                            EncodeName(path, m_referenceTypeName.Name);
                            path.Append('>');
                        }

                        break;
                    }
                    }

                    // write the target browse name component.
                    if (m_targetName != null && !String.IsNullOrEmpty(m_targetName.Name))
                    {
                        if (m_targetName.NamespaceIndex != 0)
                        {
                            path.AppendFormat("{0}:", m_targetName.NamespaceIndex);
                        }

                        EncodeName(path, m_targetName.Name);
                    }

                    return(path.ToString());
                }

                throw new FormatException(Utils.Format("Invalid format string: '{0}'.", format));
            }
Ejemplo n.º 2
0
            /// <summary>
            /// Extracts a browse name with an optional namespace prefix from the reader.
            /// </summary>
            private static QualifiedName ParseName(
                StringReader reader,
                bool referenceName)
            {
                ushort namespaceIndex = 0;

                // extract namespace index if present.
                StringBuilder buffer = new StringBuilder();

                int last = reader.Peek();

                for (int next = last; next != -1; next = reader.Peek())
                {
                    last = next;

                    if (!Char.IsDigit((char)next))
                    {
                        if (next == ':')
                        {
                            reader.Read();
                            namespaceIndex = Convert.ToUInt16(buffer.ToString(), CultureInfo.InvariantCulture);
                            buffer.Length  = 0;

                            // fetch next character.
                            last = reader.Peek();
                        }

                        break;
                    }

                    buffer.Append((char)next);
                    reader.Read();
                }

                // extract rest of name.
                for (int next = last; next != -1; next = reader.Peek())
                {
                    last = next;

                    // check for terminator.
                    if (referenceName)
                    {
                        if (next == '>')
                        {
                            reader.Read();
                            break;
                        }
                    }
                    else
                    {
                        if (next == '<' || next == '/' || next == '.')
                        {
                            break;
                        }
                    }

                    // check for invalid character.
                    if (next == '!' || next == ':' || next == '<' || next == '>' || next == '/' || next == '.')
                    {
                        throw new ServiceResultException(
                                  StatusCodes.BadSyntaxError,
                                  Utils.Format("Unexpected character '{0}' in browse path.", next));
                    }

                    // check for escape character.
                    if (next == '&')
                    {
                        next = reader.Read();
                        next = reader.Read();
                        buffer.Append((char)next);
                        continue;
                    }

                    // append character.
                    buffer.Append((char)next);
                    reader.Read();
                }

                // check for enclosing bracket.
                if (referenceName)
                {
                    if (last != '>')
                    {
                        throw new ServiceResultException(
                                  StatusCodes.BadSyntaxError,
                                  Utils.Format("Missing file '>' for reference type name in browse path."));
                    }
                }

                if (buffer.Length == 0)
                {
                    if (referenceName)
                    {
                        throw new ServiceResultException(
                                  StatusCodes.BadSyntaxError,
                                  Utils.Format("Reference type name is null in browse path."));
                    }

                    if (namespaceIndex == 0)
                    {
                        return(null);
                    }
                }

                return(new QualifiedName(buffer.ToString(), namespaceIndex));
            }
        /// <summary>
        /// Recursively collects the nodes within a type hierarchy.
        /// </summary>
        private void GetInstanceHierarchyForType(
            HierarchyBrowsePath parent,
            ExpandedNodeId instanceId,
            InstanceDeclarationHierarchy hierarchy)
        {
            // the instance must be local to the address space.
            ILocalNode instance = m_nodes.Find(instanceId) as ILocalNode;

            if (instance == null)
            {
                return;
            }

            // must be an object, variable or method.
            if ((instance.NodeClass & (NodeClass.Object | NodeClass.Variable | NodeClass.Method)) == 0)
            {
                return;
            }

            // get the naming rule.
            NamingRule namingRule = GetNamingRule(instance.ModellingRule);

            // only include instances with unique browse names in the hierarchy.
            if (namingRule != NamingRule.Unique && namingRule != NamingRule.UniqueOptional)
            {
                return;
            }

            // construct the browse path that identifies the node.
            string browsePath = null;

            if (parent.BrowsePath == "/")
            {
                browsePath = Utils.Format("/{0}", instance.BrowseName);
            }
            else
            {
                browsePath = Utils.Format("{0}/{1}", parent.BrowsePath, instance.BrowseName);
            }

            // check if the browse path already exists in the hierarchy.
            HierarchyBrowsePath child = null;

            if (!hierarchy.BrowsePaths.TryGetValue(browsePath, out child))
            {
                child = new HierarchyBrowsePath();

                child.BrowsePath    = browsePath;
                child.DeclarationId = instance.NodeId;
                child.InstanceId    = null;
                child.IsModelParent = false;
                child.IsOptional    = namingRule != NamingRule.Unique;

                // add new browse path to hierarchy.
                hierarchy.BrowsePaths.Add(browsePath, child);
            }

            // override any declaration specified in a supertype.
            child.DeclarationId = instance.NodeId;

            // check if node has been processed via another path.
            HierarchyBrowsePath alternatePath = null;

            if (hierarchy.Declarations.TryGetValue(instance.NodeId, out alternatePath))
            {
                // keep the model parent path as the primary path.
                if (!alternatePath.IsModelParent && child.IsModelParent)
                {
                    hierarchy.Declarations[instance.NodeId] = child;
                }

                // nothing more to do since node has been processed once.
                return;
            }

            // save child.
            hierarchy.Declarations.Add(instance.NodeId, child);



            // follow children.
            foreach (IReference reference in instance.References.Find(ReferenceTypeIds.HierarchicalReferences, false, true, m_nodes.TypeTree))
            {
                GetInstanceHierarchyForType(child, reference.TargetId, hierarchy);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Dispatches an incoming binary encoded request.
        /// </summary>
        /// <param name="incoming">Incoming request.</param>
        public virtual IServiceResponse ProcessRequest(IServiceRequest incoming)
        {
            try
            {
                SetRequestContext(RequestEncoding.Binary);

                ServiceDefinition service = null;

                // find service.
                if (!SupportedServices.TryGetValue(incoming.TypeId, out service))
                {
                    throw new ServiceResultException(StatusCodes.BadServiceUnsupported, Utils.Format("'{0}' is an unrecognized service identifier.", incoming.TypeId));
                }

                // invoke service.
                return(service.Invoke(incoming));
            }
            catch (Exception e)
            {
                // create fault.
                return(CreateFault(incoming, e));
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Called before the server starts.
        /// </summary>
        /// <param name="configuration">The object that stores the configurable configuration information for a UA application.</param>
        protected virtual void OnServerStarting(ApplicationConfiguration configuration)
        {
            // fetch properties and configuration.
            Configuration    = configuration;
            ServerProperties = LoadServerProperties();

            // ensure at least one security policy exists.
            if (configuration.ServerConfiguration != null)
            {
                if (configuration.ServerConfiguration.SecurityPolicies.Count == 0)
                {
                    configuration.ServerConfiguration.SecurityPolicies.Add(new ServerSecurityPolicy());
                }

                // ensure at least one user token policy exists.
                if (configuration.ServerConfiguration.UserTokenPolicies.Count == 0)
                {
                    UserTokenPolicy userTokenPolicy = new UserTokenPolicy();

                    userTokenPolicy.TokenType = UserTokenType.Anonymous;
                    userTokenPolicy.PolicyId  = userTokenPolicy.TokenType.ToString();

                    configuration.ServerConfiguration.UserTokenPolicies.Add(userTokenPolicy);
                }
            }

            // load the instance certificate.
            if (configuration.SecurityConfiguration.ApplicationCertificate != null)
            {
                InstanceCertificate = configuration.SecurityConfiguration.ApplicationCertificate.Find(true).Result;
            }

            if (InstanceCertificate == null)
            {
                throw new ServiceResultException(
                          StatusCodes.BadConfigurationError,
                          "Server does not have an instance certificate assigned.");
            }

            if (!InstanceCertificate.HasPrivateKey)
            {
                throw new ServiceResultException(
                          StatusCodes.BadConfigurationError,
                          "Server does not have access to the private key for the instance certificate.");
            }

            // load certificate chain.
            InstanceCertificateChain = new X509Certificate2Collection(InstanceCertificate);
            List <CertificateIdentifier> issuers = new List <CertificateIdentifier>();

            configuration.CertificateValidator.GetIssuers(InstanceCertificateChain, issuers).Wait();

            for (int i = 0; i < issuers.Count; i++)
            {
                InstanceCertificateChain.Add(issuers[i].Certificate);
            }

            // use the message context from the configuration to ensure the channels are using the same one.
            MessageContext = configuration.CreateMessageContext();

            // assign a unique identifier if none specified.
            if (String.IsNullOrEmpty(configuration.ApplicationUri))
            {
                configuration.ApplicationUri = X509Utils.GetApplicationUriFromCertificate(InstanceCertificate);

                if (String.IsNullOrEmpty(configuration.ApplicationUri))
                {
                    configuration.ApplicationUri = Utils.Format(
                        "http://{0}/{1}/{2}",
                        Utils.GetHostName(),
                        configuration.ApplicationName,
                        Guid.NewGuid());
                }
            }

            // initialize namespace table.
            MessageContext.NamespaceUris = new NamespaceTable();
            MessageContext.NamespaceUris.Append(configuration.ApplicationUri);

            // assign an instance name.
            if (String.IsNullOrEmpty(configuration.ApplicationName) && InstanceCertificate != null)
            {
                configuration.ApplicationName = InstanceCertificate.GetNameInfo(X509NameType.DnsName, false);
            }

            // save the certificate validator.
            CertificateValidator = configuration.CertificateValidator;
        }
        /// <summary>
        /// Recursively collects the nodes within a type hierarchy.
        /// </summary>
        private void UpdateInstanceHierarchyWithInstance(
            HierarchyBrowsePath parent,
            ExpandedNodeId instanceId,
            InstanceDeclarationHierarchy hierarchy)
        {
            INode instance = m_nodes.Find(instanceId) as INode;

            // ignore instances not in the address space.
            if (instance == null)
            {
                return;
            }

            // must be an object, variable or method.
            if ((instance.NodeClass & (NodeClass.Object | NodeClass.Variable | NodeClass.Method)) == 0)
            {
                return;
            }

            // construct the browse path that identifies the node.
            string browsePath = null;

            if (parent.BrowsePath == "/")
            {
                browsePath = Utils.Format("/{0}", instance.BrowseName);
            }
            else
            {
                browsePath = Utils.Format("{0}/{1}", parent.BrowsePath, instance.BrowseName);
            }

            // check if the browse path exists in the hierarchy.
            HierarchyBrowsePath child = null;

            if (!hierarchy.BrowsePaths.TryGetValue(browsePath, out child))
            {
                return;
            }

            // update the instance.
            child.InstanceId = instance.NodeId;

            // check if already followed.
            if (hierarchy.Instances.ContainsKey((NodeId)instance.NodeId))
            {
                return;
            }

            // save child.
            hierarchy.Instances.Add((NodeId)instance.NodeId, instance);

            // check for local node.
            ILocalNode localInstance = instance as ILocalNode;

            if (localInstance == null)
            {
                return;
            }

            // follow children.
            foreach (IReference reference in localInstance.References.Find(ReferenceTypeIds.HierarchicalReferences, false, true, m_nodes.TypeTree))
            {
                UpdateInstanceHierarchyWithInstance(child, reference.TargetId, hierarchy);
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Converts an ContentFilterElement to a displayable string.
        /// </summary>
        /// <param name="nodeTable">The node table.</param>
        /// <returns>ContentFilterElement as a displayable string.</returns>
        public virtual string ToString(INodeTable nodeTable)
        {
            List <FilterOperand> operands = GetOperands();

            string operand1 = (operands.Count > 0)?operands[0].ToString(nodeTable):null;
            string operand2 = (operands.Count > 1)?operands[1].ToString(nodeTable):null;
            string operand3 = (operands.Count > 2)?operands[2].ToString(nodeTable):null;

            StringBuilder buffer = new StringBuilder();

            switch (FilterOperator)
            {
            case FilterOperator.OfType:
            case FilterOperator.InView:
            case FilterOperator.IsNull:
            case FilterOperator.Not:
            {
                buffer.AppendFormat("{0} '{1}'", FilterOperator, operand1);
                break;
            }

            case FilterOperator.And:
            case FilterOperator.Equals:
            case FilterOperator.GreaterThan:
            case FilterOperator.GreaterThanOrEqual:
            case FilterOperator.LessThan:
            case FilterOperator.LessThanOrEqual:
            case FilterOperator.Like:
            case FilterOperator.Or:
            {
                buffer.AppendFormat("'{1}' {0} '{2}'", FilterOperator, operand1, operand2);
                break;
            }

            case FilterOperator.Between:
            {
                buffer.AppendFormat("'{1}' <= '{0}' <= '{2}'", operand1, operand2, operand3);
                break;
            }

            case FilterOperator.Cast:
            {
                buffer.AppendFormat("({1}){0}", operand1, operand2);
                break;
            }

            case FilterOperator.InList:
            {
                buffer.AppendFormat("'{0}' in {", operand1);

                for (int ii = 1; ii < operands.Count; ii++)
                {
                    if (ii < operands.Count - 1)
                    {
                        buffer.Append(", ");
                    }

                    buffer.AppendFormat("'{0}'", operands[ii].ToString());
                }

                buffer.Append("}");
                break;
            }

            case FilterOperator.RelatedTo:
            {
                buffer.AppendFormat("'{0}' ", operand1);

                string referenceType = operand2;

                if (operands.Count > 1)
                {
                    LiteralOperand literalOperand = operands[1] as LiteralOperand;

                    if (literalOperand != null)
                    {
                        INode node = nodeTable.Find(literalOperand.Value.Value as NodeId);

                        if (node != null)
                        {
                            referenceType = Utils.Format("{0}", node);
                        }
                    }
                }

                buffer.AppendFormat("{0} '{1}'", referenceType, operand2);

                if (operand3 != null)
                {
                    buffer.AppendFormat("Hops='{0}'", operand3);
                }

                break;
            }
            }

            return(buffer.ToString());
        }
Ejemplo n.º 8
0
 /// <summary>
 /// Converts an FilterOperand to a displayable string.
 /// </summary>
 /// <param name="nodeTable">The node table.</param>
 /// <returns>ContentFilterElement as a displayable string.</returns>
 public virtual string ToString(INodeTable nodeTable)
 {
     return(Utils.Format("{0}", this));
 }
Ejemplo n.º 9
0
 /// <summary>
 /// Converts an ElementOperand to a displayable string.
 /// </summary>
 /// <param name="table">The table.</param>
 /// <returns>ElementOperand as a displayable string.</returns>
 public override string ToString(INodeTable table)
 {
     return(Utils.Format("Element[{0}]", Index));
 }
        /// <summary>
        /// Sets the parameters to suitable defaults.
        /// </summary>
        private static void SetSuitableDefaults(
            ref string applicationUri,
            ref string applicationName,
            ref string subjectName,
            ref IList <String> domainNames)
        {
            // parse the subject name if specified.
            List <string> subjectNameEntries = null;

            if (!String.IsNullOrEmpty(subjectName))
            {
                subjectNameEntries = X509Utils.ParseDistinguishedName(subjectName);
            }

            // check the application name.
            if (String.IsNullOrEmpty(applicationName))
            {
                if (subjectNameEntries == null)
                {
                    throw new ArgumentNullException(nameof(applicationName), "Must specify a applicationName or a subjectName.");
                }

                // use the common name as the application name.
                for (int ii = 0; ii < subjectNameEntries.Count; ii++)
                {
                    if (subjectNameEntries[ii].StartsWith("CN=", StringComparison.Ordinal))
                    {
                        applicationName = subjectNameEntries[ii].Substring(3).Trim();
                        break;
                    }
                }
            }

            if (String.IsNullOrEmpty(applicationName))
            {
                throw new ArgumentNullException(nameof(applicationName), "Must specify a applicationName or a subjectName.");
            }

            // remove special characters from name.
            StringBuilder buffer = new StringBuilder();

            for (int ii = 0; ii < applicationName.Length; ii++)
            {
                char ch = applicationName[ii];

                if (Char.IsControl(ch) || ch == '/' || ch == ',' || ch == ';')
                {
                    ch = '+';
                }

                buffer.Append(ch);
            }

            applicationName = buffer.ToString();

            // ensure at least one host name.
            if (domainNames == null || domainNames.Count == 0)
            {
                domainNames = new List <string>();
                domainNames.Add(Utils.GetHostName());
            }

            // create the application uri.
            if (String.IsNullOrEmpty(applicationUri))
            {
                StringBuilder builder = new StringBuilder();

                builder.Append("urn:");
                builder.Append(domainNames[0]);
                builder.Append(':');
                builder.Append(applicationName);

                applicationUri = builder.ToString();
            }

            Uri uri = Utils.ParseUri(applicationUri);

            if (uri == null)
            {
                throw new ArgumentNullException(nameof(applicationUri), "Must specify a valid URL.");
            }

            // create the subject name,
            if (String.IsNullOrEmpty(subjectName))
            {
                subjectName = Utils.Format("CN={0}", applicationName);
            }

            if (!subjectName.Contains("CN="))
            {
                subjectName = Utils.Format("CN={0}", subjectName);
            }

            if (domainNames != null && domainNames.Count > 0)
            {
                if (!subjectName.Contains("DC=") && !subjectName.Contains('='))
                {
                    subjectName += Utils.Format(", DC={0}", domainNames[0]);
                }
                else
                {
                    subjectName = Utils.ReplaceDCLocalhost(subjectName, domainNames[0]);
                }
            }
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Returns the string representation of the embededobject.
        /// </summary>
        /// <param name="format">(Unused). Leave this as null</param>
        /// <param name="formatProvider">The provider of a mechanism for retrieving an object to control formatting.</param>
        /// <returns>
        /// A <see cref="T:System.String"/> containing the value of the current embeded instance in the specified format.
        /// </returns>
        /// <exception cref="FormatException">Thrown if the <i>format</i> parameter is not null</exception>
        public string ToString(string format, IFormatProvider formatProvider)
        {
            if (format == null)
            {
                if (m_body is byte[])
                {
                    return(String.Format(formatProvider, "Byte[{0}]", ((byte[])m_body).Length));
                }

                if (m_body is XmlElement)
                {
                    return(String.Format(formatProvider, "<{0}>", ((XmlElement)m_body).Name));
                }

                if (m_body is IEncodeable)
                {
                    StringBuilder body = new StringBuilder();

                    PropertyInfo[] properties = m_body.GetType().GetProperties(BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance);

                    foreach (PropertyInfo property in properties)
                    {
                        object[] attributes = property.GetCustomAttributes(typeof(DataMemberAttribute), true);

                        for (int ii = 0; ii < attributes.Length; ii++)
                        {
                            DataMemberAttribute contract = attributes[ii] as DataMemberAttribute;

                            if (contract != null)
                            {
                                if (body.Length == 0)
                                {
                                    body.Append("{");
                                }
                                else
                                {
                                    body.Append(" | ");
                                }

                                body.AppendFormat("{0}", property.GetGetMethod().Invoke(m_body, null));
                            }
                        }
                    }

                    if (body.Length > 0)
                    {
                        body.Append("}");
                    }

                    return(String.Format(formatProvider, "{0}", body));
                }

                if (!NodeId.IsNull(this.m_typeId))
                {
                    return(String.Format(formatProvider, "{{{0}}}", this.m_typeId));
                }

                return("(null)");
            }

            throw new FormatException(Utils.Format("Invalid format string: '{0}'.", format));
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Writes the given value in raw format without meta information.
        /// </summary>
        /// <param name="encoder">The encoder to use.</param>
        /// <param name="fieldName">The name of the field.</param>
        /// <param name="value">The value to write.</param>
        /// <param name="typeInfo">The type of the value.</param>
        /// <exception cref="NotImplementedException"></exception>
        /// <exception cref="ServiceResultException"></exception>
        public static void WriteRaw(this IEncoder encoder, string fieldName, object value, TypeInfo typeInfo)
        {
            if (value != null)
            {
                if (typeInfo.ValueRank < 0)
                {
                    switch (typeInfo.BuiltInType)
                    {
                    case BuiltInType.Boolean:
                        encoder.WriteBoolean(fieldName, (bool)value);
                        return;

                    case BuiltInType.SByte:
                        encoder.WriteSByte(fieldName, (sbyte)value);
                        return;

                    case BuiltInType.Byte:
                        encoder.WriteByte(fieldName, (byte)value);
                        return;

                    case BuiltInType.Int16:
                        encoder.WriteInt16(fieldName, (short)value);
                        return;

                    case BuiltInType.UInt16:
                        encoder.WriteUInt16(fieldName, (ushort)value);
                        return;

                    case BuiltInType.Int32:
                        encoder.WriteInt32(fieldName, (int)value);
                        return;

                    case BuiltInType.UInt32:
                        encoder.WriteUInt32(fieldName, (uint)value);
                        return;

                    case BuiltInType.Int64:
                        encoder.WriteInt64(fieldName, (long)value);
                        return;

                    case BuiltInType.UInt64:
                        encoder.WriteUInt64(fieldName, (ulong)value);
                        return;

                    case BuiltInType.Float:
                        encoder.WriteFloat(fieldName, (float)value);
                        return;

                    case BuiltInType.Double:
                        encoder.WriteDouble(fieldName, (double)value);
                        return;

                    case BuiltInType.String:
                        encoder.WriteString(fieldName, (string)value);
                        return;

                    case BuiltInType.DateTime:
                        encoder.WriteDateTime(fieldName, (DateTime)value);
                        return;

                    case BuiltInType.Guid:
                        encoder.WriteGuid(fieldName, (Uuid)value);
                        return;

                    case BuiltInType.ByteString:
                        encoder.WriteByteString(fieldName, (byte[])value);
                        return;

                    case BuiltInType.XmlElement:
                        encoder.WriteXmlElement(fieldName, (XmlElement)value);
                        return;

                    case BuiltInType.NodeId:
                        encoder.WriteNodeId(fieldName, (NodeId)value);
                        return;

                    case BuiltInType.ExpandedNodeId:
                        encoder.WriteExpandedNodeId(fieldName, (ExpandedNodeId)value);
                        return;

                    case BuiltInType.StatusCode:
                        encoder.WriteStatusCode(fieldName, (StatusCode)value);
                        return;

                    case BuiltInType.QualifiedName:
                        encoder.WriteQualifiedName(fieldName, (QualifiedName)value);
                        return;

                    case BuiltInType.LocalizedText:
                        encoder.WriteLocalizedText(fieldName, (LocalizedText)value);
                        return;

                    case BuiltInType.ExtensionObject:
                        encoder.WriteExtensionObject(fieldName, (ExtensionObject)value);
                        return;

                    case BuiltInType.DataValue:
                        encoder.WriteDataValue(fieldName, (DataValue)value);
                        return;

                    case BuiltInType.Enumeration:
                        encoder.WriteInt32(fieldName, (int)value);
                        return;
                    }
                }
                else if (typeInfo.ValueRank <= 1)
                {
                    switch (typeInfo.BuiltInType)
                    {
                    case BuiltInType.Boolean:
                        encoder.WriteBooleanArray(fieldName, (bool[])value);
                        return;

                    case BuiltInType.SByte:
                        encoder.WriteSByteArray(fieldName, (sbyte[])value);
                        return;

                    case BuiltInType.Byte:
                        encoder.WriteByteArray(fieldName, (byte[])value);
                        return;

                    case BuiltInType.Int16:
                        encoder.WriteInt16Array(fieldName, (short[])value);
                        return;

                    case BuiltInType.UInt16:
                        encoder.WriteUInt16Array(fieldName, (ushort[])value);
                        return;

                    case BuiltInType.Int32:
                        encoder.WriteInt32Array(fieldName, (int[])value);
                        return;

                    case BuiltInType.UInt32:
                        encoder.WriteUInt32Array(fieldName, (uint[])value);
                        return;

                    case BuiltInType.Int64:
                        encoder.WriteInt64Array(fieldName, (long[])value);
                        return;

                    case BuiltInType.UInt64:
                        encoder.WriteUInt64Array(fieldName, (ulong[])value);
                        return;

                    case BuiltInType.Float:
                        encoder.WriteFloatArray(fieldName, (float[])value);
                        return;

                    case BuiltInType.Double:
                        encoder.WriteDoubleArray(fieldName, (double[])value);
                        return;

                    case BuiltInType.String:
                        encoder.WriteStringArray(fieldName, (string[])value);
                        return;

                    case BuiltInType.DateTime:
                        encoder.WriteDateTimeArray(fieldName, (DateTime[])value);
                        return;

                    case BuiltInType.Guid:
                        encoder.WriteGuidArray(fieldName, (Uuid[])value);
                        return;

                    case BuiltInType.ByteString:
                        encoder.WriteByteStringArray(fieldName, (byte[][])value);
                        return;

                    case BuiltInType.XmlElement:
                        encoder.WriteXmlElementArray(fieldName, (XmlElement[])value);
                        return;

                    case BuiltInType.NodeId:
                        encoder.WriteNodeIdArray(fieldName, (NodeId[])value);
                        return;

                    case BuiltInType.ExpandedNodeId:
                        encoder.WriteExpandedNodeIdArray(fieldName, (ExpandedNodeId[])value);
                        return;

                    case BuiltInType.StatusCode:
                        encoder.WriteStatusCodeArray(fieldName, (StatusCode[])value);
                        return;

                    case BuiltInType.QualifiedName:
                        encoder.WriteQualifiedNameArray(fieldName, (QualifiedName[])value);
                        return;

                    case BuiltInType.LocalizedText:
                        encoder.WriteLocalizedTextArray(fieldName, (LocalizedText[])value);
                        return;

                    case BuiltInType.ExtensionObject:
                        encoder.WriteExtensionObjectArray(fieldName, (ExtensionObject[])value);
                        return;

                    case BuiltInType.DataValue:
                        encoder.WriteDataValueArray(fieldName, (DataValue[])value);
                        return;

                    case BuiltInType.Variant:
                        if (value is Variant[] variantArray)
                        {
                            encoder.WriteVariantArray(fieldName, variantArray);
                            return;
                        }
                        if (value is object[] objArray)
                        {
                            throw new NotImplementedException();
                        }
                        throw ServiceResultException.Create(2147876864U, "Unexpected type encountered while encoding an array of Variants: {0}", (object)value.GetType());

                    case BuiltInType.Enumeration:
                        var enumArray = value as Enum[];
                        var strArray  = new string[enumArray.Length];

                        for (var index = 0; index < enumArray.Length; ++index)
                        {
                            var str = enumArray[index].ToString() + "_" + enumArray[index].As <int>().ToString(CultureInfo.InvariantCulture);
                            strArray[index] = str;
                        }
                        encoder.WriteStringArray(null, strArray);
                        return;
                    }
                }
                else if (typeInfo.ValueRank > 1)
                {
                    encoder.WriteMatrix(fieldName, (Matrix)value);
                    return;
                }
                throw new ServiceResultException(2147876864U, Utils.Format("Type '{0}' is not allowed in an Variant.", (object)value.GetType().FullName));
            }
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Throws an exception if validation fails.
        /// </summary>
        /// <param name="certificates">The certificates to be checked.</param>
        /// <param name="endpoint">The endpoint for domain validation.</param>
        /// <exception cref="ServiceResultException">If certificate[0] cannot be accepted</exception>
        protected virtual async Task InternalValidate(X509Certificate2Collection certificates, ConfiguredEndpoint endpoint)
        {
            X509Certificate2 certificate = certificates[0];

            // check for previously validated certificate.
            X509Certificate2 certificate2 = null;

            if (m_validatedCertificates.TryGetValue(certificate.Thumbprint, out certificate2))
            {
                if (Utils.IsEqual(certificate2.RawData, certificate.RawData))
                {
                    return;
                }
            }

            CertificateIdentifier trustedCertificate = await GetTrustedCertificate(certificate);

            // get the issuers (checks the revocation lists if using directory stores).
            List <CertificateIdentifier> issuers = new List <CertificateIdentifier>();
            bool isIssuerTrusted = await GetIssuers(certificates, issuers);

            // setup policy chain
            X509ChainPolicy policy = new X509ChainPolicy();

            policy.RevocationFlag    = X509RevocationFlag.EntireChain;
            policy.RevocationMode    = X509RevocationMode.NoCheck;
            policy.VerificationFlags = X509VerificationFlags.NoFlag;

            foreach (CertificateIdentifier issuer in issuers)
            {
                if ((issuer.ValidationOptions & CertificateValidationOptions.SuppressRevocationStatusUnknown) != 0)
                {
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown;
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreCtlSignerRevocationUnknown;
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreEndRevocationUnknown;
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreRootRevocationUnknown;
                }

                // we did the revocation check in the GetIssuers call. No need here.
                policy.RevocationMode = X509RevocationMode.NoCheck;
                policy.ExtraStore.Add(issuer.Certificate);
            }

            // build chain.
            X509Chain chain = new X509Chain();

            chain.ChainPolicy = policy;
            chain.Build(certificate);

            // check the chain results.
            CertificateIdentifier target = trustedCertificate;

            if (target == null)
            {
                target = new CertificateIdentifier(certificate);
            }

            ServiceResult sresult = null;

            for (int ii = 0; ii < chain.ChainElements.Count; ii++)
            {
                X509ChainElement element = chain.ChainElements[ii];

                CertificateIdentifier issuer = null;

                if (ii < issuers.Count)
                {
                    issuer = issuers[ii];
                }
                // check for chain status errors.
                if (element.ChainElementStatus.Length > 0)
                {
                    foreach (X509ChainStatus status in element.ChainElementStatus)
                    {
                        ServiceResult result = CheckChainStatus(status, target, issuer, (ii != 0));
                        if (ServiceResult.IsBad(result))
                        {
                            sresult = new ServiceResult(result, sresult);
                        }
                    }
                }

                if (issuer != null)
                {
                    target = issuer;
                }
            }

            // check whether the chain is complete (if there is a chain)
            bool issuedByCA      = !X509Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer);
            bool chainIncomplete = false;

            if (issuers.Count > 0)
            {
                var rootCertificate = issuers[issuers.Count - 1].Certificate;
                if (!X509Utils.CompareDistinguishedName(rootCertificate.Subject, rootCertificate.Issuer))
                {
                    chainIncomplete = true;
                }
            }
            else
            {
                if (issuedByCA)
                {
                    // no issuer found at all
                    chainIncomplete = true;
                }
            }

            // check if certificate issuer is trusted.
            if (issuedByCA && !isIssuerTrusted && trustedCertificate == null)
            {
                var message = CertificateMessage("Certificate Issuer is not trusted.", certificate);
                sresult = new ServiceResult(StatusCodes.BadCertificateUntrusted,
                                            null, null, message, null, sresult);
            }

            // check if certificate is trusted.
            if (trustedCertificate == null && !isIssuerTrusted)
            {
                if (m_applicationCertificate == null || !Utils.IsEqual(m_applicationCertificate.RawData, certificate.RawData))
                {
                    var message = CertificateMessage("Certificate is not trusted.", certificate);
                    sresult = new ServiceResult(StatusCodes.BadCertificateUntrusted,
                                                null, null, message, null, sresult);
                }
            }

            if (endpoint != null && !FindDomain(certificate, endpoint))
            {
                string message = Utils.Format(
                    "The domain '{0}' is not listed in the server certificate.",
                    endpoint.EndpointUrl.DnsSafeHost);
                sresult = new ServiceResult(StatusCodes.BadCertificateHostNameInvalid,
                                            null, null, message, null, sresult
                                            );
            }

            // check if certificate is valid for use as app/sw or user cert
            X509KeyUsageFlags certificateKeyUsage = X509Utils.GetKeyUsage(certificate);

            if ((certificateKeyUsage & X509KeyUsageFlags.DataEncipherment) == 0)
            {
                sresult = new ServiceResult(StatusCodes.BadCertificateUseNotAllowed,
                                            null, null, "Usage of certificate is not allowed.", null, sresult);
            }

            // check if minimum requirements are met
            if (m_rejectSHA1SignedCertificates && IsSHA1SignatureAlgorithm(certificate.SignatureAlgorithm))
            {
                sresult = new ServiceResult(StatusCodes.BadCertificatePolicyCheckFailed,
                                            null, null, "SHA1 signed certificates are not trusted.", null, sresult);
            }

            int keySize = X509Utils.GetRSAPublicKeySize(certificate);

            if (keySize < m_minimumCertificateKeySize)
            {
                sresult = new ServiceResult(StatusCodes.BadCertificatePolicyCheckFailed,
                                            null, null, "Certificate doesn't meet minimum key length requirement.", null, sresult);
            }

            if (issuedByCA && chainIncomplete)
            {
                var message = CertificateMessage("Certificate chain validation incomplete.", certificate);
                sresult = new ServiceResult(StatusCodes.BadCertificateChainIncomplete,
                                            null, null, message, null, sresult);
            }
            if (sresult != null)
            {
                throw new ServiceResultException(sresult);
            }
        }