File: Microsoft.NetCore.Analyzers\Security\DoNotUseInsecureCryptographicAlgorithms.cs
Web Access
Project: src\sdk\src\Microsoft.CodeAnalysis.NetAnalyzers\src\Microsoft.CodeAnalysis.NetAnalyzers\Microsoft.CodeAnalysis.NetAnalyzers.csproj (Microsoft.CodeAnalysis.NetAnalyzers)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Immutable;
using Microsoft.NetCore.Analyzers.Security.Helpers;
using Analyzer.Utilities;
using Analyzer.Utilities.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using System.Diagnostics;

namespace Microsoft.NetCore.Analyzers.Security
{
    using static MicrosoftNetCoreAnalyzersResources;

    /// <summary>
    /// CA5350: <inheritdoc cref="DoNotUseBrokenCryptographicAlgorithms"/>
    /// CA5351: <inheritdoc cref="DoNotUseWeakCryptographicAlgorithms"/>
    /// </summary>
    [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
    public sealed class DoNotUseInsecureCryptographicAlgorithmsAnalyzer : DiagnosticAnalyzer
    {
        internal const string DoNotUseWeakCryptographyRuleId = "CA5350";
        internal const string DoNotUseBrokenCryptographyRuleId = "CA5351";

        internal static readonly DiagnosticDescriptor DoNotUseBrokenCryptographyRule =
            DiagnosticDescriptorHelper.Create(
                DoNotUseBrokenCryptographyRuleId,
                CreateLocalizableResourceString(nameof(DoNotUseBrokenCryptographicAlgorithms)),
                CreateLocalizableResourceString(nameof(DoNotUseBrokenCryptographicAlgorithmsMessage)),
                DiagnosticCategory.Security,
                RuleLevel.IdeHidden_BulkConfigurable,
                description: CreateLocalizableResourceString(nameof(DoNotUseBrokenCryptographicAlgorithmsDescription)),
                isPortedFxCopRule: false,
                isDataflowRule: false);

        internal static readonly DiagnosticDescriptor DoNotUseWeakCryptographyRule =
            DiagnosticDescriptorHelper.Create(
                DoNotUseWeakCryptographyRuleId,
                CreateLocalizableResourceString(nameof(DoNotUseWeakCryptographicAlgorithms)),
                CreateLocalizableResourceString(nameof(DoNotUseWeakCryptographicAlgorithmsMessage)),
                DiagnosticCategory.Security,
                RuleLevel.IdeHidden_BulkConfigurable,
                description: CreateLocalizableResourceString(nameof(DoNotUseWeakCryptographicAlgorithmsDescription)),
                isPortedFxCopRule: false,
                isDataflowRule: false);

        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(DoNotUseBrokenCryptographyRule, DoNotUseWeakCryptographyRule);

        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();

            // Security analyzer - analyze and report diagnostics on generated code.
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext context) =>
                {
                    var cryptTypes = new CompilationSecurityTypes(context.Compilation);
                    if (!ReferencesAnyTargetType(cryptTypes))
                    {
                        return;
                    }

                    context.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                        {
                            IMethodSymbol method;

                            switch (operationAnalysisContext.Operation)
                            {
                                case IInvocationOperation invocationOperation:
                                    method = invocationOperation.TargetMethod;
                                    break;
                                case IObjectCreationOperation objectCreationOperation:
                                    if (objectCreationOperation.Constructor == null)
                                        return;
                                    method = objectCreationOperation.Constructor;
                                    break;
                                default:
                                    Debug.Fail($"Unhandled IOperation {operationAnalysisContext.Operation.Kind}");
                                    return;
                            }

                            INamedTypeSymbol type = method.ContainingType;
                            DiagnosticDescriptor rule;
                            string algorithmName;

                            if (type.DerivesFrom(cryptTypes.MD5))
                            {
                                rule = DoNotUseBrokenCryptographyRule;
                                algorithmName = cryptTypes.MD5.Name;
                            }
                            else if (type.DerivesFrom(cryptTypes.SHA1))
                            {
                                rule = DoNotUseWeakCryptographyRule;
                                algorithmName = cryptTypes.SHA1.Name;
                            }
                            else if (type.DerivesFrom(cryptTypes.HMACSHA1))
                            {
                                rule = DoNotUseWeakCryptographyRule;
                                algorithmName = cryptTypes.HMACSHA1.Name;
                            }
                            else if (type.DerivesFrom(cryptTypes.DES))
                            {
                                rule = DoNotUseBrokenCryptographyRule;
                                algorithmName = cryptTypes.DES.Name;
                            }
                            else if ((method.ContainingType.DerivesFrom(cryptTypes.DSA)
                                      && method.MetadataName == SecurityMemberNames.CreateSignature)
                                || (type.Equals(cryptTypes.DSASignatureFormatter)
                                    && method.ContainingType.DerivesFrom(cryptTypes.DSASignatureFormatter)
                                    && method.MetadataName == WellKnownMemberNames.InstanceConstructorName))
                            {
                                rule = DoNotUseBrokenCryptographyRule;
                                algorithmName = "DSA";
                            }
                            else if (type.DerivesFrom(cryptTypes.HMACMD5))
                            {
                                rule = DoNotUseBrokenCryptographyRule;
                                algorithmName = cryptTypes.HMACMD5.Name;
                            }
                            else if (type.DerivesFrom(cryptTypes.RC2))
                            {
                                rule = DoNotUseBrokenCryptographyRule;
                                algorithmName = cryptTypes.RC2.Name;
                            }
                            else if (type.DerivesFrom(cryptTypes.TripleDES))
                            {
                                rule = DoNotUseWeakCryptographyRule;
                                algorithmName = cryptTypes.TripleDES.Name;
                            }
                            else if (type.DerivesFrom(cryptTypes.RIPEMD160))
                            {
                                rule = DoNotUseWeakCryptographyRule;
                                algorithmName = cryptTypes.RIPEMD160.Name;
                            }
                            else if (type.DerivesFrom(cryptTypes.HMACRIPEMD160))
                            {
                                rule = DoNotUseWeakCryptographyRule;
                                algorithmName = cryptTypes.HMACRIPEMD160.Name;
                            }
                            else
                            {
                                return;
                            }

                            operationAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    rule,
                                    operationAnalysisContext.Operation.Syntax.GetLocation(),
                                    operationAnalysisContext.ContainingSymbol.Name,
                                    algorithmName));
                        },
                        OperationKind.Invocation,
                        OperationKind.ObjectCreation);
                });
        }

        private static bool ReferencesAnyTargetType(CompilationSecurityTypes types)
        {
            return types.MD5 != null
                || types.SHA1 != null
                || types.HMACSHA1 != null
                || types.DES != null
                || types.DSA != null
                || types.DSASignatureFormatter != null
                || types.HMACMD5 != null
                || types.RC2 != null
                || types.TripleDES != null
                || types.RIPEMD160 != null
                || types.HMACRIPEMD160 != null;
        }
    }
}