public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); // Security analyzer - analyze and report diagnostics on generated code. context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); HazardousUsageEvaluatorCollection hazardousUsageEvaluators = new HazardousUsageEvaluatorCollection( new HazardousUsageEvaluator("GetBytes", HazardousUsageCallback)); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationStartAnalysisContext) => { var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation); if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemSecurityCryptographyRfc2898DeriveBytes, out var rfc2898DeriveBytesTypeSymbol)) { return; } var cancellationToken = compilationStartAnalysisContext.CancellationToken; var sufficientIterationCount = compilationStartAnalysisContext.Options.GetUnsignedIntegralOptionValue( optionName: EditorConfigOptionNames.SufficientIterationCountForWeakKDFAlgorithm, rule: DefinitelyUseWeakKDFInsufficientIterationCountRule, defaultValue: 100000, cancellationToken: cancellationToken); var constructorMapper = new ConstructorMapper( (IMethodSymbol constructorMethod, IReadOnlyList <ValueContentAbstractValue> argumentValueContentAbstractValues, IReadOnlyList <PointsToAbstractValue> argumentPointsToAbstractValues) => { var kind = DefaultIterationCount >= sufficientIterationCount ? PropertySetAbstractValueKind.Unflagged : PropertySetAbstractValueKind.Flagged; if (constructorMethod.Parameters.Length >= 3) { if (constructorMethod.Parameters[2].Name == "iterations" && constructorMethod.Parameters[2].Type.SpecialType == SpecialType.System_Int32) { kind = PropertySetAnalysis.EvaluateLiteralValues(argumentValueContentAbstractValues[2], o => Convert.ToInt32(o) < sufficientIterationCount); } } return(PropertySetAbstractValue.GetInstance(kind)); }); var propertyMappers = new PropertyMapperCollection( new PropertyMapper( "IterationCount", (ValueContentAbstractValue valueContentAbstractValue) => { return(PropertySetAnalysis.EvaluateLiteralValues(valueContentAbstractValue, o => Convert.ToInt32(o) < sufficientIterationCount)); })); var rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance(); compilationStartAnalysisContext.RegisterOperationBlockStartAction( (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) => { operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (rfc2898DeriveBytesTypeSymbol.Equals(invocationOperation.Instance?.Type) && invocationOperation.TargetMethod.Name == "GetBytes") { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add((invocationOperation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.Invocation); operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var argumentOperation = (IArgumentOperation)operationAnalysisContext.Operation; if (rfc2898DeriveBytesTypeSymbol.Equals(argumentOperation.Parameter.Type)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add((argumentOperation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.Argument); }); compilationStartAnalysisContext.RegisterCompilationEndAction( (CompilationAnalysisContext compilationAnalysisContext) => { PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null; try { lock (rootOperationsNeedingAnalysis) { if (!rootOperationsNeedingAnalysis.Any()) { return; } allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages( compilationAnalysisContext.Compilation, rootOperationsNeedingAnalysis, WellKnownTypeNames.SystemSecurityCryptographyRfc2898DeriveBytes, constructorMapper, propertyMappers, hazardousUsageEvaluators, InterproceduralAnalysisConfiguration.Create( compilationAnalysisContext.Options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive, cancellationToken: cancellationToken)); } if (allResults == null) { return; } foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp in allResults) { DiagnosticDescriptor descriptor; switch (kvp.Value) { case HazardousUsageEvaluationResult.Flagged: descriptor = DefinitelyUseWeakKDFInsufficientIterationCountRule; break; case HazardousUsageEvaluationResult.MaybeFlagged: descriptor = MaybeUseWeakKDFInsufficientIterationCountRule; break; default: Debug.Fail($"Unhandled result value {kvp.Value}"); continue; } compilationAnalysisContext.ReportDiagnostic( Diagnostic.Create( descriptor, kvp.Key.Location, sufficientIterationCount)); } } finally { rootOperationsNeedingAnalysis.Free(); allResults?.Free(); } }); }); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); // Security analyzer - analyze and report diagnostics on generated code. context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); HazardousUsageEvaluatorCollection hazardousUsageEvaluators = new HazardousUsageEvaluatorCollection( new HazardousUsageEvaluator("Add", HazardousUsageCallback)); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationStartAnalysisContext) => { var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation); if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemSecurityCryptographyX509CertificatesX509Store, out var x509TypeSymbol)) { return; } if (!wellKnownTypeProvider.TryGetTypeByMetadataName(WellKnownTypeNames.SystemSecurityCryptographyX509CertificatesStoreName, out var storeNameTypeSymbol)) { return; } // If X509Store is initialized with Root store, then that instance is flagged. var constructorMapper = new ConstructorMapper( (IMethodSymbol constructorMethod, IReadOnlyList <ValueContentAbstractValue> argumentValueContentAbstractValues, IReadOnlyList <PointsToAbstractValue> argumentPointsToAbstractValues) => { var kind = PropertySetAbstractValueKind.Unflagged; if (constructorMethod.Parameters.Length > 0) { if (constructorMethod.Parameters[0].Type.Equals(storeNameTypeSymbol)) { kind = PropertySetAnalysis.EvaluateLiteralValues(argumentValueContentAbstractValues[0], o => o.Equals(6)); } else if (constructorMethod.Parameters[0].Type.SpecialType == SpecialType.System_String) { kind = PropertySetAnalysis.EvaluateLiteralValues( argumentValueContentAbstractValues[0], s => string.Equals(s.ToString(), "root", StringComparison.OrdinalIgnoreCase)); } } return(PropertySetAbstractValue.GetInstance(kind)); }); var rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance(); compilationStartAnalysisContext.RegisterOperationBlockStartAction( (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) => { operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; if (x509TypeSymbol.Equals(invocationOperation.Instance?.Type) && invocationOperation.TargetMethod.Name == "Add") { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add((invocationOperation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.Invocation); operationBlockStartAnalysisContext.RegisterOperationAction( (OperationAnalysisContext operationAnalysisContext) => { var argumentOperation = (IArgumentOperation)operationAnalysisContext.Operation; if (x509TypeSymbol.Equals(argumentOperation.Parameter.Type)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add((argumentOperation.GetRoot(), operationAnalysisContext.ContainingSymbol)); } } }, OperationKind.Argument); }); compilationStartAnalysisContext.RegisterCompilationEndAction( (CompilationAnalysisContext compilationAnalysisContext) => { PooledDictionary <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> allResults = null; try { lock (rootOperationsNeedingAnalysis) { if (!rootOperationsNeedingAnalysis.Any()) { return; } allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages( compilationAnalysisContext.Compilation, rootOperationsNeedingAnalysis, WellKnownTypeNames.SystemSecurityCryptographyX509CertificatesX509Store, constructorMapper, PropertyMappers, hazardousUsageEvaluators, InterproceduralAnalysisConfiguration.Create( compilationAnalysisContext.Options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive, cancellationToken: compilationAnalysisContext.CancellationToken)); } if (allResults == null) { return; } foreach (KeyValuePair <(Location Location, IMethodSymbol Method), HazardousUsageEvaluationResult> kvp in allResults) { DiagnosticDescriptor descriptor; switch (kvp.Value) { case HazardousUsageEvaluationResult.Flagged: descriptor = DefinitelyInstallRootCertRule; break; case HazardousUsageEvaluationResult.MaybeFlagged: descriptor = MaybeInstallRootCertRule; break; default: Debug.Fail($"Unhandled result value {kvp.Value}"); continue; } compilationAnalysisContext.ReportDiagnostic( Diagnostic.Create( descriptor, kvp.Key.Location, kvp.Key.Method.ToDisplayString( SymbolDisplayFormat.MinimallyQualifiedFormat))); } } finally { rootOperationsNeedingAnalysis.Free(); allResults?.Free(); } }); }); }