Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net6.0 #4

Merged
merged 12 commits into from
Jun 16, 2022
22 changes: 20 additions & 2 deletions src/Cats.CertificateTransparency.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30711.63
# Visual Studio Version 17
VisualStudioVersion = 17.3.32519.111
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cats.CertificateTransparency", "Cats.CertificateTransparency\Cats.CertificateTransparency.csproj", "{E9314C8B-7CA6-4295-9FB3-0BBB22C9455D}"
EndProject
Expand All @@ -24,6 +24,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests\Tests.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.Data", "Tests\Tests.Data\Tests.Data.csproj", "{28ED2DC4-22B1-456E-9C23-2882DC5508C4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples.Droid.net6", "Samples\Samples.Droid.net6\Samples.Droid.net6.csproj", "{C86573DA-9227-462B-9267-34816FE23908}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.Droid.net6", "Tests\Tests.Droid.net6\Tests.Droid.net6.csproj", "{E83305F6-E317-4095-93A1-80705C27C339}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -58,6 +62,18 @@ Global
{28ED2DC4-22B1-456E-9C23-2882DC5508C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{28ED2DC4-22B1-456E-9C23-2882DC5508C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{28ED2DC4-22B1-456E-9C23-2882DC5508C4}.Release|Any CPU.Build.0 = Release|Any CPU
{C86573DA-9227-462B-9267-34816FE23908}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C86573DA-9227-462B-9267-34816FE23908}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C86573DA-9227-462B-9267-34816FE23908}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{C86573DA-9227-462B-9267-34816FE23908}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C86573DA-9227-462B-9267-34816FE23908}.Release|Any CPU.Build.0 = Release|Any CPU
{C86573DA-9227-462B-9267-34816FE23908}.Release|Any CPU.Deploy.0 = Release|Any CPU
{E83305F6-E317-4095-93A1-80705C27C339}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E83305F6-E317-4095-93A1-80705C27C339}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E83305F6-E317-4095-93A1-80705C27C339}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{E83305F6-E317-4095-93A1-80705C27C339}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E83305F6-E317-4095-93A1-80705C27C339}.Release|Any CPU.Build.0 = Release|Any CPU
{E83305F6-E317-4095-93A1-80705C27C339}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -68,6 +84,8 @@ Global
{18497B17-CD53-46DC-AC16-D3F1BD3178D7} = {EC994E11-0FEB-4EAA-B2F8-3A72A4317BBC}
{515FB7C4-F8AC-4D02-9978-D350A246F408} = {EC994E11-0FEB-4EAA-B2F8-3A72A4317BBC}
{28ED2DC4-22B1-456E-9C23-2882DC5508C4} = {EC994E11-0FEB-4EAA-B2F8-3A72A4317BBC}
{C86573DA-9227-462B-9267-34816FE23908} = {82221379-8EB9-4D51-96CE-30FCACF9CB70}
{E83305F6-E317-4095-93A1-80705C27C339} = {EC994E11-0FEB-4EAA-B2F8-3A72A4317BBC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {70BA6A45-D92F-4A03-BDE0-0D851B48A4A6}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="MSBuild.Sdk.Extras/2.1.2">
<Project Sdk="MSBuild.Sdk.Extras/3.0.44">

<PropertyGroup>
<TargetFrameworks>netstandard2.1;monoandroid10.0;</TargetFrameworks>
<TargetFrameworks>netstandard2.1;monoandroid10.0;net6.0;net6.0-android;</TargetFrameworks>
<LangVersion>latest</LangVersion>

<AssemblyName>Cats.CertificateTransparency</AssemblyName>
Expand All @@ -15,8 +15,8 @@
<Product>$(AssemblyName) ($(TargetFramework))</Product>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<AssemblyFileVersion>1.0.0.0</AssemblyFileVersion>
<Version>1.3.0</Version>
<PackageVersion>1.3.0</PackageVersion>
<Version>2.0.0</Version>
<PackageVersion>2.0.0</PackageVersion>
<Authors>dmariogatto</Authors>
<Owners>dmariogatto</Owners>
<NeutralLanguage>en</NeutralLanguage>
Expand All @@ -25,8 +25,8 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryType>git</RepositoryType>
<PackageReleaseNotes>
- Updated dependencies
- Linker safe
- Added net6.0 and net6.0-android support
- [net6.0-android] `CatsAndroidClientHandler` has been deprecated and removed. Use `CatsAndroidMessageHandler` instead.
</PackageReleaseNotes>
</PropertyGroup>

Expand All @@ -35,6 +35,10 @@
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>

<PropertyGroup Condition="$(TargetFramework.EndsWith('-android'))">
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
</PropertyGroup>

<ItemGroup>
<None Include="../../logo.png">
<Pack>True</Pack>
Expand All @@ -58,7 +62,11 @@
<None Include="Platforms\**\*.*" />
</ItemGroup>

<ItemGroup Condition=" $(TargetFramework.StartsWith('monoandroid')) ">
<ItemGroup Condition="$(TargetFramework.EndsWith('-android')) ">
<Compile Include="Platforms\Android\**\*.cs" />
</ItemGroup>

<ItemGroup Condition="$(TargetFramework.StartsWith('monoandroid')) ">
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />

Expand Down
36 changes: 29 additions & 7 deletions src/Cats.CertificateTransparency/Constants/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#if DEBUG
[assembly: InternalsVisibleTo("Tests")]
[assembly: InternalsVisibleTo("Tests.Droid")]
[assembly: InternalsVisibleTo("Tests.Droid.net6")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
#endif

Expand All @@ -12,15 +13,20 @@ namespace Cats.CertificateTransparency
public static class Constants
{
public const int BitsInByte = 8;
public const int BytesInLong = 8;

public const int ExtensionsMaxLength = (1 << 16) - 1;
public const int SignatureMaxLength = (1 << 16) - 1;
public const int KeyIdLength = 32;
public const int TimestampLength = 8;
public const int VersionLength = 1;
public const int LogEntryTypeLength = 2;
public const int CertificateMaxLength = (1 << 24) - 1;
public const int X509TbsSequenceIndex = 0;
public const int TbsSpkiSequenceIndex = 6;

public const int ExtensionsMaxValue = (1 << 16) - 1;
public const int SignatureMaxValue = (1 << 16) - 1;
public const int CertificateMaxValue = (1 << 24) - 1;

public const int KeyIdNumOfBytes = 32;
public const int TimestampNumOfBytes = 8;
public const int VersionNumOfBytes = 1;
public const int LogEntryTypeNumOfBytes = 2;

public const string PreCertificateSigningOid = "1.3.6.1.4.1.11129.2.4.4";
public const string PoisonOid = "1.3.6.1.4.1.11129.2.4.3";
public const string SctCertificateOid = "1.3.6.1.4.1.11129.2.4.2";
Expand All @@ -35,5 +41,21 @@ public static class Constants

public const string Sha256WithRsa = "SHA256withRSA";
public const string Sha256WithEcdsa = "SHA256withECDSA";

internal static int BytesToStoreValue(int value)
{
if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Cannot be negative");

var numBytes = 0;
var local = value;

while (local > 0)
{
local >>= Constants.BitsInByte;
numBytes++;
}

return numBytes;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal static class SignedCertificateTimestampExtensions
{
internal static SctVerificationResult VerifySignature(this SignedCertificateTimestamp sct, Log logServer, IList<X509Certificate2> chain)
{
if (logServer == null || sct == null || chain?.Any() != true || logServer.LogId != sct.LogIdBase64)
if (logServer is null || sct is null || chain?.Any() != true || logServer.LogId != sct.LogIdBase64)
return SctVerificationResult.FailedVerification(sct.TimestampUtc, logServer?.LogId, "Invalid verification arguments");

var nowUtc = DateTime.UtcNow;
Expand Down Expand Up @@ -80,24 +80,27 @@ private static TbsCertificateStructure CreateTbsForVerification(X509Certificate2
{
if (preCertificate.Version < 3) throw new InvalidOperationException("PreCertificate version must be 3 or higher!");

var asn1Obj = Asn1Object.FromByteArray(preCertificate.GetTbsCertificateRaw());
var asn1Obj = preCertificate.GetTbsCertificateAsn1Object();
var tbsCert = TbsCertificateStructure.GetInstance(asn1Obj);
var hasX509AuthorityKeyIdentifier = tbsCert.Extensions.GetExtension(new DerObjectIdentifier(Constants.X509AuthorityKeyIdentifier)) != null;
var hasX509AuthorityKeyIdentifier = tbsCert.Extensions.GetExtension(new DerObjectIdentifier(Constants.X509AuthorityKeyIdentifier)) is not null;

if (hasX509AuthorityKeyIdentifier &&
issuerInformation.IssuedByPreCertificateSigningCert &&
issuerInformation.X509AuthorityKeyIdentifier == null)
issuerInformation.X509AuthorityKeyIdentifier is null)
{
throw new InvalidOperationException("PreCertificate was not signed by a PreCertificate signing cert");
}

var orderedExtensions = GetExtensionsWithoutPoisonAndSct(tbsCert.Extensions, issuerInformation.X509AuthorityKeyIdentifier);
var issuer = !string.IsNullOrEmpty(issuerInformation.Name)
? new X509Name(issuerInformation.Name)
: tbsCert.Issuer;
var orderedExtensions = GetExtensionsWithoutPoisonAndSct(tbsCert.Extensions, issuerInformation);

var generator = new V3TbsCertificateGenerator();

generator.SetSerialNumber(tbsCert.SerialNumber);
generator.SetSignature(tbsCert.Signature);
generator.SetIssuer(issuerInformation.Name ?? tbsCert.Issuer);
generator.SetIssuer(issuer);
generator.SetStartDate(tbsCert.StartDate);
generator.SetEndDate(tbsCert.EndDate);
generator.SetSubject(tbsCert.Subject);
Expand All @@ -114,17 +117,19 @@ private static TbsCertificateStructure CreateTbsForVerification(X509Certificate2
return generator.GenerateTbsCertificate();
}

private static Dictionary<DerObjectIdentifier, X509Extension> GetExtensionsWithoutPoisonAndSct(X509Extensions extensions, X509Extension replacementX509Authority)
private static Dictionary<DerObjectIdentifier, X509Extension> GetExtensionsWithoutPoisonAndSct(X509Extensions extensions, IssuerInformation issuerInformation)
{
var result = new Dictionary<DerObjectIdentifier, X509Extension>();

foreach (DerObjectIdentifier oid in extensions.GetExtensionOids())
{
if (oid.Id != Constants.PoisonOid && oid.Id != Constants.SctCertificateOid)
if (!oid.Id.Equals(Constants.PoisonOid, StringComparison.Ordinal) && !oid.Id.Equals(Constants.SctCertificateOid, StringComparison.Ordinal))
{
if (oid.Id == Constants.X509AuthorityKeyIdentifier && replacementX509Authority != null)
if (issuerInformation?.X509AuthorityKeyIdentifier is not null && oid.Id.Equals(Constants.X509AuthorityKeyIdentifier, StringComparison.Ordinal))
{
result.Add(oid, replacementX509Authority);
var critical = issuerInformation.X509AuthorityKeyIdentifier.Critical;
var asn1OctetString = Asn1Object.FromByteArray(issuerInformation.X509AuthorityKeyIdentifier.RawData) as DerOctetString;
result.Add(oid, new X509Extension(critical, asn1OctetString));
}
else
{
Expand Down Expand Up @@ -163,9 +168,9 @@ private static byte[] SerialiseSignedSctData(this SignedCertificateTimestamp sct

SerialiseCommonFields(bw, sct);

bw.WriteLong(0, Constants.LogEntryTypeLength); // X509 Entry
bw.WriteVariableLength(certificate.RawData, Constants.CertificateMaxLength);
bw.WriteVariableLength(sct.Extensions, Constants.ExtensionsMaxLength);
bw.WriteLong(0, Constants.LogEntryTypeNumOfBytes); // X509 Entry
bw.WriteVariableLength(certificate.RawData, Constants.CertificateMaxValue);
bw.WriteVariableLength(sct.Extensions, Constants.ExtensionsMaxValue);

return ms.ToArray();
}
Expand All @@ -177,10 +182,10 @@ private static byte[] SerialiseSignedSctDataForPreCertificate(this SignedCertifi

SerialiseCommonFields(bw, sct);

bw.WriteLong(1, Constants.LogEntryTypeLength); // PerCert Entry
bw.WriteLong(1, Constants.LogEntryTypeNumOfBytes); // PerCert Entry
bw.Write(issuerKeyHash);
bw.WriteVariableLength(preCert, Constants.CertificateMaxLength);
bw.WriteVariableLength(sct.Extensions, Constants.ExtensionsMaxLength);
bw.WriteVariableLength(preCert, Constants.CertificateMaxValue);
bw.WriteVariableLength(sct.Extensions, Constants.ExtensionsMaxValue);

return ms.ToArray();
}
Expand All @@ -189,9 +194,9 @@ private static void SerialiseCommonFields(BinaryWriter bw, SignedCertificateTime
{
if (sct.SctVersion != SctVersion.V1) throw new InvalidOperationException("Can only serialise SCT v1!");

bw.WriteLong((long)sct.SctVersion, Constants.VersionLength);
bw.WriteLong((long)sct.SctVersion, Constants.VersionNumOfBytes);
bw.WriteLong(0, 1); // Certificate Timestamp
bw.WriteLong(sct.TimestampMs, Constants.TimestampLength);
bw.WriteLong(sct.TimestampMs, Constants.TimestampNumOfBytes);
}

private static (string oid, CtSignatureAlgorithm sigAlg) GetKeyAlgorithm(byte[] keyBytes)
Expand Down
37 changes: 37 additions & 0 deletions src/Cats.CertificateTransparency/Extensions/SpanExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.IO;

namespace Cats.CertificateTransparency.Extensions
{
internal static class SpanExtensions
{
internal static long ReadLong(this Span<byte> span, int bytesToRead, ref int position)
{
if (bytesToRead > Constants.BytesInLong)
throw new ArgumentOutOfRangeException(nameof(bytesToRead), $"Cannot read long of length {bytesToRead} bytes");

var result = 0L;

for (var i = 0; i < bytesToRead; i++)
{
var readVal = span[position++];
result = (result << Constants.BitsInByte) | readVal;
}

return result;
}

internal static Span<byte> ReadVariableLength(this Span<byte> span, int maxDataValue, ref int position)
{
var bytesForDataLength = Constants.BytesToStoreValue(maxDataValue);
var dataLength = ReadLong(span, bytesForDataLength, ref position);

var data = span.Slice(position, (int)dataLength);
position += data.Length;

if (data.Length != dataLength) throw new IOException($"Incomplete data. Expected {dataLength} bytes, got {span.Length}");

return data;
}
}
}
24 changes: 4 additions & 20 deletions src/Cats.CertificateTransparency/Extensions/StreamExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ internal static class StreamExtensions
{
internal static long ReadLong(this Stream stream, int numberOfBytes)
{
if (numberOfBytes > Constants.BitsInByte)
if (numberOfBytes > Constants.BytesInLong)
throw new ArgumentOutOfRangeException(nameof(numberOfBytes), $"Cannot read long of length {numberOfBytes} bytes");

var result = 0L;
Expand All @@ -22,9 +22,9 @@ internal static long ReadLong(this Stream stream, int numberOfBytes)
return result;
}

internal static byte[] ReadVariableLength(this Stream stream, int maxDataLength)
internal static byte[] ReadVariableLength(this Stream stream, int maxDataValue)
{
var bytesForDataLength = BytesToStoreValue(maxDataLength);
var bytesForDataLength = Constants.BytesToStoreValue(maxDataValue);
var dataLength = ReadLong(stream, bytesForDataLength);

var data = new byte[dataLength];
Expand Down Expand Up @@ -55,25 +55,9 @@ internal static void WriteVariableLength(this BinaryWriter writer, byte[] data,
{
if (data.Length > maxDataLength) throw new ArgumentOutOfRangeException($"Length {data.Length} is greater than max data length {maxDataLength}");

var bytesForDataLength = BytesToStoreValue(maxDataLength);
var bytesForDataLength = Constants.BytesToStoreValue(maxDataLength);
writer.WriteLong(data.Length, bytesForDataLength);
writer.Write(data, 0, data.Length);
}

private static int BytesToStoreValue(int value)
{
if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Cannot be negative");

var numBytes = 0;
var local = value;

while (local > 0)
{
local >>= Constants.BitsInByte;
numBytes++;
}

return numBytes;
}
}
}
Loading