Skip to content

Commit

Permalink
Migrate S3329: Scaffold the rule for the new SE (#7563)
Browse files Browse the repository at this point in the history
  • Loading branch information
mary-georgiou-sonarsource authored Jul 12, 2023
1 parent 239e7f2 commit e9edd5f
Show file tree
Hide file tree
Showing 8 changed files with 611 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* SonarAnalyzer for .NET
* Copyright (C) 2015-2023 SonarSource SA
* mailto: contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

namespace SonarAnalyzer.SymbolicExecution.Roslyn.RuleChecks.CSharp;

public sealed class InitializationVectorShouldBeRandom : InitializationVectorShouldBeRandomBase
{
public static readonly DiagnosticDescriptor S3329 = DescriptorFactory.Create(DiagnosticId, MessageFormat);
protected override DiagnosticDescriptor Rule => S3329;

public override bool ShouldExecute() => false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* SonarAnalyzer for .NET
* Copyright (C) 2015-2023 SonarSource SA
* mailto: contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

namespace SonarAnalyzer.SymbolicExecution.Roslyn.RuleChecks;

public abstract class InitializationVectorShouldBeRandomBase : SymbolicRuleCheck
{
protected const string DiagnosticId = "S3329";
protected const string MessageFormat = "Use a dynamically-generated, random IV.";
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,51 +18,102 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using SonarAnalyzer.Rules.CSharp;
using SonarAnalyzer.SymbolicExecution.Sonar.Analyzers;

using ChecksCS = SonarAnalyzer.SymbolicExecution.Roslyn.RuleChecks.CSharp;
using CS = SonarAnalyzer.Rules.CSharp;

namespace SonarAnalyzer.UnitTest.Rules
{
[TestClass]
public class InitializationVectorShouldBeRandomTest
{
private readonly VerifierBuilder sonar = new VerifierBuilder<SymbolicExecutionRunner>().WithBasePath(@"SymbolicExecution\Sonar")
.WithOnlyDiagnostics(InitializationVectorShouldBeRandom.S3329)
.AddReferences(MetadataReferenceFacade.SystemSecurityCryptography);
private readonly VerifierBuilder sonar = new VerifierBuilder()
.AddAnalyzer(() => new CS.SymbolicExecutionRunner(AnalyzerConfiguration.AlwaysEnabledWithSonarCfg))
.WithBasePath(@"SymbolicExecution\Sonar")
.AddReferences(MetadataReferenceFacade.SystemSecurityCryptography)
.WithOnlyDiagnostics(InitializationVectorShouldBeRandom.S3329);

private readonly VerifierBuilder roslynCS = new VerifierBuilder()
.AddAnalyzer(() => new CS.SymbolicExecutionRunner(AnalyzerConfiguration.AlwaysEnabled))
.WithBasePath(@"SymbolicExecution\Roslyn")
.AddReferences(MetadataReferenceFacade.SystemSecurityCryptography)
.WithOnlyDiagnostics(ChecksCS.InitializationVectorShouldBeRandom.S3329);

[TestMethod]
public void InitializationVectorShouldBeRandom_CSharp8() =>
public void InitializationVectorShouldBeRandom_Sonar_CS() =>
sonar.AddPaths("InitializationVectorShouldBeRandom.cs")
.WithOptions(ParseOptionsHelper.FromCSharp8)
.Verify();

[Ignore] // ToDo: Remove after S3329 implementation
[TestMethod]
public void InitializationVectorShouldBeRandom_Roslyn_CS() =>
roslynCS.AddPaths("InitializationVectorShouldBeRandom.cs")
.Verify();

[Ignore] // ToDo: Remove after S3329 implementation
[TestMethod]
public void InitializationVectorShouldBeRandom_Roslyn_CSharp8() =>
roslynCS.AddPaths("InitializationVectorShouldBeRandom.CSharp8.cs")
.WithOptions(ParseOptionsHelper.FromCSharp8)
.Verify();

[TestMethod]
public void InitializationVectorShouldBeRandom_DoesNotRaiseIssuesForTestProject() =>
public void InitializationVectorShouldBeRandom_DoesNotRaiseIssuesForTestProject_Sonar() =>
sonar.AddPaths("InitializationVectorShouldBeRandom.cs")
.WithOptions(ParseOptionsHelper.FromCSharp8)
.AddTestReference()
.VerifyNoIssueReported();

[Ignore] // ToDo: Remove after S3329 implementation
[TestMethod]
public void InitializationVectorShouldBeRandom_DoesNotRaiseIssuesForTestProject_Roslyn_CS() =>
roslynCS.AddPaths("InitializationVectorShouldBeRandom.cs")
.AddTestReference()
.VerifyNoIssueReported();

#if NET

[TestMethod]
public void InitializationVectorShouldBeRandom_CSharp9() =>
public void InitializationVectorShouldBeRandom_Sonar_CSharp9() =>
sonar.AddPaths("InitializationVectorShouldBeRandom.CSharp9.cs")
.WithTopLevelStatements()
.Verify();

[Ignore] // ToDo: Remove after S3329 implementation
[TestMethod]
public void InitializationVectorShouldBeRandom_CSharp10() =>
public void InitializationVectorShouldBeRandom_Roslyn_CSharp9() =>
roslynCS.AddPaths("InitializationVectorShouldBeRandom.CSharp9.cs")
.WithTopLevelStatements()
.Verify();

[TestMethod]
public void InitializationVectorShouldBeRandom_Sonar_CSharp10() =>
sonar.AddPaths("InitializationVectorShouldBeRandom.CSharp10.cs")
.WithOptions(ParseOptionsHelper.FromCSharp10)
.Verify();

[Ignore] // ToDo: Remove after S3329 implementation
[TestMethod]
public void InitializationVectorShouldBeRandom_Roslyn_CSharp10() =>
roslynCS.AddPaths("InitializationVectorShouldBeRandom.CSharp10.cs")
.WithOptions(ParseOptionsHelper.FromCSharp10)
.Verify();

[TestMethod]
public void InitializationVectorShouldBeRandom_CSharp11() =>
public void InitializationVectorShouldBeRandom_Sonar_CSharp11() =>
sonar.AddPaths("InitializationVectorShouldBeRandom.CSharp11.cs")
.WithOptions(ParseOptionsHelper.FromCSharp11)
.Verify();

[Ignore] // ToDo: Remove after S3329 implementation
[TestMethod]
public void InitializationVectorShouldBeRandom_Roslyn_CSharp11() =>
roslynCS.AddPaths("InitializationVectorShouldBeRandom.CSharp11.cs")
.WithOptions(ParseOptionsHelper.FromCSharp11)
.Verify();

#endif

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Security.Cryptography;

public class Sample
{
public void Examples()
{
AesCng aes = new AesCng();
aes.CreateEncryptor();
(var rgb, int a) = (new byte[16], 42);
aes.CreateEncryptor(aes.Key, rgb); // FIXME Non-compliant
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Security.Cryptography;

public class Sample
{
public void SymetricAlgorithmCreateEncryptor()
{
var initializationVectorConstant = new byte[16];

using (SymmetricAlgorithm sa = SymmetricAlgorithm.Create("AES"))
{
sa.GenerateKey();
var generateIVNotCalled = sa.CreateEncryptor(sa.Key, sa.IV);
var constantVector2 = sa.CreateEncryptor(sa.Key, "1234567890123456"u8.ToArray()); // FIXME Non-compliant
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
using System.Security.Cryptography;

class InitializationVectorShouldBeRandom
{
public void UsingRandomNumberGeneratorIsCompliant()
{
var initializationVectorConstant = new byte[16];
var initializationVectorRng = new byte[16];
var initializationVectorRngNonZero = new byte[16];

using var rng = RandomNumberGenerator.Create();
rng.GetBytes(initializationVectorRng);
rng.GetNonZeroBytes(initializationVectorRngNonZero);

using var sa = SymmetricAlgorithm.Create("AES");

sa.GenerateKey();
var fromRng = sa.CreateEncryptor(sa.Key, initializationVectorRng);
var fromRngNonZero = sa.CreateEncryptor(sa.Key, initializationVectorRngNonZero);

sa.GenerateIV();
var fromGenerateIV = sa.CreateEncryptor(sa.Key, sa.IV);

sa.CreateDecryptor(sa.Key, initializationVectorConstant); // Compliant, not relevant for decrypting
}

public void AesCryptoServiceProviderCreateEncryptor()
{
using var aes = new AesCryptoServiceProvider();
using var rng = new RNGCryptoServiceProvider();

var noParams = aes.CreateEncryptor(); // Compliant

var constantIV = new byte[16];
var withConstant = aes.CreateEncryptor(aes.Key, constantIV); // FIXME Non-compliant

aes.GenerateKey();
aes.GenerateIV();
aes.CreateEncryptor();
var withGeneratedKeyAndIV = aes.CreateEncryptor(aes.Key, aes.IV);

aes.CreateDecryptor(aes.Key, constantIV); // Compliant, we do not check CreateDecryptor

rng.GetBytes(constantIV);
var fromRng = aes.CreateEncryptor(aes.Key, constantIV);
}

public void AesCreateEncryptor()
{
using var aes = Aes.Create();
using var rng = new RNGCryptoServiceProvider();

var noParams = aes.CreateEncryptor(); // Compliant

aes.GenerateKey();
var reGeneratedKey = aes.CreateEncryptor(); // Compliant

var constantIV = new byte[16];
var withConstant = aes.CreateEncryptor(aes.Key, constantIV); // FIXME Non-compliant

aes.GenerateIV();
aes.CreateEncryptor();
var withGeneratedKeyAndIV = aes.CreateEncryptor(aes.Key, aes.IV);

aes.CreateDecryptor(aes.Key, constantIV); // Compliant, we do not check CreateDecryptor

rng.GetBytes(constantIV);
var fromRng = aes.CreateEncryptor(aes.Key, constantIV);
}

public void AesCngCreateEncryptor()
{
using var aes = new AesCng();
using var rng = new RNGCryptoServiceProvider();

var noParams = aes.CreateEncryptor(); // Compliant

aes.GenerateKey();
var withGeneratedKey = aes.CreateEncryptor(); // Compliant

var constantIV = new byte[16];
var withConstant = aes.CreateEncryptor(aes.Key, constantIV); // FIXME Non-compliant

aes.GenerateIV();
aes.CreateEncryptor();
var withGeneratedKeyAndIV = aes.CreateEncryptor(aes.Key, aes.IV);

aes.CreateDecryptor(aes.Key, constantIV); // Compliant, we do not check CreateDecryptor

rng.GetBytes(constantIV);
var fromRng = aes.CreateEncryptor(aes.Key, constantIV);
}

public void CustomImplementationOfAes()
{
using var aes = new CustomAes();
using var rng = new RNGCryptoServiceProvider();

var noParams = aes.CreateEncryptor(); // Compliant

aes.GenerateKey();
var withGeneratedKey = aes.CreateEncryptor(); // Compliant

var constantIV = new byte[16];
var withConstant = aes.CreateEncryptor(aes.Key, constantIV); // FIXME Non-compliant

aes.GenerateIV();
aes.CreateEncryptor();
var withGeneratedKeyAndIV = aes.CreateEncryptor(aes.Key, aes.IV);

aes.CreateDecryptor(aes.Key, constantIV); // Compliant, we do not check CreateDecryptor

rng.GetBytes(constantIV);
var fromRng = aes.CreateEncryptor(aes.Key, constantIV);
}

public void InConditionals(int a)
{
var constantIV = new byte[16];

using var aes = new AesCng();
using var rng = new RNGCryptoServiceProvider();

var e = a switch
{
1 => aes.CreateEncryptor(), // Compliant
2 => aes.CreateEncryptor(aes.Key, constantIV), // FIXME Non-compliant
_ => null
};

var iv = new byte[16];

using var aes2 = new AesCng();
if (a == 1)
{
aes2.IV = iv; // Set IV to constant
}
aes2.CreateEncryptor(); // FIXME Non-compliant

var aes3 = a == 2 ? aes2 : aes;
aes3.CreateEncryptor(); // FIXME Non-compliant
}
}

public class CustomAes : Aes
{
public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) => throw new NotImplementedException();

public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) => throw new NotImplementedException();

public override void GenerateIV() => throw new NotImplementedException();

public override void GenerateKey() => throw new NotImplementedException();
}
Loading

0 comments on commit e9edd5f

Please sign in to comment.