/// <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]); } } }
/// <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); }
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); }
/// <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> /// 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); }