public void ConfigureRules()
        {
            WriteOnce.SafeLog("TagTestCommand::ConfigRules", LogLevel.Trace);

            if (string.IsNullOrEmpty(_options.CustomRulesPath))
            {
                throw new OpException(MsgHelp.GetString(MsgHelp.ID.CMD_NORULES_SPECIFIED));
            }

            RulesVerifier verifier = new RulesVerifier(_options.CustomRulesPath, _options.Log);

            verifier.Verify();
            if (!verifier.IsVerified)
            {
                throw new OpException(MsgHelp.GetString(MsgHelp.ID.VERIFY_RULES_RESULTS_FAIL));
            }

            _rulesSet = verifier.CompiledRuleset ?? new RuleSet(null);

            //error check based on ruleset not path enumeration
            if (!_rulesSet.Any())
            {
                throw new OpException(MsgHelp.GetString(MsgHelp.ID.CMD_NORULES_SPECIFIED));
            }
        }
Example #2
0
        private void ConfigRules()
        {
            _logger.LogTrace("ExportTagsCommand::ConfigRules");
            _rules = new RuleSet(_loggerFactory);
            if (!_options.IgnoreDefaultRules)
            {
                _rules = RuleSetUtils.GetDefaultRuleSet(_loggerFactory);
            }

            if (!string.IsNullOrEmpty(_options?.CustomRulesPath))
            {
                if (Directory.Exists(_options.CustomRulesPath))
                {
                    _rules.AddDirectory(_options.CustomRulesPath);
                }
                else if (File.Exists(_options.CustomRulesPath))
                {
                    _rules.AddFile(_options.CustomRulesPath);
                }
                else
                {
                    throw new OpException(MsgHelp.FormatString(MsgHelp.ID.CMD_INVALID_RULE_PATH, _options.CustomRulesPath));
                }
            }

            //error check based on ruleset not path enumeration
            if (_rules == null || !_rules.Any())
            {
                throw new OpException(MsgHelp.GetString(MsgHelp.ID.CMD_NORULES_SPECIFIED));
            }
        }
Example #3
0
        /// <summary>
        ///     Analyzes a directory of files.
        /// </summary>
        /// <param name="directory"> directory to analyze. </param>
        /// <returns> List of tags identified </returns>
        public async Task <List <IssueRecord> > AnalyzeDirectory(string directory)
        {
            Logger.Trace("AnalyzeDirectory({0})", directory);

            var analysisResults = new List <IssueRecord>();

            RuleSet rules = new RuleSet();

            if (Options["disable-default-rules"] is bool disableDefaultRules && !disableDefaultRules)
            {
                var assembly = Assembly.GetExecutingAssembly();
                foreach (var resourceName in assembly.GetManifestResourceNames())
                {
                    if (resourceName.EndsWith(".json"))
                    {
                        try
                        {
                            var stream = assembly.GetManifestResourceStream(resourceName);
                            using var resourceStream = new StreamReader(stream ?? new MemoryStream());
                            rules.AddString(resourceStream.ReadToEnd(), resourceName);
                        }
                        catch (Exception ex)
                        {
                            Logger.Warn(ex, "Error loading {0}: {1}", resourceName, ex.Message);
                        }
                    }
                }
            }

            if (Options["custom-rule-directory"] is string customDirectory)
            {
                rules.AddDirectory(customDirectory);
            }

            if (!rules.Any())
            {
                Logger.Error("No rules were specified, unable to continue.");
                return(analysisResults); // empty
            }

            var processor = new RuleProcessor(rules)
            {
                EnableSuppressions = false,
                SeverityLevel      = (Severity)31
            };

            string[] fileList;

            if (Directory.Exists(directory))
            {
                fileList = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
            }
            else if (File.Exists(directory))
            {
                fileList = new string[] { directory };
            }
            else
            {
                Logger.Warn("{0} is neither a directory nor a file.", directory);
                return(analysisResults); // empty
            }

            foreach (var filename in fileList)
            {
                Logger.Trace($"Processing {filename}");

                // TODO: Make this more resilient
                if (IGNORE_FILES.Contains(Path.GetFileName(filename)))
                {
                    Logger.Trace($"Ignoring {filename}");
                    continue;
                }

                byte[] fileContents;
                try
                {
                    fileContents = File.ReadAllBytes(filename);
                }
                catch (Exception ex)
                {
                    Logger.Trace(ex, "File {0} cannot be read, ignoring.", filename);
                    continue;
                }

                var buffer = NormalizeFileContent(filename, fileContents);
                Logger.Debug("Normalization complete.");

                double MIN_CRYPTO_OP_DENSITY = 0.10;
                try
                {
                    // TODO don't do this if we disassembled native code
                    var cryptoOperationLikelihood = CalculateCryptoOpDensity(buffer);
                    Logger.Debug("Cryptographic operation density for {0} was {1}", filename, cryptoOperationLikelihood);

                    if (cryptoOperationLikelihood >= MIN_CRYPTO_OP_DENSITY)
                    {
                        analysisResults.Add(new IssueRecord(
                                                Filename: filename,
                                                Filesize: buffer.Length,
                                                TextSample: "n/a",
                                                Issue: new Issue(
                                                    Boundary: new Boundary(),
                                                    StartLocation: new Location(),
                                                    EndLocation: new Location(),
                                                    Rule: new Rule("Crypto Symbols")
                        {
                            Id          = "_CRYPTO_DENSITY",
                            Name        = "Cryptographic symbols",
                            Description = cryptoOperationLikelihood.ToString(),
                            Tags        = new string[]
                            {
                                "Cryptography.GenericImplementation.HighDensityOperators"
                            }
                        }
                                                    )
                                                ));
                    }
                    Logger.Debug($"Analyzing {filename}, length={buffer.Length}");

                    Issue[]? fileResults = null;
                    var task = Task.Run(() => processor.Analyze(buffer, Language.FromFileName(filename)));
                    if (task.Wait(TimeSpan.FromSeconds(2)))
                    {
                        fileResults = task.Result;
                    }
                    else
                    {
                        Logger.Debug("DevSkim operation timed out.");
                        return(analysisResults);
                    }

                    Logger.Debug("Operation Complete: {0}", fileResults?.Length);
                    foreach (var issue in fileResults ?? Array.Empty <Issue>())
                    {
                        var fileContentArray = buffer.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
                        var excerpt          = new List <string>();
                        var startLoc         = Math.Max(issue.StartLocation.Line - 1, 0);
                        var endLoc           = Math.Min(issue.EndLocation.Line + 1, fileContentArray.Length - 1);
                        for (int i = startLoc; i <= endLoc; i++)
                        {
                            excerpt.Add(fileContentArray[i].Trim());
                        }

                        analysisResults.Add(new IssueRecord(
                                                Filename: filename,
                                                Filesize: buffer.Length,
                                                TextSample: issue.StartLocation.Line + " => " + string.Join(Environment.NewLine, excerpt),
                                                Issue: issue)
                                            );
                    }
                }
                catch (Exception ex)
                {
                    Logger.Warn(ex, "Error analyzing {0}: {1}", filename, ex.Message);
                    Logger.Warn(ex.StackTrace);
                }
            }

            return(analysisResults);
        }