예제 #1
0
        /// <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="))
                    {
                        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]);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Ensures that the application configuration is valid.
        /// </summary>
        /// <param name="applicationType">Type of the application.</param>
        public virtual async Task Validate(ApplicationType applicationType)
        {
            if (String.IsNullOrEmpty(ApplicationName))
            {
                throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "ApplicationName must be specified.");
            }

            if (SecurityConfiguration == null)
            {
                throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "SecurityConfiguration must be specified.");
            }

            SecurityConfiguration.Validate();

            // load private key
            await SecurityConfiguration.ApplicationCertificate.LoadPrivateKey(null);

            //  generate a default uri if null
            if (String.IsNullOrEmpty(ApplicationUri))
            {
                StringBuilder buffer = new StringBuilder();

                buffer.Append("urn:");
                buffer.Append(Utils.GetHostName());
                buffer.Append(":");
                buffer.Append(ApplicationName);

                m_applicationUri = buffer.ToString();
            }

            if (applicationType == ApplicationType.Client || applicationType == ApplicationType.ClientAndServer)
            {
                if (ClientConfiguration == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "ClientConfiguration must be specified.");
                }

                ClientConfiguration.Validate();
            }

            if (applicationType == ApplicationType.Server || applicationType == ApplicationType.ClientAndServer)
            {
                if (ServerConfiguration == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "ServerConfiguration must be specified.");
                }

                ServerConfiguration.Validate();
            }

            if (applicationType == ApplicationType.DiscoveryServer)
            {
                if (DiscoveryServerConfiguration == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "DiscoveryServerConfiguration must be specified.");
                }

                DiscoveryServerConfiguration.Validate();
            }

            // toggle the state of the hi-res clock.
            HiResClock.Disabled = m_disableHiResClock;

            if (m_disableHiResClock)
            {
                if (m_serverConfiguration != null)
                {
                    if (m_serverConfiguration.PublishingResolution < 50)
                    {
                        m_serverConfiguration.PublishingResolution = 50;
                    }
                }
            }

            // create the certificate validator.
            m_certificateValidator = new CertificateValidator();
            await m_certificateValidator.Update(this.SecurityConfiguration);
        }
