public void UseStd3AsciiRules_NonLDH_ASCII_Codepoint()
        {
            var idnStd3False = new IdnMapping { UseStd3AsciiRules = false };
            string unicode = "\u0030\u002D\u0045\u007A";

            Assert.Equal(unicode, idnStd3False.GetAscii(unicode), ignoreCase: true);
        }
 public void GetAscii_Invalid()
 {
     foreach (var entry in Factory.GetDataset())
     {
         if (!entry.GetASCIIResult.Success)
         {
             var map = new IdnMapping();
             Assert.Throws<ArgumentException>(() => map.GetAscii(entry.Source));
         }
     }
 }
 public void GetAscii_Success()
 {
     foreach (var entry in Factory.GetDataset())
     {
         if (entry.GetASCIIResult.Success)
         {
             var map = new IdnMapping();
             var asciiResult = map.GetAscii(entry.Source);
             Assert.Equal(entry.GetASCIIResult.Value, asciiResult, StringComparer.OrdinalIgnoreCase);
         }
     }
 }
        public void SimpleValidationTests()
        {
            var idn = new IdnMapping();

            Assert.Equal("xn--yda", idn.GetAscii("\u0101"));
            Assert.Equal("xn--yda", idn.GetAscii("\u0101", 0));
            Assert.Equal("xn--yda", idn.GetAscii("\u0101", 0, 1));

            Assert.Equal("xn--aa-cla", idn.GetAscii("\u0101\u0061\u0041"));
            Assert.Equal("xn--ab-dla", idn.GetAscii("\u0061\u0101\u0062"));
            Assert.Equal("xn--ab-ela", idn.GetAscii("\u0061\u0062\u0101"));
        }
Exemple #5
0
        public static void GetUnicodeThrows()
        {
            IdnMapping idnMapping = new IdnMapping();

            Assert.Throws<ArgumentNullException>("ascii", () => idnMapping.GetUnicode(null, -5));
            Assert.Throws<ArgumentNullException>("ascii", () => idnMapping.GetUnicode(null, -5, -10));
            Assert.Throws<ArgumentOutOfRangeException>("index", () => idnMapping.GetUnicode("abc", -5, -10));
            Assert.Throws<ArgumentOutOfRangeException>("count", () => idnMapping.GetUnicode("abc", 10, -10));
            Assert.Throws<ArgumentOutOfRangeException>("byteIndex", () => idnMapping.GetUnicode("abc", 4, 99));
            Assert.Throws<ArgumentOutOfRangeException>("ascii", () => idnMapping.GetUnicode("abc", 2, 2));
            Assert.Throws<ArgumentException>("ascii", () => idnMapping.GetUnicode("abc", 3, 0));
        }
 public static void GetUnicode_Invalid(IdnMapping idnMapping, string ascii, int index, int count, Type exceptionType)
 {
     if (ascii == null || index + count == ascii.Length)
     {
         if (ascii == null || index == 0)
         {
             Assert.Throws(exceptionType, () => idnMapping.GetUnicode(ascii));
         }
         Assert.Throws(exceptionType, () => idnMapping.GetUnicode(ascii, index));
     }
     Assert.Throws(exceptionType, () => idnMapping.GetUnicode(ascii, index, count));
 }
        public void FullyQualifiedDomainNameVsIndividualLabels()
        {
            var idn = new IdnMapping();

            // ASCII only code points
            Assert.Equal("\u0061\u0062\u0063", idn.GetAscii("\u0061\u0062\u0063"));
            // non-ASCII only code points
            Assert.Equal("xn--d9juau41awczczp", idn.GetAscii("\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067"));
            // ASCII and non-ASCII code points
            Assert.Equal("xn--de-jg4avhby1noc0d", idn.GetAscii("\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0"));
            // Fully Qualified Domain Name
            Assert.Equal("abc.xn--d9juau41awczczp.xn--de-jg4avhby1noc0d", idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0"));
        }
Exemple #8
0
        public void EmbeddedNulls()
        {
            var idn = new IdnMapping();

            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0101\u0000"));
            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0101\u0000", 0));
            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0101\u0000", 0, 2));
            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0101\u0000\u0101"));
            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0101\u0000\u0101", 0));
            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0101\u0000\u0101", 0, 3));
            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0101\u0000\u0101\u0000"));
            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0101\u0000\u0101\u0000", 0));
            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0101\u0000\u0101\u0000", 0, 4));
            Assert.Throws<ArgumentException>(() => idn.GetUnicode("abc\u0000", 0, 4));
            Assert.Throws<ArgumentException>(() => idn.GetUnicode("ab\u0000c", 0, 4));
        }
    private string DomainMapper(Match match)
    {
        // IdnMapping class with default property values.
        IdnMapping idn = new IdnMapping();

        string domainName = match.Groups[2].Value;
        try
        {
            domainName = idn.GetAscii(domainName);
        }
        catch (ArgumentException)
        {
            invalid = true;
        }
        return match.Groups[1].Value + domainName;
    }
        [InlineData("\u002D\u0062\u002D", true)] // Leading and trailing hyphen minus
        public void UseStd3AsciiRules_ChangesGetAsciiBehavior(string unicode, bool containsInvalidHyphen)
        {
            var idnStd3False = new IdnMapping { UseStd3AsciiRules = false };
            var idnStd3True = new IdnMapping { UseStd3AsciiRules = true };

            if (containsInvalidHyphen && !s_isWindows)
            {
                // ICU always fails on leading/trailing hyphens regardless of the Std3 rules option.
                Assert.Throws<ArgumentException>("unicode", () => idnStd3False.GetAscii(unicode));
            }
            else
            {
                Assert.Equal(unicode, idnStd3False.GetAscii(unicode));
            }

            Assert.Throws<ArgumentException>("unicode", () => idnStd3True.GetAscii(unicode));
        }
        [InlineData("\u002D\u0062\u002D", true)] // Leading and trailing hyphen minus
        public void UseStd3AsciiRules_ChangesGetAsciiBehavior(string unicode, bool containsInvalidHyphen)
        {
            var idnStd3False = new IdnMapping { UseStd3AsciiRules = false };
            var idnStd3True = new IdnMapping { UseStd3AsciiRules = true };

            if (containsInvalidHyphen && !s_isWindows)
            {
                // ICU always fails on leading/trailing hyphens regardless of the Std3 rules option.
                Assert.Throws<ArgumentException>("unicode", () => idnStd3False.GetAscii(unicode));
            }
            else
            {
                Assert.Equal(unicode, idnStd3False.GetAscii(unicode));
            }

            ArgumentException ae = Assert.Throws<ArgumentException>(() => idnStd3True.GetAscii(unicode));
            // sometimes the desktop returns "Unicode" instead of "unicode" for the parameter name.
            Assert.Equal("unicode", ae.ParamName, ignoreCase: true);
        }
        public void GetUnicode_Succes()
        {
            foreach (var entry in Factory.GetDataset())
            {
                if (entry.GetUnicodeResult.Success)
                {
                    try
                    {
                        var map = new IdnMapping { UseStd3AsciiRules = true, AllowUnassigned = true };
                        var unicodeResult = map.GetUnicode(entry.Source);

                        Assert.Equal(entry.GetUnicodeResult.Value, unicodeResult, StringComparer.OrdinalIgnoreCase);
                    }
                    catch (ArgumentException)
                    {
                        Assert.Equal(entry.GetUnicodeResult.Value, entry.Source, StringComparer.OrdinalIgnoreCase);
                    }
                }
            }
        }
    public static bool IsValidDomain(String domain)
    {
        Regex r = new Regex(IP_DOMAIN_REGEX, RegexOptions.IgnoreCase);
        Match m = r.Match(domain);
        if (m.Success)
        {
            IPAddress ipAddress;
            return IPAddress.TryParse(m.Groups[1].ToString(), out ipAddress);
        }

        Boolean mappingInvalid = false;
        try
        {
            domain = new IdnMapping().GetAscii(domain);
        }
        catch (ArgumentException)
        {
            mappingInvalid = true;
        }

        if (mappingInvalid)
        {
            return false;
        }

        if (Regex.IsMatch(domain, DOMAIN_NAME_REGEX, RegexOptions.IgnoreCase))
        {
            String[] group = domain.Split('.');
            if (group.Length >2)
            {
                return IsValidTld(group[2]);
            }
            return IsValidTld(group[1]);
        }
        return false;
    }
Exemple #14
0
        void Initialize()
        {
            if (port == defaultPort || port == 0)
            {
                new SmtpPermission(SmtpAccess.Connect).Demand();
            }
            else
            {
                new SmtpPermission(SmtpAccess.ConnectToUnrestrictedPort).Demand();
            }

            transport = new SmtpTransport(this);
            if (Logging.On)
            {
                Logging.Associate(Logging.Web, this, transport);
            }
            onSendCompletedDelegate = new SendOrPostCallback(SendCompletedWaitCallback);

            if (MailConfiguration.Smtp != null)
            {
                if (MailConfiguration.Smtp.Network != null)
                {
                    if (host == null || host.Length == 0)
                    {
                        host = MailConfiguration.Smtp.Network.Host;
                    }
                    if (port == 0)
                    {
                        port = MailConfiguration.Smtp.Network.Port;
                    }

                    transport.Credentials = MailConfiguration.Smtp.Network.Credential;
                    transport.EnableSsl   = MailConfiguration.Smtp.Network.EnableSsl;

                    if (MailConfiguration.Smtp.Network.TargetName != null)
                    {
                        targetName = MailConfiguration.Smtp.Network.TargetName;
                    }

                    // If the config file contains a domain to be used for the
                    // domain element in the client's EHLO or HELO message,
                    // use it.
                    //
                    // We do not validate whether the domain specified is valid.
                    // It is up to the administrators or user to use the right
                    // value for their scenario.
                    //
                    // Note: per section 4.1.4 of RFC2821, the domain element of
                    // the HELO/EHLO should be used for logging purposes. An
                    // SMTP server should not decide to route an email based on
                    // this value.
                    clientDomain = MailConfiguration.Smtp.Network.ClientDomain;
                }

                deliveryFormat = MailConfiguration.Smtp.DeliveryFormat;

                deliveryMethod = MailConfiguration.Smtp.DeliveryMethod;
                if (MailConfiguration.Smtp.SpecifiedPickupDirectory != null)
                {
                    pickupDirectoryLocation = MailConfiguration.Smtp.SpecifiedPickupDirectory.PickupDirectoryLocation;
                }
            }

            if (host != null && host.Length != 0)
            {
                host = host.Trim();
            }

            if (port == 0)
            {
                port = defaultPort;
            }

            if (this.targetName == null)
            {
                targetName = "SMTPSVC/" + host;
            }

            if (clientDomain == null)
            {
                // We use the local host name as the default client domain
                // for the client's EHLO or HELO message. This limits the
                // information about the host that we share. Additionally, the
                // FQDN is not available to us or useful to the server (internal
                // machine connecting to public server).

                // SMTP RFC's require ASCII only host names in the HELO/EHLO message.
                string     clientDomainRaw = IPGlobalProperties.InternalGetIPGlobalProperties().HostName;
                IdnMapping mapping         = new IdnMapping();
                try
                {
                    clientDomainRaw = mapping.GetAscii(clientDomainRaw);
                }
                catch (ArgumentException) { }

                // For some inputs GetAscii may fail (bad Unicode, etc).  If that happens
                // we must strip out any non-ASCII characters.
                // If we end up with no characters left, we use the string "LocalHost".  This
                // matches Outlook behavior.
                StringBuilder sb = new StringBuilder();
                char          ch;
                for (int i = 0; i < clientDomainRaw.Length; i++)
                {
                    ch = clientDomainRaw[i];
                    if ((ushort)ch <= 0x7F)
                    {
                        sb.Append(ch);
                    }
                }
                if (sb.Length > 0)
                {
                    clientDomain = sb.ToString();
                }
                else
                {
                    clientDomain = "LocalHost";
                }
            }
        }
Exemple #15
0
        private string ToPunyCode(string hostName)
        {
            var idn = new IdnMapping();

            return(idn.GetAscii(hostName));
        }
 public static void GetAscii_Invalid(IdnMapping idnMapping, string unicode, int index, int count, Type exceptionType)
 {
     if (unicode == null || index + count == unicode.Length)
     {
         if (unicode == null || index == 0)
         {
             Assert.Throws(exceptionType, () => idnMapping.GetAscii(unicode));
         }
         Assert.Throws(exceptionType, () => idnMapping.GetAscii(unicode, index));
     }
     Assert.Throws(exceptionType, () => idnMapping.GetAscii(unicode, index, count));
 }
    public bool ValidateEmail(string email)
    {
        if (string.IsNullOrWhiteSpace(email))
        {
            Message.instance.Show(MessageClass.ERROR_EMAIL_EMPTY);
            return(false);
        }

        try
        {
            // Normalize the domain
            email = Regex.Replace(email, @"(@)(.+)$", DomainMapper,
                                  RegexOptions.None, TimeSpan.FromMilliseconds(200));

            // Examines the domain part of the email and normalizes it.
            string DomainMapper(Match match)
            {
                // Use IdnMapping class to convert Unicode domain names.
                var idn = new IdnMapping();

                // Pull out and process domain name (throws ArgumentException on invalid)
                var domainName = idn.GetAscii(match.Groups[2].Value);

                return(match.Groups[1].Value + domainName);
            }
        }
        catch (RegexMatchTimeoutException)
        {
            Message.instance.Show(MessageClass.ERROR_EMAIL_INVALID);
            return(false);
        }
        catch (ArgumentException)
        {
            Message.instance.Show(MessageClass.ERROR_EMAIL_INVALID);
            return(false);
        }

        try
        {
            if (!Regex.IsMatch(email,
                               @"^(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))" +
                               @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-0-9a-z]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$",
                               RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250)))
            {
                Message.instance.Show(MessageClass.ERROR_EMAIL_INVALID);
                return(false);
            }
        }
        catch (RegexMatchTimeoutException)
        {
            Message.instance.Show(MessageClass.ERROR_EMAIL_INVALID);
            return(false);
        }

        var requisicaoWeb = WebRequest.CreateHttp(ConstantClass.SERVER_URL + "Person/Email?email=" + email);

        requisicaoWeb.Method      = "GET";
        requisicaoWeb.ContentType = "text";
        requisicaoWeb.UserAgent   = "RequisicaoWebDemo";

        using (var resposta = requisicaoWeb.GetResponse())
        {
            var          streamDados = resposta.GetResponseStream();
            StreamReader reader      = new StreamReader(streamDados);
            object       objResponse = reader.ReadToEnd();

            if (bool.Parse(objResponse.ToString()) == false)
            {
                Message.instance.Show(MessageClass.ERROR_EMAIL_ALREADY_EXISTS);
                return(false);
            }

            streamDados.Close();
            resposta.Close();
        }

        return(true);
    }
Exemple #18
0
        public void SurrogatePairsSeparatedByAscii()
        {
            var idn = new IdnMapping();

            Assert.Equal("xn--ab-ic6nfag", idn.GetAscii("\uD800\uDF00\u0061\uD800\uDF01\u0042\uD800\uDF02"));
        }
 public HeuristicLinkDetector(IEnumerable <string> topLevelDomains)
 {
     TopLevelDomains = new HashSet <string>(topLevelDomains);
     IDNMapping      = new IdnMapping();
 }
Exemple #20
0
        public override async Task PrepareChallenge()
        {
            // Check for substitute domains
            if (_settings.Validation.AllowDnsSubstitution)
            {
                try
                {
                    // Resolve CNAME in DNS
                    var client = await _dnsClient.GetClients(Challenge.DnsRecordName);

                    var(_, cname) = await client.First().GetTextRecordValues(Challenge.DnsRecordName, 0);

                    // Normalize CNAME
                    var idn = new IdnMapping();
                    cname = cname.ToLower().Trim().TrimEnd('.');
                    cname = idn.GetAscii(cname);

                    // Substitute
                    if (cname != Challenge.DnsRecordName)
                    {
                        _log.Information("Detected that {DnsRecordName} is a CNAME that leads to {cname}", Challenge.DnsRecordName, cname);
                        _recordName = cname;
                    }
                }
                catch (Exception ex)
                {
                    _log.Debug("Error checking for substitute domains: {ex}", ex.Message);
                }
            }

            // Create record
            await CreateRecord(_recordName ?? Challenge.DnsRecordName, Challenge.DnsRecordValue);

            _log.Information("Answer should now be available at {answerUri}", _recordName);

            // Verify that the record was created succesfully and wait for possible
            // propagation/caching/TTL issues to resolve themselves naturally
            var retry        = 0;
            var maxRetries   = _settings.Validation.PreValidateDnsRetryCount;
            var retrySeconds = _settings.Validation.PreValidateDnsRetryInterval;

            while (_settings.Validation.PreValidateDns)
            {
                if (await PreValidate(retry))
                {
                    break;
                }
                else
                {
                    retry += 1;
                    if (retry > maxRetries)
                    {
                        _log.Information("It looks like validation is going to fail, but we will try now anyway...");
                        break;
                    }
                    else
                    {
                        _log.Information("Will retry in {s} seconds (retry {i}/{j})...", retrySeconds, retry, maxRetries);
                        Thread.Sleep(retrySeconds * 1000);
                    }
                }
            }
        }
Exemple #21
0
        public void SurrogatePairsSeparatedByAsciiAndNonAscii()
        {
            var idn = new IdnMapping();

            Assert.Equal("xn--a-nha4529qfag", idn.GetAscii("\uD800\uDF00\u0101\uD800\uDF01\u0061\uD800\uDF02"));
        }
Exemple #22
0
        /// <summary>
        /// Request certificate from the ACME server
        /// </summary>
        /// <param name="csrPlugin">Plugin used to generate CSR if it has not been provided in the target</param>
        /// <param name="runLevel"></param>
        /// <param name="renewal"></param>
        /// <param name="target"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        public async Task <CertificateInfo> RequestCertificate(ICsrPlugin?csrPlugin, RunLevel runLevel, Order order)
        {
            if (order.Details == null)
            {
                throw new InvalidOperationException("No order details found");
            }

            // What are we going to get?
            var cacheKey    = CacheKey(order);
            var pfxFileInfo = new FileInfo(GetPath(order.Renewal, $"-{cacheKey}{PfxPostFix}"));

            // Determine/check the common name
            var identifiers     = order.Target.GetHosts(false);
            var commonNameUni   = order.Target.CommonName;
            var commonNameAscii = string.Empty;

            if (!string.IsNullOrWhiteSpace(commonNameUni))
            {
                var idn = new IdnMapping();
                commonNameAscii = idn.GetAscii(commonNameUni);
                if (!identifiers.Contains(commonNameAscii, StringComparer.InvariantCultureIgnoreCase))
                {
                    _log.Warning($"Common name {commonNameUni} provided is invalid.");
                    commonNameAscii = identifiers.First();
                    commonNameUni   = idn.GetUnicode(commonNameAscii);
                }
            }

            // Determine the friendly name base (for the renewal)
            var friendlyNameBase = order.Renewal.FriendlyName;

            if (string.IsNullOrEmpty(friendlyNameBase))
            {
                friendlyNameBase = order.Target.FriendlyName;
            }
            if (string.IsNullOrEmpty(friendlyNameBase))
            {
                friendlyNameBase = commonNameUni;
            }

            // Determine the friendly name for this specific certificate
            var friendlyNameIntermediate = friendlyNameBase;

            if (!string.IsNullOrEmpty(order.FriendlyNamePart))
            {
                friendlyNameIntermediate += $" [{order.FriendlyNamePart}]";
            }
            var friendlyName = $"{friendlyNameIntermediate} @ {_inputService.FormatDate(DateTime.Now)}";

            // Try using cached certificate first to avoid rate limiting during
            // (initial?) deployment troubleshooting. Real certificate requests
            // will only be done once per day maximum unless the --force parameter
            // is used.
            var cache = CachedInfo(order);

            if (cache != null && cache.CacheFile != null)
            {
                if (cache.CacheFile.LastWriteTime > DateTime.Now.AddDays(_settings.Cache.ReuseDays * -1))
                {
                    if (runLevel.HasFlag(RunLevel.IgnoreCache))
                    {
                        _log.Warning("Cached certificate available on disk but not used due to --{switch} switch.",
                                     nameof(MainArguments.Force).ToLower());
                    }
                    else
                    {
                        _log.Warning("Using cached certificate for {friendlyName}. To force a new request of the " +
                                     "certificate within {days} days, run with the --{switch} switch.",
                                     friendlyNameIntermediate,
                                     _settings.Cache.ReuseDays,
                                     nameof(MainArguments.Force).ToLower());
                        return(cache);
                    }
                }
            }

            if (order.Details.Payload.Status != AcmeClient.OrderValid)
            {
                // Clear cache and write new cert
                ClearCache(order.Renewal, postfix: CsrPostFix);

                if (order.Target.CsrBytes == null)
                {
                    if (csrPlugin == null)
                    {
                        throw new InvalidOperationException("Missing csrPlugin");
                    }
                    // Backwards compatible with existing keys, which are not split per order yet.
                    var keyFile = new FileInfo(GetPath(order.Renewal, $".keys"));
                    if (!keyFile.Exists)
                    {
                        keyFile = new FileInfo(GetPath(order.Renewal, $"-{cacheKey}.keys"));
                    }
                    var csr = await csrPlugin.GenerateCsr(keyFile.FullName, commonNameAscii, identifiers);

                    var keySet = await csrPlugin.GetKeys();

                    order.Target.CsrBytes   = csr.GetDerEncoded();
                    order.Target.PrivateKey = keySet.Private;
                    var csrPath = GetPath(order.Renewal, $"-{cacheKey}{CsrPostFix}");
                    await File.WriteAllTextAsync(csrPath, _pemService.GetPem("CERTIFICATE REQUEST", order.Target.CsrBytes));

                    _log.Debug("CSR stored at {path} in certificate cache folder {folder}", Path.GetFileName(csrPath), Path.GetDirectoryName(csrPath));
                }

                _log.Verbose("Submitting CSR");
                order.Details = await _client.SubmitCsr(order.Details, order.Target.CsrBytes);

                if (order.Details.Payload.Status != AcmeClient.OrderValid)
                {
                    _log.Error("Unexpected order status {status}", order.Details.Payload.Status);
                    throw new Exception($"Unable to complete order");
                }
            }

            _log.Information("Requesting certificate {friendlyName}", friendlyNameIntermediate);
            var certInfo = await _client.GetCertificate(order.Details);

            if (certInfo == null || certInfo.Certificate == null)
            {
                throw new Exception($"Unable to get certificate");
            }
            var alternatives = new List <X509Certificate2Collection>
            {
                ParseCertificate(certInfo.Certificate, friendlyName, order.Target.PrivateKey)
            };

            foreach (var alt in certInfo.Links["alternate"])
            {
                try
                {
                    var altCertRaw = await _client.GetCertificate(alt);

                    var altCert = ParseCertificate(altCertRaw, friendlyName, order.Target.PrivateKey);
                    alternatives.Add(altCert);
                }
                catch (Exception ex)
                {
                    _log.Warning("Unable to get alternate certificate: {ex}", ex.Message);
                }
            }
            var selected = Select(alternatives);

            ClearCache(order.Renewal, postfix: $"*{PfxPostFix}");
            ClearCache(order.Renewal, postfix: $"*{PfxPostFixLegacy}");
            await File.WriteAllBytesAsync(pfxFileInfo.FullName, selected.Export(X509ContentType.Pfx, order.Renewal.PfxPassword?.Value));

            _log.Debug("Certificate written to cache file {path} in certificate cache folder {folder}. It will be " +
                       "reused when renewing within {x} day(s) as long as the Target and Csr parameters remain the same and " +
                       "the --force switch is not used.",
                       pfxFileInfo.Name,
                       pfxFileInfo.Directory.FullName,
                       _settings.Cache.ReuseDays);

            if (csrPlugin != null)
            {
                try
                {
                    var cert = selected.
                               OfType <X509Certificate2>().
                               Where(x => x.HasPrivateKey).
                               FirstOrDefault();
                    if (cert != null)
                    {
                        var certIndex  = selected.IndexOf(cert);
                        var newVersion = await csrPlugin.PostProcess(cert);

                        if (newVersion != cert)
                        {
                            newVersion.FriendlyName = friendlyName;
                            selected[certIndex]     = newVersion;
                            await File.WriteAllBytesAsync(pfxFileInfo.FullName, selected.Export(X509ContentType.Pfx, order.Renewal.PfxPassword?.Value));

                            newVersion.Dispose();
                        }
                    }
                }
                catch (Exception ex)
                {
                    _log.Warning("Private key conversion error: {ex}", ex.Message);
                }
            }

            pfxFileInfo.Refresh();

            // Update LastFriendlyName so that the user sees
            // the most recently issued friendlyName in
            // the WACS GUI
            order.Renewal.LastFriendlyName = friendlyNameBase;

            // Recreate X509Certificate2 with correct flags for Store/Install
            return(FromCache(pfxFileInfo, order.Renewal.PfxPassword?.Value));
        }