예제 #3
0
        public override X509Certificate2 LoadApplicationCertificate(string thumbprint, string subjectName, string applicationURI, string password)
        {
            try
            {
                // Create a handle based on the hash of the keys
                ushort    slotIndex = ushort.Parse(thumbprint);
                TpmHandle nvHandle  = TpmHandle.NV(slotIndex);
                ushort    offset    = 0;

                // Read the serial number
                byte[] serialNumber = m_tpm[m_ownerAuth].NvRead(nvHandle, nvHandle, sizeof(long), offset);
                offset += sizeof(long);

                // Read the "valid from" date (today) in FileTime format
                byte[] validFrom = m_tpm[m_ownerAuth].NvRead(nvHandle, nvHandle, sizeof(long), offset);
                offset += sizeof(long);

                // Read size of keys from NV storage (located in the first 4 bytes)
                byte[] certSizeBlob = m_tpm[m_ownerAuth].NvRead(nvHandle, nvHandle, sizeof(int), offset);
                offset += sizeof(int);

                // Read keys from NV storage in 64-byte chunks
                int    certSize   = BitConverter.ToInt32(certSizeBlob, 0);
                byte[] rawData    = new byte[certSize];
                ushort index      = 0;
                ushort sizeToRead = 0;
                while (index < certSize)
                {
                    if ((certSize - index) < 64)
                    {
                        sizeToRead = (ushort)(certSize - index);
                    }
                    else
                    {
                        sizeToRead = 64;
                    }

                    byte[] dataToRead = m_tpm[m_ownerAuth].NvRead(nvHandle, nvHandle, sizeToRead, offset);
                    offset += sizeToRead;

                    for (int i = 0; i < sizeToRead; i++)
                    {
                        rawData[index + i] = dataToRead[i];
                    }

                    index += sizeToRead;
                }

                // Import
                TextReader textReader        = new StringReader(new string(Encoding.ASCII.GetChars(rawData)));
                PemReader  pemReader         = new PemReader(textReader);
                AsymmetricCipherKeyPair keys = (AsymmetricCipherKeyPair)pemReader.ReadObject();

                X509Name   CN            = new X509Name("CN=" + subjectName + ",DC=" + Utils.GetHostName());
                BigInteger SN            = new BigInteger(serialNumber).Abs();
                DateTime   validFromDate = DateTime.FromFileTime(BitConverter.ToInt64(validFrom, 0));

                // Certificate Generator
                X509V3CertificateGenerator cGenerator = new X509V3CertificateGenerator();
                cGenerator.SetSerialNumber(SN);
                cGenerator.SetSubjectDN(CN);
                cGenerator.SetIssuerDN(CN);
                cGenerator.SetNotBefore(validFromDate);
                cGenerator.SetNotAfter(validFromDate.AddYears(1));
                cGenerator.SetPublicKey(keys.Public);
                cGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage(new List <DerObjectIdentifier>()
                {
                    new DerObjectIdentifier("1.3.6.1.5.5.7.3.1")
                }));
                cGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier.Id, false, new AuthorityKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keys.Public), new GeneralNames(new GeneralName(CN)), SN));
                cGenerator.AddExtension(X509Extensions.SubjectAlternativeName, false, new GeneralNames(new GeneralName(GeneralName.UniformResourceIdentifier, applicationURI)));

                ISignatureFactory signatureFactory         = new Asn1SignatureFactory("SHA1withRSA", keys.Private, new SecureRandom());
                Org.BouncyCastle.X509.X509Certificate cert = cGenerator.Generate(signatureFactory);
                X509Certificate2 certificate = new X509Certificate2(cert.GetEncoded());

                RSACng rsa = new RSACng();
                RsaPrivateCrtKeyParameters keyParams = (RsaPrivateCrtKeyParameters)keys.Private;

                m_RSAParams = new RSAParameters();

                m_RSAParams.Modulus = new byte[keyParams.Modulus.ToByteArrayUnsigned().Length];
                keyParams.Modulus.ToByteArrayUnsigned().CopyTo(m_RSAParams.Modulus, 0);

                m_RSAParams.P = new byte[keyParams.P.ToByteArrayUnsigned().Length];
                keyParams.P.ToByteArrayUnsigned().CopyTo(m_RSAParams.P, 0);

                m_RSAParams.Q = new byte[keyParams.Q.ToByteArrayUnsigned().Length];
                keyParams.Q.ToByteArrayUnsigned().CopyTo(m_RSAParams.Q, 0);

                m_RSAParams.DP = new byte[keyParams.DP.ToByteArrayUnsigned().Length];
                keyParams.DP.ToByteArrayUnsigned().CopyTo(m_RSAParams.DP, 0);

                m_RSAParams.DQ = new byte[keyParams.DQ.ToByteArrayUnsigned().Length];
                keyParams.DQ.ToByteArrayUnsigned().CopyTo(m_RSAParams.DQ, 0);

                m_RSAParams.InverseQ = new byte[keyParams.QInv.ToByteArrayUnsigned().Length];
                keyParams.QInv.ToByteArrayUnsigned().CopyTo(m_RSAParams.InverseQ, 0);

                m_RSAParams.D = new byte[keyParams.Exponent.ToByteArrayUnsigned().Length];
                keyParams.Exponent.ToByteArrayUnsigned().CopyTo(m_RSAParams.D, 0);

                m_RSAParams.Exponent = new byte[keyParams.PublicExponent.ToByteArrayUnsigned().Length];
                keyParams.PublicExponent.ToByteArrayUnsigned().CopyTo(m_RSAParams.Exponent, 0);

                rsa.ImportParameters(m_RSAParams);
                if (rsa != null)
                {
                    int    inputBlockSize = rsa.KeySize / 8 - 42;
                    byte[] bytes1         = rsa.Encrypt(new byte[inputBlockSize], RSAEncryptionPadding.OaepSHA1);
                    byte[] bytes2         = rsa.Decrypt(bytes1, RSAEncryptionPadding.OaepSHA1);
                    if (bytes2 != null)
                    {
                        return(certificate);
                    }
                }
            }
            catch (Exception e)
            {
                Utils.Trace(e, "Could not load application certificate " + subjectName);
            }

            return(null);
        }