Exemple #23
0
        /// <summary>
        /// Request certificate from the ACME server
        /// </summary>
        /// <param name="csrPlugin">Plugin used to generate CSR if it has not been provided in the target</param>
        /// <param name="runLevel"></param>
        /// <param name="renewal"></param>
        /// <param name="target"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        public async Task <CertificateInfo> RequestCertificate(
            ICsrPlugin?csrPlugin,
            RunLevel runLevel,
            Renewal renewal,
            Target target,
            OrderDetails order)
        {
            // What are we going to get?
            var cacheKey    = CacheKey(renewal, target);
            var pfxFileInfo = new FileInfo(GetPath(renewal, $"-{cacheKey}{PfxPostFix}"));

            // Determine/check the common name
            var identifiers     = target.GetHosts(false);
            var commonNameUni   = target.CommonName;
            var commonNameAscii = string.Empty;

            if (!string.IsNullOrWhiteSpace(commonNameUni))
            {
                var idn = new IdnMapping();
                commonNameAscii = idn.GetAscii(commonNameUni);
                if (!identifiers.Contains(commonNameAscii, StringComparer.InvariantCultureIgnoreCase))
                {
                    _log.Warning($"Common name {commonNameUni} provided is invalid.");
                    commonNameAscii = identifiers.First();
                    commonNameUni   = idn.GetUnicode(commonNameAscii);
                }
            }

            // Determine the friendly name
            var friendlyNameBase = renewal.FriendlyName;

            if (string.IsNullOrEmpty(friendlyNameBase))
            {
                friendlyNameBase = target.FriendlyName;
            }
            if (string.IsNullOrEmpty(friendlyNameBase))
            {
                friendlyNameBase = commonNameUni;
            }
            var friendyName = $"{friendlyNameBase} @ {_inputService.FormatDate(DateTime.Now)}";

            // Try using cached certificate first to avoid rate limiting during
            // (initial?) deployment troubleshooting. Real certificate requests
            // will only be done once per day maximum unless the --force parameter
            // is used.
            var cache = CachedInfo(renewal, target);

            if (cache != null && cache.CacheFile != null)
            {
                if (cache.CacheFile.LastWriteTime >
                    DateTime.Now.AddDays(_settings.Cache.ReuseDays * -1))
                {
                    if (runLevel.HasFlag(RunLevel.IgnoreCache))
                    {
                        _log.Warning("Cached certificate available but not used with the --{switch} switch. " +
                                     "Use 'Manage renewals > Run renewal' in the main menu to run unscheduled " +
                                     "renewals without hitting rate limits.",
                                     nameof(MainArguments.Force).ToLower());
                    }
                    else
                    {
                        _log.Warning("Using cached certificate for {friendlyName}. To force issue of a " +
                                     "new certificate within {days} days, delete the .pfx file from the CertificatePath " +
                                     "or run with the --{switch} switch. Be ware that you might run into rate " +
                                     "limits doing so.",
                                     friendlyNameBase,
                                     _settings.Cache.ReuseDays,
                                     nameof(MainArguments.Force).ToLower());
                        return(cache);
                    }
                }
            }

            // Clear cache and write new cert
            ClearCache(renewal, postfix: CsrPostFix);

            if (target.CsrBytes == null)
            {
                if (csrPlugin == null)
                {
                    throw new InvalidOperationException("Missing csrPlugin");
                }
                var keyFile = GetPath(renewal, ".keys");
                var csr     = await csrPlugin.GenerateCsr(keyFile, commonNameAscii, identifiers);

                var keySet = await csrPlugin.GetKeys();

                target.CsrBytes   = csr.GetDerEncoded();
                target.PrivateKey = keySet.Private;
                var csrPath = GetPath(renewal, CsrPostFix);
                File.WriteAllText(csrPath, _pemService.GetPem("CERTIFICATE REQUEST", target.CsrBytes));
                _log.Debug("CSR stored at {path} in certificate cache folder {folder}", Path.GetFileName(csrPath), Path.GetDirectoryName(csrPath));
            }

            _log.Verbose("Submitting CSR");
            order = await _client.SubmitCsr(order, target.CsrBytes);

            if (order.Payload.Status != AcmeClient.OrderValid)
            {
                _log.Error("Unexpected order status {status}", order.Payload.Status);
                throw new Exception($"Unable to complete order");
            }

            _log.Information("Requesting certificate {friendlyName}", friendlyNameBase);
            var rawCertificate = await _client.GetCertificate(order);

            if (rawCertificate == null)
            {
                throw new Exception($"Unable to get certificate");
            }

            // Build pfx archive including any intermediates provided
            var          text        = Encoding.UTF8.GetString(rawCertificate);
            var          pfx         = new bc.Pkcs.Pkcs12Store();
            var          startIndex  = 0;
            var          endIndex    = 0;
            const string startString = "-----BEGIN CERTIFICATE-----";
            const string endString   = "-----END CERTIFICATE-----";

            while (true)
            {
                startIndex = text.IndexOf(startString, startIndex);
                if (startIndex < 0)
                {
                    break;
                }
                endIndex = text.IndexOf(endString, startIndex);
                if (endIndex < 0)
                {
                    break;
                }
                endIndex += endString.Length;
                var pem           = text[startIndex..endIndex];
Exemple #24
0
        public static List <string> GetImportableItems(int packageId, int itemTypeId)
        {
            List <string> items = new List <string>();

            // check account
            int accountCheck = SecurityContext.CheckAccount(DemandAccount.IsAdmin | DemandAccount.NotDemo);

            if (accountCheck < 0)
            {
                return(items);
            }

            // load item type
            if (itemTypeId > 0)
            {
                ServiceProviderItemType itemType = PackageController.GetServiceItemType(itemTypeId);

                // load group
                ResourceGroupInfo group = ServerController.GetResourceGroup(itemType.GroupId);

                // Is it DNS Zones? Then create a IDN Mapping object
                var isDnsZones = group.GroupName == "DNS";
                var idn        = new IdnMapping();

                // get service id
                int serviceId = PackageController.GetPackageServiceId(packageId, group.GroupName);
                if (serviceId == 0)
                {
                    return(items);
                }

                // Read existing packages and serviceitems
                DataTable dtServiceItems = PackageController.GetServiceItemsDataSet(serviceId).Tables[0];
                DataTable dtPackageItems = PackageController.GetPackageItemsDataSet(packageId).Tables[0];

                // Add already existing packages and serviceitems to lowercase ignorelist
                List <string> ignorelist = new List <string>();
                foreach (DataRow dr in dtServiceItems.Rows)
                {
                    string serviceItemName   = (string)dr["ItemName"];
                    int    serviceItemTypeId = (int)dr["ItemTypeId"];

                    if (serviceItemTypeId == itemTypeId)
                    {
                        if (!ignorelist.Contains(serviceItemName))
                        {
                            ignorelist.Add(serviceItemName.ToLower());
                        }
                    }
                }
                foreach (DataRow dr in dtPackageItems.Rows)
                {
                    string packageItemName   = (string)dr["ItemName"];
                    int    packageItemTypeId = (int)dr["ItemTypeId"];

                    if (packageItemTypeId == itemTypeId)
                    {
                        if (!ignorelist.Contains(packageItemName))
                        {
                            ignorelist.Add(packageItemName.ToLower());
                        }
                    }
                }

                // instantiate controller
                IImportController ctrl = null;
                try
                {
                    List <string> importableItems = null;
                    ctrl = Activator.CreateInstance(Type.GetType(group.GroupController)) as IImportController;
                    if (ctrl != null)
                    {
                        importableItems = ctrl.GetImportableItems(packageId, itemTypeId, Type.GetType(itemType.TypeName), group);
                    }

                    foreach (string importableItem in importableItems)
                    {
                        if (!ignorelist.Contains(importableItem.ToLower()))
                        {
                            var itemToImport = importableItem;

                            // For DNS zones the compare has been made using ascii, convert to unicode if necessary to make the list of items easier to read
                            if (isDnsZones && itemToImport.StartsWith("xn--"))
                            {
                                itemToImport = idn.GetUnicode(importableItem);
                            }

                            items.Add(itemToImport);
                        }
                    }
                }
                catch { /* do nothing */ }
            }
            else
            {
                return(GetImportableCustomItems(packageId, itemTypeId));
            }

            return(items);
        }
Exemple #25
0
        public void SurrogatePairsSeparatedByAsciiAndNonAscii()
        {
            var idn = new IdnMapping();

            Assert.Equal("xn--a-nha4529qfag", idn.GetAscii("\uD800\uDF00\u0101\uD800\uDF01\u0061\uD800\uDF02"));
        }
Exemple #26
0
        public void SurrogatePairsSeparatedByNonAscii()
        {
            var idn = new IdnMapping();

            Assert.Equal("xn--yda263v6b6kfag", idn.GetAscii("\uD800\uDF00\u0101\uD800\uDF01\u305D\uD800\uDF02"));
        }
Exemple #27
0
        public void EmbeddedDomainNameConversion()
        {
            var idn = new IdnMapping();

            Assert.Equal("abc.xn--d9juau41awczczp.xn--de-jg4avhby1noc0d", idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 0));
            Assert.Equal("abc.xn--d9juau41awczczp", idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 0, 11));
            Assert.Equal("abc.xn--d9juau41awczczp.", idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 0, 12));
            Assert.Equal("abc.xn--d9juau41awczczp.xn--de-jg4avhby1noc0d", idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 0, 21));
            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 3));
            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 3, 8));
            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 3, 9));
            Assert.Equal("xn--d9juau41awczczp.xn--de-jg4avhby1noc0d", idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 4));
            Assert.Equal("xn--d9juau41awczczp", idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 4, 7));
            Assert.Equal("xn--d9juau41awczczp.", idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 4, 8));
            Assert.Equal("xn--d9juau41awczczp.xn--de-jg4avhby1noc0d", idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 4, 17));
            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 11));
            Assert.Throws<ArgumentException>(() => idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 11, 10));
            Assert.Equal("xn--de-jg4avhby1noc0d", idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 12));
            Assert.Equal("xn--de-jg4avhby1noc0d", idn.GetAscii("\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", 12, 9));
        }