예제 #4
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;
        }
예제 #5
0
        /// <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,
            ref ushort keySize,
            ref ushort lifetimeInMonths,
            bool isCA)
        {
            // enforce recommended keysize unless lower value is enforced.
            if (keySize < 1024)
            {
                keySize = defaultKeySize;
            }

            if (keySize % 1024 != 0)
            {
                throw new ArgumentNullException("keySize", "KeySize must be a multiple of 1024.");
            }

            // enforce minimum lifetime.
            if (lifetimeInMonths < 1)
            {
                lifetimeInMonths = 1;
            }

            // parse the subject name if specified.
            List <string> subjectNameEntries = null;

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

            // check the application name.
            if (String.IsNullOrEmpty(applicationName))
            {
                if (subjectNameEntries == null)
                {
                    throw new ArgumentNullException("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="))
                    {
                        applicationName = subjectNameEntries[ii].Substring(3).Trim();
                        break;
                    }
                }
            }

            // 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("applicationUri", "Must specify a valid URL.");
            }

            // create the subject name,
            if (String.IsNullOrEmpty(subjectName))
            {
                subjectName = applicationName;
            }
        }
        /// <summary>
        /// Ensures that the application configuration is valid.
        /// </summary>
        /// <param name="applicationType">Type of the application.</param>
        public virtual async Task Validate(ApplicationType applicationType)
        {
            if (String.IsNullOrEmpty(ApplicationName))
            {
                throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "ApplicationName must be specified.");
            }

            if (SecurityConfiguration == null)
            {
                throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "SecurityConfiguration must be specified.");
            }

            SecurityConfiguration.Validate();

            // load private key
            await SecurityConfiguration.ApplicationCertificate.LoadPrivateKeyEx(SecurityConfiguration.CertificatePasswordProvider).ConfigureAwait(false);

            Func <string> generateDefaultUri = () =>
            {
                var sb = new StringBuilder();
                sb.Append("urn:");
                sb.Append(Utils.GetHostName());
                sb.Append(':');
                sb.Append(ApplicationName);
                return(sb.ToString());
            };

            if (String.IsNullOrEmpty(ApplicationUri))
            {
                m_applicationUri = generateDefaultUri();
            }

            if (applicationType == ApplicationType.Client || applicationType == ApplicationType.ClientAndServer)
            {
                if (ClientConfiguration == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "ClientConfiguration must be specified.");
                }

                ClientConfiguration.Validate();
            }

            if (applicationType == ApplicationType.Server || applicationType == ApplicationType.ClientAndServer)
            {
                if (ServerConfiguration == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "ServerConfiguration must be specified.");
                }

                ServerConfiguration.Validate();
            }

            if (applicationType == ApplicationType.DiscoveryServer)
            {
                if (DiscoveryServerConfiguration == null)
                {
                    throw ServiceResultException.Create(StatusCodes.BadConfigurationError, "DiscoveryServerConfiguration must be specified.");
                }

                DiscoveryServerConfiguration.Validate();
            }

            // toggle the state of the hi-res clock.
            HiResClock.Disabled = m_disableHiResClock;

            if (HiResClock.Disabled)
            {
                if (m_serverConfiguration != null)
                {
                    if (m_serverConfiguration.PublishingResolution < 50)
                    {
                        m_serverConfiguration.PublishingResolution = 50;
                    }
                }
            }

            await m_certificateValidator.Update(this.SecurityConfiguration).ConfigureAwait(false);
        }