Exemple #28
0
        /// <summary>
        /// Convert puny-code to unicode
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        private string ProcessName(string name)
        {
            var idn = new IdnMapping();

            return(idn.GetUnicode(name.ToLower()));
        }
Exemple #29
0
        public void SurrogatePairsSeparatedByAscii()
        {
            var idn = new IdnMapping();

            Assert.Equal("xn--ab-ic6nfag", idn.GetAscii("\uD800\uDF00\u0061\uD800\uDF01\u0042\uD800\uDF02"));
        }
Exemple #30
0
        protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List <object> output)
        {
            if (!this.suppressRead && !this.handshakeFailed)
            {
                int       writerIndex = input.WriterIndex;
                Exception error       = null;
                try
                {
                    bool continueLoop = true;
                    for (int i = 0; i < MAX_SSL_RECORDS && continueLoop; i++)
                    {
                        int readerIndex   = input.ReaderIndex;
                        int readableBytes = writerIndex - readerIndex;
                        if (readableBytes < TlsUtils.SSL_RECORD_HEADER_LENGTH)
                        {
                            // Not enough data to determine the record type and length.
                            return;
                        }

                        int command = input.GetByte(readerIndex);
                        // tls, but not handshake command
                        switch (command)
                        {
                        case TlsUtils.SSL_CONTENT_TYPE_CHANGE_CIPHER_SPEC:
                        case TlsUtils.SSL_CONTENT_TYPE_ALERT:
                            int len = TlsUtils.GetEncryptedPacketLength(input, readerIndex);

                            // Not an SSL/TLS packet
                            if (len == TlsUtils.NOT_ENCRYPTED)
                            {
                                this.handshakeFailed = true;
                                var e = new NotSslRecordException(
                                    "not an SSL/TLS record: " + ByteBufferUtil.HexDump(input));
                                input.SkipBytes(input.ReadableBytes);

                                TlsUtils.NotifyHandshakeFailure(context, e);
                                throw e;
                            }
                            if (len == TlsUtils.NOT_ENOUGH_DATA ||
                                writerIndex - readerIndex - TlsUtils.SSL_RECORD_HEADER_LENGTH < len)
                            {
                                // Not enough data
                                return;
                            }

                            // increase readerIndex and try again.
                            input.SkipBytes(len);
                            continue;

                        case TlsUtils.SSL_CONTENT_TYPE_HANDSHAKE:
                            int majorVersion = input.GetByte(readerIndex + 1);

                            // SSLv3 or TLS
                            if (majorVersion == 3)
                            {
                                int packetLength = input.GetUnsignedShort(readerIndex + 3) + TlsUtils.SSL_RECORD_HEADER_LENGTH;

                                if (readableBytes < packetLength)
                                {
                                    // client hello incomplete; try again to decode once more data is ready.
                                    return;
                                }

                                // See https://tools.ietf.org/html/rfc5246#section-7.4.1.2
                                //
                                // Decode the ssl client hello packet.
                                // We have to skip bytes until SessionID (which sum to 43 bytes).
                                //
                                // struct {
                                //    ProtocolVersion client_version;
                                //    Random random;
                                //    SessionID session_id;
                                //    CipherSuite cipher_suites<2..2^16-2>;
                                //    CompressionMethod compression_methods<1..2^8-1>;
                                //    select (extensions_present) {
                                //        case false:
                                //            struct {};
                                //        case true:
                                //            Extension extensions<0..2^16-1>;
                                //    };
                                // } ClientHello;
                                //

                                int endOffset = readerIndex + packetLength;
                                int offset    = readerIndex + 43;

                                if (endOffset - offset < 6)
                                {
                                    continueLoop = false;
                                    break;
                                }

                                int sessionIdLength = input.GetByte(offset);
                                offset += sessionIdLength + 1;

                                int cipherSuitesLength = input.GetUnsignedShort(offset);
                                offset += cipherSuitesLength + 2;

                                int compressionMethodLength = input.GetByte(offset);
                                offset += compressionMethodLength + 1;

                                int extensionsLength = input.GetUnsignedShort(offset);
                                offset += 2;
                                int extensionsLimit = offset + extensionsLength;

                                if (extensionsLimit > endOffset)
                                {
                                    // Extensions should never exceed the record boundary.
                                    continueLoop = false;
                                    break;
                                }

                                for (;;)
                                {
                                    if (extensionsLimit - offset < 4)
                                    {
                                        continueLoop = false;
                                        break;
                                    }

                                    int extensionType = input.GetUnsignedShort(offset);
                                    offset += 2;

                                    int extensionLength = input.GetUnsignedShort(offset);
                                    offset += 2;

                                    if (extensionsLimit - offset < extensionLength)
                                    {
                                        continueLoop = false;
                                        break;
                                    }

                                    // SNI
                                    // See https://tools.ietf.org/html/rfc6066#page-6
                                    if (extensionType == 0)
                                    {
                                        offset += 2;
                                        if (extensionsLimit - offset < 3)
                                        {
                                            continueLoop = false;
                                            break;
                                        }

                                        int serverNameType = input.GetByte(offset);
                                        offset++;

                                        if (serverNameType == 0)
                                        {
                                            int serverNameLength = input.GetUnsignedShort(offset);
                                            offset += 2;

                                            if (serverNameLength <= 0 || extensionsLimit - offset < serverNameLength)
                                            {
                                                continueLoop = false;
                                                break;
                                            }

                                            string hostname = input.ToString(offset, serverNameLength, Encoding.UTF8);
                                            //try
                                            //{
                                            //    select(ctx, IDN.toASCII(hostname,
                                            //                            IDN.ALLOW_UNASSIGNED).toLowerCase(Locale.US));
                                            //}
                                            //catch (Throwable t)
                                            //{
                                            //    PlatformDependent.throwException(t);
                                            //}

                                            var idn = new IdnMapping()
                                            {
                                                AllowUnassigned = true
                                            };

                                            hostname = idn.GetAscii(hostname);
#if NETSTANDARD1_3
                                            // TODO: netcore does not have culture sensitive tolower()
                                            hostname = hostname.ToLowerInvariant();
#else
                                            hostname = hostname.ToLower(new CultureInfo("en-US"));
#endif
                                            this.Select(context, hostname);
                                            return;
                                        }
                                        else
                                        {
                                            // invalid enum value
                                            continueLoop = false;
                                            break;
                                        }
                                    }

                                    offset += extensionLength;
                                }
                            }

                            break;

                        // Fall-through
                        default:
                            //not tls, ssl or application data, do not try sni
                            continueLoop = false;
                            break;
                        }
                    }
                }
                catch (Exception e)
                {
                    error = e;

                    // unexpected encoding, ignore sni and use default
                    if (Logger.DebugEnabled)
                    {
                        Logger.Warn($"Unexpected client hello packet: {ByteBufferUtil.HexDump(input)}", e);
                    }
                }

                if (this.serverTlsSniSettings.DefaultServerHostName != null)
                {
                    // Just select the default server TLS setting
                    this.Select(context, this.serverTlsSniSettings.DefaultServerHostName);
                }
                else
                {
                    this.handshakeFailed = true;
                    var e = new DecoderException($"failed to get the server TLS setting {error}");
                    TlsUtils.NotifyHandshakeFailure(context, e);
                    throw e;
                }
            }
        }
Exemple #31
0
        public void IllegalChars(bool useStd3AsciiRules)
        {
            var idn = new IdnMapping();
            idn.UseStd3AsciiRules = useStd3AsciiRules;
            string testString;

            for (int i = 0; i <= 0x1F; i++)
            {
                testString = "abc" + new string((char)i, 1) + "def";
                Assert.Throws<ArgumentException>(() => idn.GetAscii(testString));
                Assert.Throws<ArgumentException>(() => idn.GetUnicode(testString));
            }

            testString = "abc" + new string((char)0x7F, 1) + "def";
            Assert.Throws<ArgumentException>(() => idn.GetAscii(testString));
            Assert.Throws<ArgumentException>(() => idn.GetUnicode(testString));
        }
        /// <summary>
        /// Request certificate from the ACME server
        /// </summary>
        /// <param name="binding"></param>
        /// <returns></returns>
        public CertificateInfo RequestCertificate(ICsrPlugin csrPlugin, Renewal renewal, Target target, OrderDetails order)
        {
            // What are we going to get?
            var pfxFileInfo = new FileInfo(PfxFilePath(renewal));

            // Determine/check the common name
            var identifiers = target.GetHosts(false);
            var commonName  = target.CommonName;

            if (!string.IsNullOrWhiteSpace(commonName))
            {
                var idn = new IdnMapping();
                commonName = idn.GetAscii(commonName);
                if (!identifiers.Contains(commonName, StringComparer.InvariantCultureIgnoreCase))
                {
                    _log.Warning($"Common name {commonName} provided is invalid.");
                    commonName = identifiers.First();
                }
            }

            // Determine the friendly name
            var friendlyName = renewal.FriendlyName;

            if (string.IsNullOrEmpty(friendlyName))
            {
                friendlyName = target.FriendlyName;
            }
            if (string.IsNullOrEmpty(friendlyName))
            {
                friendlyName = commonName;
            }

            // Try using cached certificate first to avoid rate limiting during
            // (initial?) deployment troubleshooting. Real certificate requests
            // will only be done once per day maximum unless the --force parameter
            // is used.
            var cache = CachedInfo(renewal);

            if (cache != null &&
                cache.PfxFile.LastWriteTime > DateTime.Now.AddDays(-1) &&
                cache.Match(target))
            {
                if (_runLevel.HasFlag(RunLevel.Force))
                {
                    _log.Warning("Cached certificate available but not used with --{switch}. Use 'Renew specific' or " +
                                 "'Renew all' in the main menu to run unscheduled renewals without hitting rate limits.",
                                 nameof(MainArguments.Force).ToLower());
                }
                else
                {
                    _log.Warning("Using cached certificate for {friendlyName}. To force issue of a new certificate within " +
                                 "24 hours, delete the .pfx file from the CertificatePath or run with the --{switch} switch. " +
                                 "Be ware that you might run into rate limits doing so.",
                                 friendlyName,
                                 nameof(MainArguments.Force).ToLower());
                    return(cache);
                }
            }

            var csr      = csrPlugin.GenerateCsr(commonName, identifiers);
            var csrBytes = csr.CreateSigningRequest();

            order = _client.SubmitCsr(order, csrBytes);
            File.WriteAllText(GetPath(renewal, "-csr.pem"), GetPem("CERTIFICATE REQUEST", csrBytes));

            _log.Information("Requesting certificate {friendlyName}", friendlyName);
            var rawCertificate = _client.GetCertificate(order);

            if (rawCertificate == null)
            {
                throw new Exception($"Unable to get certificate");
            }

            var certificate       = new X509Certificate2(rawCertificate);
            var certificateExport = certificate.Export(X509ContentType.Cert);
            var crtPem            = GetPem("CERTIFICATE", certificateExport);

            // Get issuer certificate
            var chain = new X509Chain();

            chain.Build(certificate);
            X509Certificate2 issuerCertificate = chain.ChainElements[1].Certificate;
            var issuerCertificateExport        = issuerCertificate.Export(X509ContentType.Cert);
            var issuerPem = GetPem("CERTIFICATE", issuerCertificateExport);

            // Build pfx archive
            var pfx                = new bc.Pkcs.Pkcs12Store();
            var bcCertificate      = ParsePem <bc.X509.X509Certificate>(crtPem);
            var bcCertificateEntry = new bc.Pkcs.X509CertificateEntry(bcCertificate);
            var bcCertificateAlias = bcCertificate.SubjectDN.ToString();
            var bcPrivateKeyEntry  = new bc.Pkcs.AsymmetricKeyEntry(csrPlugin.GetPrivateKey());

            pfx.SetCertificateEntry(bcCertificateAlias, bcCertificateEntry);
            pfx.SetKeyEntry(bcCertificateAlias, bcPrivateKeyEntry, new[] { bcCertificateEntry });

            var bcIssuer      = ParsePem <bc.X509.X509Certificate>(issuerPem);
            var bcIssuerEntry = new bc.Pkcs.X509CertificateEntry(bcIssuer);
            var bcIssuerAlias = bcIssuer.SubjectDN.ToString();

            pfx.SetCertificateEntry(bcIssuerAlias, bcIssuerEntry);

            var pfxStream = new MemoryStream();

            pfx.Save(pfxStream, null, new bc.Security.SecureRandom());
            pfxStream.Position = 0;
            using (var pfxStreamReader = new BinaryReader(pfxStream))
            {
                var tempPfx = new X509Certificate2(
                    pfxStreamReader.ReadBytes((int)pfxStream.Length),
                    (string)null,
                    X509KeyStorageFlags.MachineKeySet |
                    X509KeyStorageFlags.PersistKeySet |
                    X509KeyStorageFlags.Exportable);
                if (csrPlugin.CanConvert())
                {
                    try
                    {
                        var converted = csrPlugin.Convert(tempPfx.PrivateKey);
                        if (converted != null)
                        {
                            tempPfx.PrivateKey = converted;
                        }
                    }
                    catch
                    {
                        _log.Warning("Private key conversion error.");
                    }
                }

                tempPfx.FriendlyName = $"{friendlyName} {DateTime.Now.ToUserString()}";
                File.WriteAllBytes(pfxFileInfo.FullName, tempPfx.Export(X509ContentType.Pfx, renewal.PfxPassword));
                pfxFileInfo.Refresh();
            }

            // Update LastFriendlyName so that the user sees
            // the most recently issued friendlyName in
            // the WACS GUI
            renewal.LastFriendlyName = friendlyName;

            // Recreate X509Certificate2 with correct flags for Store/Install
            return(new CertificateInfo()
            {
                Certificate = ReadForUse(pfxFileInfo, renewal.PfxPassword),
                PfxFile = pfxFileInfo,
                PfxFilePassword = renewal.PfxPassword
            });
        }
Exemple #33
0
 public IISBindingHelper(ILogService log, IIISClient iisClient)
 {
     _log        = log;
     _iisClient  = iisClient;
     _idnMapping = new IdnMapping();
 }
Exemple #34
0
        public bool IsValidEmail(string strIn)
        {
            var invalid = false;

            if (String.IsNullOrEmpty(strIn))
            {
                return(false);
            }

            MatchEvaluator DomainMapper = match =>
            {
                // IdnMapping class with default property values.
                IdnMapping idn = new IdnMapping();

                string domainName = match.Groups[2].Value;
                try
                {
                    domainName = idn.GetAscii(domainName);
                }
                catch (ArgumentException)
                {
                    invalid = true;
                }
                return(match.Groups[1].Value + domainName);
            };

            // Use IdnMapping class to convert Unicode domain names.
            strIn = Regex.Replace(strIn, @"(@)(.+)$", DomainMapper);
            if (invalid)
            {
                return(false);
            }

            // Return true if strIn is in valid e-mail format.
            if (Regex.IsMatch(strIn,
                              @"^(?("")(""[^""]+?""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))" +
                              @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9]{2,17}))$",
                              RegexOptions.IgnoreCase))
            {
                string s         = strIn.Remove(0, strIn.IndexOf('@') + 1);
                string emailBody = s.Remove(s.IndexOf('.'));
                switch (emailBody)
                {
                case "live":
                case "mail":
                case "yandex":
                case "yahoo":
                case "aol":
                case "eclipso":
                case "maills":
                case "gmail":
                case "googlemail":
                case "firemail":
                case "maili":
                case "hotmail":
                case "emailn":
                case "outlook":
                case "rediffmail":
                case "oyoony":
                case "lycos":
                case "directbox":
                case "new-post":
                case "gmx":
                case "slucia":
                case "5x2":
                case "smart-mail":
                case "spl":
                case "t-online":
                case "compu-freemail":
                case "web":
                case "x-mail":
                case "k":
                case "mc-free":
                case "freenet":
                case "k-bg":
                case "overmail":
                case "anpa":
                case "freemailer":
                case "vcmail":
                case "mail4nature":
                case "uims":
                case "1vbb":
                case "uni":
                case "techmail":
                case "hushmail":
                case "freemail-24":
                case "guru":
                case "email":
                case "1email":
                case "canineworld":
                case "zelx":
                case "sify":
                case "softhome":
                case "kuekomail":
                case "mailde":
                case "mail-king":
                case "noxamail":
                case "h3c":
                case "arcor":
                case "logomail":
                case "ueberschuss":
                case "chattler":
                case "modellraketen":
                    return(true);
                }
            }
            return(false);
        }
        /// <summary>
        /// Request certificate from the ACME server
        /// </summary>
        /// <param name="binding"></param>
        /// <returns></returns>
        public async Task <CertificateInfo> RequestCertificate(ICsrPlugin csrPlugin, RunLevel runLevel, Renewal renewal, Target target, OrderDetails order)
        {
            // What are we going to get?
            var pfxFileInfo = new FileInfo(PfxFilePath(renewal));

            // Determine/check the common name
            var identifiers     = target.GetHosts(false);
            var commonNameUni   = target.CommonName;
            var commonNameAscii = string.Empty;

            if (!string.IsNullOrWhiteSpace(commonNameUni))
            {
                var idn = new IdnMapping();
                commonNameAscii = idn.GetAscii(commonNameUni);
                if (!identifiers.Contains(commonNameAscii, StringComparer.InvariantCultureIgnoreCase))
                {
                    _log.Warning($"Common name {commonNameUni} provided is invalid.");
                    commonNameAscii = identifiers.First();
                    commonNameUni   = idn.GetUnicode(commonNameAscii);
                }
            }

            // Determine the friendly name
            var friendlyName = renewal.FriendlyName;

            if (string.IsNullOrEmpty(friendlyName))
            {
                friendlyName = target.FriendlyName;
            }
            if (string.IsNullOrEmpty(friendlyName))
            {
                friendlyName = commonNameUni;
            }

            // Try using cached certificate first to avoid rate limiting during
            // (initial?) deployment troubleshooting. Real certificate requests
            // will only be done once per day maximum unless the --force parameter
            // is used.
            var cache = CachedInfo(renewal);

            if (cache != null &&
                cache.CacheFile.LastWriteTime > DateTime.Now.AddDays(_settings.Cache.ReuseDays * -1) &&
                cache.Match(target))
            {
                if (runLevel.HasFlag(RunLevel.IgnoreCache))
                {
                    _log.Warning("Cached certificate available but not used with --{switch}. Use 'Renew specific' or " +
                                 "'Renew all' in the main menu to run unscheduled renewals without hitting rate limits.",
                                 nameof(MainArguments.Force).ToLower());
                }
                else
                {
                    _log.Warning("Using cached certificate for {friendlyName}. To force issue of a new certificate within " +
                                 "24 hours, delete the .pfx file from the CertificatePath or run with the --{switch} switch. " +
                                 "Be ware that you might run into rate limits doing so.",
                                 friendlyName,
                                 nameof(MainArguments.Force).ToLower());
                    return(cache);
                }
            }

            if (target.CsrBytes == null)
            {
                var csr = await csrPlugin.GenerateCsr(GetPath(renewal, ".keys"), commonNameAscii, identifiers);

                target.CsrBytes   = csr.GetDerEncoded();
                target.PrivateKey = (await csrPlugin.GetKeys()).Private;
                File.WriteAllText(GetPath(renewal, "-csr.pem"), _pemService.GetPem("CERTIFICATE REQUEST", target.CsrBytes));
            }

            _log.Verbose("Submitting CSR");
            order = await _client.SubmitCsr(order, target.CsrBytes);

            if (order.Payload.Status != AcmeClient.OrderValid)
            {
                _log.Error("Unexpected order status {status}", order.Payload.Status);
                throw new Exception($"Unable to complete order");
            }

            _log.Information("Requesting certificate {friendlyName}", friendlyName);
            var rawCertificate = await _client.GetCertificate(order);

            if (rawCertificate == null)
            {
                throw new Exception($"Unable to get certificate");
            }

            byte[] certificateExport;
            using (var certificate = new X509Certificate2(rawCertificate))
            {
                certificateExport = certificate.Export(X509ContentType.Cert);
            }
            var crtPem = _pemService.GetPem("CERTIFICATE", certificateExport);

            // Get issuer certificate
            var issuerCertificate       = new X509Certificate2(rawCertificate.Skip(certificateExport.Length).ToArray());
            var issuerCertificateExport = issuerCertificate.Export(X509ContentType.Cert);
            var issuerPem = _pemService.GetPem("CERTIFICATE", issuerCertificateExport);

            issuerCertificate.Dispose();

            // Build pfx archive
            var pfx                = new bc.Pkcs.Pkcs12Store();
            var bcCertificate      = _pemService.ParsePem <bc.X509.X509Certificate>(crtPem);
            var bcCertificateEntry = new bc.Pkcs.X509CertificateEntry(bcCertificate);
            var bcCertificateAlias = bcCertificate.SubjectDN.ToString();

            pfx.SetCertificateEntry(bcCertificateAlias, bcCertificateEntry);
            if (target.PrivateKey != null)
            {
                var bcPrivateKeyEntry = new bc.Pkcs.AsymmetricKeyEntry(target.PrivateKey);
                pfx.SetKeyEntry(bcCertificateAlias, bcPrivateKeyEntry, new[] { bcCertificateEntry });
            }

            var bcIssuer      = _pemService.ParsePem <bc.X509.X509Certificate>(issuerPem);
            var bcIssuerEntry = new bc.Pkcs.X509CertificateEntry(bcIssuer);
            var bcIssuerAlias = bcIssuer.SubjectDN.ToString();

            pfx.SetCertificateEntry(bcIssuerAlias, bcIssuerEntry);

            var pfxStream = new MemoryStream();

            pfx.Save(pfxStream, null, new bc.Security.SecureRandom());
            pfxStream.Position        = 0;
            using var pfxStreamReader = new BinaryReader(pfxStream);

            var tempPfx = new X509Certificate2(
                pfxStreamReader.ReadBytes((int)pfxStream.Length),
                (string)null,
                X509KeyStorageFlags.MachineKeySet |
                X509KeyStorageFlags.PersistKeySet |
                X509KeyStorageFlags.Exportable);

            tempPfx.FriendlyName = $"{friendlyName} {_inputService.FormatDate(DateTime.Now)}";
            File.WriteAllBytes(pfxFileInfo.FullName, tempPfx.Export(X509ContentType.Pfx, renewal.PfxPassword?.Value));

            if (csrPlugin != null)
            {
                try
                {
                    var newVersion = await csrPlugin.PostProcess(tempPfx);

                    if (newVersion != tempPfx)
                    {
                        newVersion.FriendlyName = $"{friendlyName} {_inputService.FormatDate(DateTime.Now)}";
                        File.WriteAllBytes(pfxFileInfo.FullName, newVersion.Export(X509ContentType.Pfx, renewal.PfxPassword?.Value));
                        newVersion.Dispose();
                    }
                }
                catch (Exception)
                {
                    _log.Warning("Private key conversion error.");
                }
            }

            pfxFileInfo.Refresh();
            tempPfx.Dispose();

            // Update LastFriendlyName so that the user sees
            // the most recently issued friendlyName in
            // the WACS GUI
            renewal.LastFriendlyName = friendlyName;

            // Recreate X509Certificate2 with correct flags for Store/Install
            return(new CertificateInfo()
            {
                Certificate = ReadForUse(pfxFileInfo, renewal.PfxPassword?.Value),
                CacheFile = pfxFileInfo,
                CacheFilePassword = renewal.PfxPassword?.Value
            });
        }
Exemple #36
0
        private static string EncodeHostname(string hostname)
        {
            var idn = new IdnMapping();

            return(idn.GetAscii(hostname));
        }
 public void TestGetAsciiWithDot()
 {
     string result = "";
     Exception ex = Record.Exception(()=> result = new IdnMapping().GetAscii("."));
     if (ex == null)
     {
         // Windows and OSX always throw exception. some versions of Linux succeed and others throw exception
         Assert.False(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
         Assert.False(RuntimeInformation.IsOSPlatform(OSPlatform.OSX));
         Assert.Equal(result, ".");
     }
     else
     {
         Assert.IsType<ArgumentException>(ex);                
     }
 }
Exemple #38
0
        private static string ExtractSniHostname(IByteBuffer input, int offset, int endOffset)
        {
            // See https://tools.ietf.org/html/rfc5246#section-7.4.1.2
            //
            // Decode the ssl client hello packet.
            //
            // struct {
            //    ProtocolVersion client_version;
            //    Random random;
            //    SessionID session_id;
            //    CipherSuite cipher_suites<2..2^16-2>;
            //    CompressionMethod compression_methods<1..2^8-1>;
            //    select (extensions_present) {
            //        case false:
            //            struct {};
            //        case true:
            //            Extension extensions<0..2^16-1>;
            //    };
            // } ClientHello;
            //

            // We have to skip bytes until SessionID (which sum to 34 bytes in this case).
            offset += 34;

            if (endOffset - offset >= 6)
            {
                int sessionIdLength = input.GetByte(offset);
                offset += sessionIdLength + 1;

                int cipherSuitesLength = input.GetUnsignedShort(offset);
                offset += cipherSuitesLength + 2;

                int compressionMethodLength = input.GetByte(offset);
                offset += compressionMethodLength + 1;

                int extensionsLength = input.GetUnsignedShort(offset);
                offset += 2;
                int extensionsLimit = offset + extensionsLength;

                // Extensions should never exceed the record boundary.
                if (extensionsLimit <= endOffset)
                {
                    while (extensionsLimit - offset >= 4)
                    {
                        int extensionType = input.GetUnsignedShort(offset);
                        offset += 2;

                        int extensionLength = input.GetUnsignedShort(offset);
                        offset += 2;

                        if (extensionsLimit - offset < extensionLength)
                        {
                            break;
                        }

                        // SNI
                        // See https://tools.ietf.org/html/rfc6066#page-6
                        if (0u >= (uint)extensionType)
                        {
                            offset += 2;
                            if (extensionsLimit - offset < 3)
                            {
                                break;
                            }

                            int serverNameType = input.GetByte(offset);
                            offset++;

                            if (0u >= (uint)serverNameType)
                            {
                                int serverNameLength = input.GetUnsignedShort(offset);
                                offset += 2;

                                if ((uint)(serverNameLength - 1) > SharedConstants.TooBigOrNegative /*serverNameLength <= 0*/ ||
                                    extensionsLimit - offset < serverNameLength)
                                {
                                    break;
                                }

                                string hostname = input.ToString(offset, serverNameLength, Encoding.UTF8);
                                var    idn      = new IdnMapping()
                                {
                                    AllowUnassigned = true
                                };
                                return(idn.GetAscii(hostname).ToLower(UnitedStatesCultureInfo));
                            }
                            else
                            {
                                // invalid enum value
                                break;
                            }
                        }

                        offset += extensionLength;
                    }
                }
            }
            return(null);
        }
Exemple #39
0
        /// <summary>
        ///     Creates a MailMessage for the current MailAttribute instance.
        /// </summary>
        protected EmailMessage GenerateProspectiveMailMessage(MailAttributes mail)
        {
            var idnmapping = new IdnMapping();

            var emailAddresses = mail.To
                                 .Select(
                t =>
            {
                var domainSplit = t.Address.Split('@');
                return(new EmailAddress(domainSplit[0] + "@" + idnmapping.GetAscii(domainSplit[1]))
                {
                    Type = "to"
                });
            })
                                 .Union(
                mail.Cc.Select(
                    t =>
            {
                var domainSplit = t.Address.Split('@');
                return(new EmailAddress(domainSplit[0] + "@" + idnmapping.GetAscii(domainSplit[1]))
                {
                    Type = "cc"
                });
            }))
                                 .Union(
                mail.Bcc.Select(
                    t =>
            {
                var domainSplit = t.Address.Split('@');
                return(new EmailAddress(domainSplit[0] + "@" + idnmapping.GetAscii(domainSplit[1]))
                {
                    Type = "bcc"
                });
            }));

            //create base message
            var message = new EmailMessage
            {
                FromName           = mail.From.DisplayName,
                FromEmail          = mail.From.Address,
                To                 = emailAddresses,
                Subject            = mail.Subject,
                Important          = mail.Priority == MailPriority.High,
                PreserveRecipients = true
            };

            // We need to set Reply-To as a custom header
            if (mail.ReplyTo.Any())
            {
                message.AddHeader("Reply-To", string.Join(" , ", mail.ReplyTo));
            }

            // Adding content to the message
            foreach (var view in mail.AlternateViews)
            {
                var reader = new StreamReader(view.ContentStream, Encoding.UTF8, true, 1024, true);

                var body = reader.ReadToEnd();

                if (view.ContentType.MediaType == MediaTypeNames.Text.Plain)
                {
                    message.Text = body;
                }
                if (view.ContentType.MediaType == MediaTypeNames.Text.Html)
                {
                    message.Html = body;
                }
            }

            // Going through headers and adding them to the message
            mail.Headers.ToList().ForEach(h => message.AddHeader(h.Key, h.Value));

            // Adding the attachments
            var attachments = new List <EmailAttachment>();

            foreach (var mailAttachment in mail.Attachments.Select(attachment => Utils.AttachmentCollection.ModifyAttachmentProperties(attachment.Key, attachment.Value, false)))
            {
                using (var stream = new MemoryStream())
                {
                    mailAttachment.ContentStream.CopyTo(stream);
                    var base64Data = Convert.ToBase64String(stream.ToArray());
                    attachments.Add(new EmailAttachment
                    {
                        Content = base64Data,
                        Name    = ReplaceGermanCharacters(mailAttachment.Name),
                        Type    = mailAttachment.ContentType.MediaType,
                    });
                }
            }

            message.Attachments = attachments;

            return(message);
        }
Exemple #40
0
        private void Initialize()
        {
            _transport = new SmtpTransport(this);
            if (NetEventSource.Log.IsEnabled())
            {
                NetEventSource.Associate(this, _transport);
            }
            _onSendCompletedDelegate = new SendOrPostCallback(SendCompletedWaitCallback);

            if (_host != null && _host.Length != 0)
            {
                _host = _host.Trim();
            }

            if (_port == 0)
            {
                _port = DefaultPort;
            }

            if (_targetName == null)
            {
                _targetName = "SMTPSVC/" + _host;
            }

            if (_clientDomain == null)
            {
                // We use the local host name as the default client domain
                // for the client's EHLO or HELO message. This limits the
                // information about the host that we share. Additionally, the
                // FQDN is not available to us or useful to the server (internal
                // machine connecting to public server).

                // SMTP RFC's require ASCII only host names in the HELO/EHLO message.
                string clientDomainRaw = IPGlobalProperties.GetIPGlobalProperties().HostName;

                IdnMapping mapping = new IdnMapping();
                try
                {
                    clientDomainRaw = mapping.GetAscii(clientDomainRaw);
                }
                catch (ArgumentException) { }

                // For some inputs GetAscii may fail (bad Unicode, etc).  If that happens
                // we must strip out any non-ASCII characters.
                // If we end up with no characters left, we use the string "LocalHost".  This
                // matches Outlook behavior.
                StringBuilder sb = new StringBuilder();
                char          ch;
                for (int i = 0; i < clientDomainRaw.Length; i++)
                {
                    ch = clientDomainRaw[i];
                    if ((ushort)ch <= 0x7F)
                    {
                        sb.Append(ch);
                    }
                }
                if (sb.Length > 0)
                {
                    _clientDomain = sb.ToString();
                }
                else
                {
                    _clientDomain = "LocalHost";
                }
            }
        }
        public static void TestEquals(bool allowUnassigned, bool useStd3AsciiRules)
        {
            // first check for equals
            IdnMapping original = new IdnMapping() { AllowUnassigned = allowUnassigned, UseStd3AsciiRules = useStd3AsciiRules };
            IdnMapping identical = new IdnMapping() { AllowUnassigned = allowUnassigned, UseStd3AsciiRules = useStd3AsciiRules };
            Assert.True(original.Equals(identical));
            Assert.Equal(original.GetHashCode(), identical.GetHashCode());

            //  now three sets of unequals
            IdnMapping unequal1 = new IdnMapping() { AllowUnassigned = allowUnassigned, UseStd3AsciiRules = !useStd3AsciiRules };
            Assert.False(original.Equals(unequal1));
            Assert.NotEqual(original.GetHashCode(), unequal1.GetHashCode());

            IdnMapping unequal2 = new IdnMapping() { AllowUnassigned = !allowUnassigned, UseStd3AsciiRules = useStd3AsciiRules };
            Assert.False(original.Equals(unequal2));
            Assert.NotEqual(original.GetHashCode(), unequal2.GetHashCode());

            IdnMapping unequal3 = new IdnMapping() { AllowUnassigned = !allowUnassigned, UseStd3AsciiRules = useStd3AsciiRules };
            Assert.False(original.Equals(unequal3));
            Assert.NotEqual(original.GetHashCode(), unequal3.GetHashCode());
        }
Exemple #42
0
 void GetUnicode(IdnMapping m, string source, string expected, object label)
 {
     Assert.AreEqual(expected, m.GetUnicode(source), label != null ? label.ToString() : expected);
 }
Exemple #43
0
        private string FromPunyCode(string hostName)
        {
            var idn = new IdnMapping();

            return(idn.GetUnicode(hostName));
        }
Exemple #44
0
        //
        // Will convert a host name into its idn equivalent + tell you if it had a valid idn label
        //
        internal static unsafe string IdnEquivalent(char *hostname, int start, int end, ref bool allAscii, ref bool atLeastOneValidIdn)
        {
            string bidiStrippedHost = null;
            string idnEquivalent    = IdnEquivalent(hostname, start, end, ref allAscii, ref bidiStrippedHost);

            if (idnEquivalent != null)
            {
                string strippedHost = (allAscii ? idnEquivalent : bidiStrippedHost);

                fixed(char *strippedHostPtr = strippedHost)
                {
                    int  length     = strippedHost.Length;
                    int  newPos     = 0;
                    int  curPos     = 0;
                    bool foundAce   = false;
                    bool checkedAce = false;
                    bool foundDot   = false;

                    do
                    {
                        foundAce   = false;
                        checkedAce = false;
                        foundDot   = false;

                        //find the dot or hit the end
                        newPos = curPos;
                        while (newPos < length)
                        {
                            char c = strippedHostPtr[newPos];
                            if (!checkedAce)
                            {
                                checkedAce = true;
                                if ((newPos + 3 < length) && IsIdnAce(strippedHostPtr, newPos))
                                {
                                    newPos  += 4;
                                    foundAce = true;
                                    continue;
                                }
                            }

                            if ((c == '.') || (c == '\u3002') ||    //IDEOGRAPHIC FULL STOP
                                (c == '\uFF0E') ||                  //FULLWIDTH FULL STOP
                                (c == '\uFF61'))                    //HALFWIDTH IDEOGRAPHIC FULL STOP
                            {
                                foundDot = true;
                                break;
                            }
                            ++newPos;
                        }

                        if (foundAce)
                        {
                            // check ace validity
                            try
                            {
                                IdnMapping map = new IdnMapping();
                                map.GetUnicode(new string(strippedHostPtr, curPos, newPos - curPos));
                                atLeastOneValidIdn = true;
                                break;
                            }
                            catch (ArgumentException)
                            {
                                // not valid ace so treat it as a normal ascii label
                            }
                        }

                        curPos = newPos + (foundDot ? 1 : 0);
                    } while (curPos < length);
                }
            }
            else
            {
                atLeastOneValidIdn = false;
            }
            return(idnEquivalent);
        }
Exemple #45
0
        public void SurrogatePairsConsecutive()
        {
            var idn = new IdnMapping();

            Assert.Equal("xn--097ccd", idn.GetAscii("\uD800\uDF00\uD800\uDF01\uD800\uDF02"));
        }
Exemple #46
0
        internal static unsafe string UnicodeEquivalent(char *hostname, int start, int end, ref bool allAscii, ref bool atLeastOneValidIdn)
        {
            IdnMapping map = new IdnMapping();

            // hostname already validated
            allAscii           = true;
            atLeastOneValidIdn = false;
            string idn = null;

            if (end <= start)
            {
                return(idn);
            }

            string unescapedHostname = UriHelper.StripBidiControlCharacter(hostname, start, (end - start));

            string unicodeEqvlHost = null;
            int    curPos          = 0;
            int    newPos          = 0;
            int    length          = unescapedHostname.Length;
            bool   asciiLabel      = true;
            bool   foundAce        = false;
            bool   checkedAce      = false;
            bool   foundDot        = false;


            // We run a loop where for every label
            // a) if label is ascii and no ace then we lowercase it
            // b) if label is ascii and ace and not valid idn then just lowercase it
            // c) if label is ascii and ace and is valid idn then get its unicode eqvl
            // d) if label is unicode then clean it by running it through idnmapping
            do
            {
                asciiLabel = true;
                foundAce   = false;
                checkedAce = false;
                foundDot   = false;

                //find the dot or hit the end
                newPos = curPos;
                while (newPos < length)
                {
                    char c = unescapedHostname[newPos];
                    if (!checkedAce)
                    {
                        checkedAce = true;
                        if ((newPos + 3 < length) && (c == 'x') && IsIdnAce(unescapedHostname, newPos))
                        {
                            foundAce = true;
                        }
                    }
                    if (asciiLabel && (c > '\x7F'))
                    {
                        asciiLabel = false;
                        allAscii   = false;
                    }
                    if ((c == '.') || (c == '\u3002') ||    //IDEOGRAPHIC FULL STOP
                        (c == '\uFF0E') ||                  //FULLWIDTH FULL STOP
                        (c == '\uFF61'))                    //HALFWIDTH IDEOGRAPHIC FULL STOP
                    {
                        foundDot = true;
                        break;
                    }
                    ++newPos;
                }

                if (!asciiLabel)
                {
                    string asciiForm = unescapedHostname.Substring(curPos, newPos - curPos);
                    try
                    {
                        asciiForm = map.GetAscii(asciiForm);
                    }
                    catch (ArgumentException)
                    {
                        throw new UriFormatException(SR.net_uri_BadUnicodeHostForIdn);
                    }

                    unicodeEqvlHost += map.GetUnicode(asciiForm);
                    if (foundDot)
                    {
                        unicodeEqvlHost += ".";
                    }
                }
                else
                {
                    bool aceValid = false;
                    if (foundAce)
                    {
                        // check ace validity
                        try
                        {
                            unicodeEqvlHost += map.GetUnicode(unescapedHostname.Substring(curPos, newPos - curPos));
                            if (foundDot)
                            {
                                unicodeEqvlHost += ".";
                            }
                            aceValid           = true;
                            atLeastOneValidIdn = true;
                        }
                        catch (ArgumentException)
                        {
                            // not valid ace so treat it as a normal ascii label
                        }
                    }

                    if (!aceValid)
                    {
                        // for invalid aces we just lowercase the label
                        unicodeEqvlHost += unescapedHostname.Substring(curPos, newPos - curPos).ToLowerInvariant();
                        if (foundDot)
                        {
                            unicodeEqvlHost += ".";
                        }
                    }
                }

                curPos = newPos + (foundDot ? 1 : 0);
            } while (curPos < length);

            return(unicodeEqvlHost);
        }
Exemple #47
0
        public void SurrogatePairsSeparatedByNonAscii()
        {
            var idn = new IdnMapping();

            Assert.Equal("xn--yda263v6b6kfag", idn.GetAscii("\uD800\uDF00\u0101\uD800\uDF01\u305D\uD800\uDF02"));
        }
Exemple #48
0
        /// <summary>
        /// Request a certificate from lets encrypt using the DNS challenge, placing the challenge record in Azure DNS.
        /// The certifiacte is not assigned, but just returned.
        /// </summary>
        /// <param name="azureDnsEnvironment"></param>
        /// <param name="acmeConfig"></param>
        /// <returns></returns>
        public async Task <CertificateInstallModel> RequestDnsChallengeCertificate(IAcmeDnsRequest acmeConfig)
        {
            logger.LogInformation("Starting request DNS Challenge certificate for {AcmeEnvironment} and {Email}", acmeConfig.AcmeEnvironment.BaseUri, acmeConfig.RegistrationEmail);
            var acmeContext = await GetOrCreateAcmeContext(acmeConfig.AcmeEnvironment.BaseUri, acmeConfig.RegistrationEmail);

            var idn = new IdnMapping();

            var order = await acmeContext.NewOrder(new[] { "*." + idn.GetAscii(acmeConfig.Host.Substring(2)) });

            var a = await order.Authorizations();

            var authz     = a.First();
            var challenge = await authz.Dns();

            var dnsTxt = acmeContext.AccountKey.DnsTxt(challenge.Token);

            logger.LogInformation("Got DNS challenge token {Token}", dnsTxt);

            ///add dns entry
            await this.dnsProvider.PersistChallenge("_acme-challenge", dnsTxt);

            if (!(await this.dnsLookupService.Exists(acmeConfig.Host, dnsTxt, this.dnsProvider.MinimumTtl)))
            {
                throw new TimeoutException($"Unable to validate that _acme-challenge was stored in txt _acme-challenge record after {this.dnsProvider.MinimumTtl} seconds");
            }


            Challenge chalResp = await challenge.Validate();

            while (chalResp.Status == ChallengeStatus.Pending || chalResp.Status == ChallengeStatus.Processing)
            {
                logger.LogInformation("Dns challenge response status {ChallengeStatus} more info at {ChallengeStatusUrl} retrying in 5 sec", chalResp.Status, chalResp.Url.ToString());
                await Task.Delay(5000);

                chalResp = await challenge.Resource();
            }

            logger.LogInformation("Finished validating dns challenge token, response was {ChallengeStatus} more info at {ChallengeStatusUrl}", chalResp.Status, chalResp.Url);

            var privateKey = await GetOrCreateKey(acmeConfig.AcmeEnvironment.BaseUri, acmeConfig.Host);

            var cert = await order.Generate(new Certes.CsrInfo
            {
                CountryName      = acmeConfig.CsrInfo?.CountryName,
                State            = acmeConfig.CsrInfo?.State,
                Locality         = acmeConfig.CsrInfo?.Locality,
                Organization     = acmeConfig.CsrInfo?.Organization,
                OrganizationUnit = acmeConfig.CsrInfo?.OrganizationUnit
            }, privateKey);

            var certPem = cert.ToPem();

            var pfxBuilder = cert.ToPfx(privateKey);
            var pfx        = pfxBuilder.Build(acmeConfig.Host, acmeConfig.PFXPassword);

            await this.dnsProvider.Cleanup(dnsTxt);

            return(new CertificateInstallModel()
            {
                CertificateInfo = new CertificateInfo()
                {
                    Certificate = new X509Certificate2(pfx, acmeConfig.PFXPassword, X509KeyStorageFlags.DefaultKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable),
                    Name = $"{acmeConfig.Host} {DateTime.Now}",
                    Password = acmeConfig.PFXPassword,
                    PfxCertificate = pfx
                },
                Host = acmeConfig.Host
            });
        }
        internal static SslPolicyErrors VerifyCertificateProperties(
            X509Chain chain,
            X509Certificate2 remoteCertificate,
            bool checkCertName,
            bool isServer,
            string hostName)
        {
            SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None;

            if (!chain.Build(remoteCertificate))
            {
                sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors;
            }

            if (checkCertName)
            {
                if (string.IsNullOrEmpty(hostName))
                {
                    sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch;
                }
                else
                {
                    int hostnameMatch;

                    using (SafeX509Handle certHandle = Interop.Crypto.X509Duplicate(remoteCertificate.Handle))
                    {
                        IPAddress hostnameAsIp;

                        if (IPAddress.TryParse(hostName, out hostnameAsIp))
                        {
                            byte[] addressBytes = hostnameAsIp.GetAddressBytes();

                            hostnameMatch = Interop.Crypto.CheckX509IpAddress(
                                certHandle,
                                addressBytes,
                                addressBytes.Length,
                                hostName,
                                hostName.Length);
                        }
                        else
                        {
                            // The IdnMapping converts Unicode input into the IDNA punycode sequence.
                            // It also does host case normalization.  The bypass logic would be something
                            // like "all characters being within [a-z0-9.-]+"
                            //
                            // Since it's not documented as being thread safe, create a new one each time.
                            IdnMapping mapping   = new IdnMapping();
                            string     matchName = mapping.GetAscii(hostName);

                            hostnameMatch = Interop.Crypto.CheckX509Hostname(certHandle, matchName, matchName.Length);
                        }
                    }

                    if (hostnameMatch != 1)
                    {
                        Debug.Assert(hostnameMatch == 0, "hostnameMatch should be (0,1) was " + hostnameMatch);
                        sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch;
                    }
                }
            }
            return(sslPolicyErrors);
        }
Exemple #50
0
        public static bool IsValidEmail(TextBox textBox, bool changeColor = true)
        {
            string email = textBox.Text;

            if (string.IsNullOrWhiteSpace(email))
            {
                return(false);
            }

            try
            {
                // Normalize the domain
                email = Regex.Replace(email, @"(@)(.+)$", DomainMapper,
                                      RegexOptions.None, TimeSpan.FromMilliseconds(200));

                // Examines the domain part of the email and normalizes it.
                string DomainMapper(Match match)
                {
                    // Use IdnMapping class to convert Unicode domain names.
                    var idn = new IdnMapping();

                    // Pull out and process domain name (throws ArgumentException on invalid)
                    var domainName = idn.GetAscii(match.Groups[2].Value);

                    return(match.Groups[1].Value + domainName);
                }
            }
            catch (RegexMatchTimeoutException e)
            {
                if (changeColor)
                {
                    ChangeColor(textBox);
                }
                return(false);
            }
            catch (ArgumentException e)
            {
                if (changeColor)
                {
                    ChangeColor(textBox);
                }
                return(false);
            }

            try
            {
                bool result = Regex.IsMatch(email,
                                            @"^(?("")("".+?(?<!\\)""@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])@))" +
                                            @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-0-9a-z]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$",
                                            RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250));

                if (!result)
                {
                    if (changeColor)
                    {
                        ChangeColor(textBox);
                    }
                }

                return(result);
            }
            catch (RegexMatchTimeoutException)
            {
                if (changeColor)
                {
                    ChangeColor(textBox);
                }
                return(false);
            }
        }
        /// <summary>
        /// Request certificate from the ACME server
        /// </summary>
        /// <param name="binding"></param>
        /// <returns></returns>
        public CertificateInfo RequestCertificate(Target binding)
        {
            // What are we going to get?
            var identifiers = binding.GetHosts(false);
            var friendlyName = FriendlyName(binding);
            var pfxPassword = Properties.Settings.Default.PFXPassword;
            var pfxFileInfo = new FileInfo(PfxFilePath(binding));

            // Try using cached certificate first to avoid rate limiting during
            // (initial?) deployment troubleshooting. Real certificate requests
            // will only be done once per day maximum.
            if (pfxFileInfo.Exists && pfxFileInfo.LastWriteTime > DateTime.Now.AddDays(-1))
            {
                try
                {
                    var cached = new CertificateInfo()
                    {
                        Certificate = ReadForUse(pfxFileInfo, pfxPassword),
                        PfxFile = pfxFileInfo
                    };
                    var idn = new IdnMapping();
                    if (cached.SubjectName == identifiers.First() &&
                        cached.HostNames.Count == identifiers.Count &&
                        cached.HostNames.All(h => identifiers.Contains(idn.GetAscii(h))))
                    {
                        if (_options.ForceRenewal)
                        {
                            _log.Warning("Cached certificate available but not used with --forcerenewal. Use 'Renew specific' or 'Renew all' in the main menu to run unscheduled renewals without hitting rate limits.");
                        }
                        else
                        {
                            _log.Warning("Using cached certificate for {friendlyName}. To force issue of a new certificate within 24 hours, delete the .pfx file from the CertificatePath or run with the --forcerenewal switch. Be ware that you might run into rate limits doing so.", friendlyName);
                            return cached;
                        }

                    }
                }
                catch
                {
                    // File corrupt or invalid password?
                    _log.Warning("Unable to read from certificate cache");
                }
            }

            using (var cp = CertificateProvider.GetProvider("BouncyCastle"))
            {
                // Generate the private key and CSR
                var rsaPkp = GetRsaKeyParameters();
                var rsaKeys = cp.GeneratePrivateKey(rsaPkp);
                var csr = GetCsr(cp, identifiers, rsaKeys, binding.CommonName);
                byte[] derRaw;
                using (var bs = new MemoryStream())
                {
                    cp.ExportCsr(csr, EncodingFormat.DER, bs);
                    derRaw = bs.ToArray();
                }
                var derB64U = JwsHelper.Base64UrlEncode(derRaw);

                // Save request parameters to disk
                using (var fs = new FileStream(GetPath(binding, "-gen-key.json"), FileMode.Create))
                    cp.SavePrivateKey(rsaKeys, fs);

                using (var fs = new FileStream(GetPath(binding, "-key.pem"), FileMode.Create))
                    cp.ExportPrivateKey(rsaKeys, EncodingFormat.PEM, fs);

                using (var fs = new FileStream(GetPath(binding, "-gen-csr.json"), FileMode.Create))
                    cp.SaveCsr(csr, fs);

                using (var fs = new FileStream(GetPath(binding, "-csr.pem"), FileMode.Create))
                    cp.ExportCsr(csr, EncodingFormat.PEM, fs);

                // Request the certificate from the ACME server
                _log.Information("Requesting certificate {friendlyName}", friendlyName);
                var certificateRequest = _client.Acme.RequestCertificate(derB64U);
                if (certificateRequest.StatusCode != HttpStatusCode.Created)
                {
                    throw new Exception($"Request status {certificateRequest.StatusCode}");
                }

                // Main certicate and issuer certificate
                Crt certificate;
                Crt issuerCertificate;

                // Certificate request was successful, save the certificate itself
                var crtDerFile = GetPath(binding, $"-crt.der");
                _log.Information("Saving certificate to {crtDerFile}", _certificatePath);
                using (var file = File.Create(crtDerFile))
                    certificateRequest.SaveCertificate(file);

                // Save certificate in PEM format too
                var crtPemFile = GetPath(binding, $"-crt.pem");
                using (FileStream source = new FileStream(crtDerFile, FileMode.Open),
                    target = new FileStream(crtPemFile, FileMode.Create))
                {
                    certificate = cp.ImportCertificate(EncodingFormat.DER, source);
                    cp.ExportCertificate(certificate, EncodingFormat.PEM, target);
                }

                // Get issuer certificate and save in DER and PEM formats
                issuerCertificate = GetIssuerCertificate(certificateRequest, cp);
                using (var target = new FileStream(GetPath(binding, "-crt.der", "ca-"), FileMode.Create))
                    cp.ExportCertificate(issuerCertificate, EncodingFormat.DER, target);

                var issuerPemFile = GetPath(binding, "-crt.pem", "ca-");
                using (var target = new FileStream(issuerPemFile, FileMode.Create))
                    cp.ExportCertificate(issuerCertificate, EncodingFormat.PEM, target);

                // Save chain in PEM format
                using (FileStream intermediate = new FileStream(issuerPemFile, FileMode.Open),
                    certificateStrean = new FileStream(crtPemFile, FileMode.Open),
                    chain = new FileStream(GetPath(binding, "-chain.pem"), FileMode.Create))
                {
                    certificateStrean.CopyTo(chain);
                    intermediate.CopyTo(chain);
                }

                // All raw data has been saved, now generate the PFX file
                using (var target = new FileStream(pfxFileInfo.FullName, FileMode.Create))
                {
                    try
                    {
                        cp.ExportArchive(rsaKeys,
                            new[] { certificate, issuerCertificate },
                            ArchiveFormat.PKCS12,
                            target,
                            pfxPassword);
                    }
                    catch (Exception ex)
                    {
                        _log.Error("Error exporting archive {@ex}", ex);
                    }
                }

                // Flags used for the internally cached certificate
                var internalFlags =
                    X509KeyStorageFlags.MachineKeySet |
                    X509KeyStorageFlags.PersistKeySet |
                    X509KeyStorageFlags.Exportable;

                // See http://paulstovell.com/blog/x509certificate2
                try
                {
                    // Convert Private Key to different CryptoProvider
                    _log.Verbose("Converting private key...");
                    var res = new X509Certificate2(pfxFileInfo.FullName, pfxPassword, internalFlags);
                    var privateKey = (RSACryptoServiceProvider)res.PrivateKey;
                    res.PrivateKey = Convert(privateKey);
                    res.FriendlyName = friendlyName;
                    File.WriteAllBytes(pfxFileInfo.FullName, res.Export(X509ContentType.Pfx, pfxPassword));
                    pfxFileInfo.Refresh();
                }
                catch (Exception ex)
                {
                    // If we couldn't convert the private key that
                    // means we're left with a pfx generated with the
                    // 'wrong' Crypto provider therefor delete it to
                    // make sure it's retried on the next run.
                    _log.Warning("Error converting private key to Microsoft RSA SChannel Cryptographic Provider, which means it might not be usable for Exchange.");
                    _log.Verbose("{ex}", ex);
                }

                // Recreate X509Certificate2 with correct flags for Store/Install
                return new CertificateInfo() {
                    Certificate = ReadForUse(pfxFileInfo, pfxPassword),
                    PfxFile = pfxFileInfo
                };
            }
        }
Exemple #52
0
        public void SurrogatePairsConsecutive()
        {
            var idn = new IdnMapping();

            Assert.Equal("xn--097ccd", idn.GetAscii("\uD800\uDF00\uD800\uDF01\uD800\uDF02"));
        }