Skip to content

Commit

Permalink
harrison314#3 Add tests to PKCS11 data provider.
Browse files Browse the repository at this point in the history
  • Loading branch information
harrison314 committed Dec 12, 2020
1 parent 3f08718 commit 2fcf4fc
Show file tree
Hide file tree
Showing 8 changed files with 445 additions and 33 deletions.
9 changes: 8 additions & 1 deletion src/Harrison314.EntityFrameworkCore.Encryption.sln
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleWebApiProject", "samp
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Harrison314.EntityFrameworkCore.Encryption.Tests", "test\Harrison314.EntityFrameworkCore.Encryption.Tests\Harrison314.EntityFrameworkCore.Encryption.Tests.csproj", "{1597ACD3-CB40-438F-8B84-8449A93930EE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Harrison314.EntityFrameworkCore.Encryption.Contrib", "src\Harrison314.EntityFrameworkCore.Encryption.Contrib\Harrison314.EntityFrameworkCore.Encryption.Contrib.csproj", "{97F417DA-B277-42F4-973E-2299711D5F41}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Harrison314.EntityFrameworkCore.Encryption.Contrib", "src\Harrison314.EntityFrameworkCore.Encryption.Contrib\Harrison314.EntityFrameworkCore.Encryption.Contrib.csproj", "{97F417DA-B277-42F4-973E-2299711D5F41}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Harrison314.EntityFrameworkCore.Contrib.Tests", "test\Harrison314.EntityFrameworkCore.Contrib.Tests\Harrison314.EntityFrameworkCore.Contrib.Tests.csproj", "{EB712EF3-DC52-4209-9FC0-8CCA028EC8BE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -44,6 +46,10 @@ Global
{97F417DA-B277-42F4-973E-2299711D5F41}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97F417DA-B277-42F4-973E-2299711D5F41}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97F417DA-B277-42F4-973E-2299711D5F41}.Release|Any CPU.Build.0 = Release|Any CPU
{EB712EF3-DC52-4209-9FC0-8CCA028EC8BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB712EF3-DC52-4209-9FC0-8CCA028EC8BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB712EF3-DC52-4209-9FC0-8CCA028EC8BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB712EF3-DC52-4209-9FC0-8CCA028EC8BE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -53,6 +59,7 @@ Global
{074639A4-FF0F-482D-A2E0-2A48D12FB5EE} = {A968397F-6358-47B8-B0F1-793E669947F8}
{1597ACD3-CB40-438F-8B84-8449A93930EE} = {9075C7DF-76A9-4080-ACDE-E650B0BA2E12}
{97F417DA-B277-42F4-973E-2299711D5F41} = {BF96E918-3D85-4AB6-81C7-C70B85D08746}
{EB712EF3-DC52-4209-9FC0-8CCA028EC8BE} = {9075C7DF-76A9-4080-ACDE-E650B0BA2E12}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {824006CF-B329-40CA-B72C-CA9ED5C28DFA}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Harrison314.EntityFrameworkCore.Encryption.Contrib.CryptoProviders.Pkcs11Data
{
public struct DataInfo
{
public string Id
{
get;
private set;
}

public string Label
{
get;
private set;
}

public DataInfo(string id, string label)
{
this.Id = id;
this.Label = label;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ public Pkcs11DataGenerator(string pkcs11LibPath, string tokenLabel, SecureString
});
}

public void GenerateDataObject(string label, string ckaId, int dataSize = 32)
public void GenerateDataObject(string application, string objectId, int dataSize = 32)
{
if (label == null) throw new ArgumentNullException(nameof(label));
if (ckaId == null) throw new ArgumentNullException(nameof(ckaId));
if (application == null) throw new ArgumentNullException(nameof(application));
if (objectId == null) throw new ArgumentNullException(nameof(objectId));

using ISession session = this.slot.OpenSession(SessionType.ReadWrite);

Expand All @@ -71,9 +71,8 @@ public void GenerateDataObject(string label, string ckaId, int dataSize = 32)
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_DATA),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PRIVATE, true),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, ckaId),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_LABEL, label),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_APPLICATION, "Harrison314.Encryption"),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_OBJECT_ID, objectId),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_APPLICATION, application),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_VALUE, data)
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ public async ValueTask<byte[]> DecryptMasterKey(MasterKeyData masterKeyData, Can
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_DATA),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PRIVATE, true),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, masterKeyData.KeyId),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_OBJECT_ID, masterKeyData.KeyId),
};

List<CKA> findAttributesTempalte = new List<CKA>()
{
CKA.CKA_ID,
CKA.CKA_LABEL,
CKA.CKA_OBJECT_ID,
CKA.CKA_APPLICATION,
CKA.CKA_VALUE
};

Expand All @@ -84,7 +84,7 @@ public async ValueTask<byte[]> DecryptMasterKey(MasterKeyData masterKeyData, Can
string ckaId = values[0].GetValueAsString();
string ckaLabel = values[1].GetValueAsString();

if (this.pkcs11Options.Value.DataObjectFilter((ckaId, ckaLabel)))
if (this.pkcs11Options.Value.DataObjectFilter(new DataInfo(ckaId, ckaLabel)))
{
byte[] data = values[2].GetValueAsByteArray();
Pkcs11SecritData pkcs11SecritData = System.Text.Json.JsonSerializer.Deserialize<Pkcs11SecritData>(masterKeyData.Parameters);
Expand Down Expand Up @@ -131,13 +131,13 @@ public async ValueTask<MasterKeyData> EncryptMasterKey(byte[] masterKey, Cancell
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_DATA),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PRIVATE, true),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, this.pkcs11Options.Value.MainDataKeyId),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_OBJECT_ID, this.pkcs11Options.Value.MainDataKeyId),
};

List<CKA> findAttributesTempalte = new List<CKA>()
{
CKA.CKA_ID,
CKA.CKA_LABEL,
CKA.CKA_OBJECT_ID,
CKA.CKA_APPLICATION,
CKA.CKA_VALUE
};

Expand All @@ -147,10 +147,10 @@ public async ValueTask<MasterKeyData> EncryptMasterKey(byte[] masterKey, Cancell

List<IObjectAttribute> values = session.GetAttributeValue(dataHandle, findAttributesTempalte);

string ckaId = values[0].GetValueAsString();
string ckaLabel = values[1].GetValueAsString();
string ckaObjectId = values[0].GetValueAsString();
string ckaApplication = values[1].GetValueAsString();

if (this.pkcs11Options.Value.DataObjectFilter((ckaId, ckaLabel)))
if (this.pkcs11Options.Value.DataObjectFilter(new DataInfo(ckaObjectId, ckaApplication)))
{
byte[] data = values[2].GetValueAsByteArray();
byte[] key = this.DerieveKey(data, pkcs11SeecritData);
Expand All @@ -163,15 +163,15 @@ public async ValueTask<MasterKeyData> EncryptMasterKey(byte[] masterKey, Cancell
MasterKeyData masterKeyData = new MasterKeyData()
{
Data = encryptedKey,
KeyId = ckaId,
KeyId = ckaObjectId,
Parameters = System.Text.Json.JsonSerializer.Serialize(pkcs11SeecritData)
};

return masterKeyData;
}
else
{
this.logger.LogDebug("Skip data object witj keyId: {keyId} label: {label}. Not match data object filter.", ckaId, ckaLabel);
this.logger.LogDebug("Skip data object witj keyId: {keyId} label: {label}. Not match data object filter.", ckaObjectId, ckaApplication);
}
}

Expand All @@ -197,8 +197,8 @@ public async ValueTask<string> FilterAcceptKeyIds(List<string> keyIds, Cancellat

List<CKA> findAttributesTempalte = new List<CKA>()
{
CKA.CKA_ID,
CKA.CKA_LABEL
CKA.CKA_OBJECT_ID,
CKA.CKA_APPLICATION
};

foreach (IObjectHandle dataHandle in session.FindAllObjects(attributesTemplate))
Expand All @@ -207,20 +207,20 @@ public async ValueTask<string> FilterAcceptKeyIds(List<string> keyIds, Cancellat

List<IObjectAttribute> values = session.GetAttributeValue(dataHandle, findAttributesTempalte);

string ckaId = values[0].GetValueAsString();
string ckaLabel = values[1].GetValueAsString();
string ckaObjectId = values[0].GetValueAsString();
string ckaApplication = values[1].GetValueAsString();

if (this.pkcs11Options.Value.DataObjectFilter((ckaId, ckaLabel)))
if (this.pkcs11Options.Value.DataObjectFilter(new DataInfo(ckaObjectId, ckaApplication)))
{
if (keyIds.Any(t => string.Equals(t, ckaId)))
if (keyIds.Any(t => string.Equals(t, ckaObjectId)))
{
this.logger.LogTrace("Found keyId: {keyId}", ckaId);
return ckaId;
this.logger.LogTrace("Found ckaObjectId: {ckaObjectId}", ckaObjectId);
return ckaObjectId;
}
}
}

this.logger.LogDebug("Not found supported keyId.");
this.logger.LogDebug("Not found supported ckaObjectId.");
return null;
}

Expand All @@ -247,7 +247,7 @@ private void ValidateKeyId(string keyId)
throw new ArgumentNullException(nameof(keyId));
}

if (!Regex.IsMatch(keyId, "^[A-Za-z0-9_]{5,32}$", RegexOptions.Singleline, TimeSpan.FromMilliseconds(200)))
if (!Regex.IsMatch(keyId, "^[A-Za-z0-9_-]{5,36}$", RegexOptions.Singleline | RegexOptions.Multiline, TimeSpan.FromMilliseconds(200)))
{
this.logger.LogError("Key id is invalid. KeyId:{0}", keyId);
throw new EfEncryptionException("Invalid keyId.");
Expand Down Expand Up @@ -288,10 +288,17 @@ private async ValueTask EnshureLogged(CancellationToken cancellationToken)
}

SecureString pin = await pinProvider.Invoke(this.serviceProvider, cancellationToken);
PkcsExtensions.SecureStringHelper.ExecuteWithSecureString(pin, Encoding.UTF8, rawPin =>
try
{
this.masterSession.Login(CKU.CKU_USER, rawPin);
});
PkcsExtensions.SecureStringHelper.ExecuteWithSecureString(pin, Encoding.UTF8, rawPin =>
{
this.masterSession.Login(CKU.CKU_USER, rawPin);
});
}
finally
{
pin?.Dispose();
}

this.logger.LogDebug("Sucessfull loged to PKCS11 device.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public string TokenLabel
set;
}

public Predicate<(string, string)> DataObjectFilter
public Predicate<DataInfo> DataObjectFilter
{
get;
set;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Builder;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Harrison314.EntityFrameworkCore.Encryption.CryptoProviders.Remote;
using Microsoft.Extensions.DependencyInjection;

namespace Harrison314.EntityFrameworkCore.Encryption.Contrib
{
public static class EndpointsExtensions
{
public static void MapRemoteEncryptedCryptoProvider<T>(this IEndpointRouteBuilder endpoints, string startUrl)
where T : IDbContextEncryptedCryptoProvider
{
endpoints.MapPost(string.Concat(startUrl.TrimEnd('/'), "/EncryptMasterKey"), async context =>
{
if (!context.Request.HasJsonContentType())
{
context.Response.StatusCode = StatusCodes.Status415UnsupportedMediaType;
return;
}

EncryptMasterKeyRequest request = await context.Request.ReadFromJsonAsync<EncryptMasterKeyRequest>(context.RequestAborted);
//TODO: Validate
T provider = context.RequestServices.GetRequiredService<T>();

MasterKeyData data = await provider.EncryptMasterKey(request.MasterKey, context.RequestAborted);
EncryptMasterKeyResponse response = new EncryptMasterKeyResponse()
{
Data = data.Data,
KeyId = data.KeyId,
Parameters = data.Parameters
};

await context.Response.WriteAsJsonAsync<EncryptMasterKeyResponse>(response, context.RequestAborted);
context.Response.StatusCode = 200;

//TODO: Error handling
});
//TODO: additional actions

endpoints.MapPost(string.Concat(startUrl.TrimEnd('/'), "/FilterAcceptKeyIds"), async context =>
{
if (!context.Request.HasJsonContentType())
{
context.Response.StatusCode = StatusCodes.Status415UnsupportedMediaType;
return;
}

FilterAcceptKeyIdsRequest request = await context.Request.ReadFromJsonAsync<FilterAcceptKeyIdsRequest>(context.RequestAborted);
//TODO: Validate
T provider = context.RequestServices.GetRequiredService<T>();

string selectedKeyId = await provider.FilterAcceptKeyIds(request.KeyIds, context.RequestAborted);
FilterAcceptKeyIdsResponse response = new FilterAcceptKeyIdsResponse()
{
SelectedKeyId = selectedKeyId
};

await context.Response.WriteAsJsonAsync<FilterAcceptKeyIdsResponse>(response, context.RequestAborted);
context.Response.StatusCode = 200;

//TODO: Error handling
});
//TODO: additional actions

endpoints.MapPost(string.Concat(startUrl.TrimEnd('/'), "/DecryptMasterKey"), async context =>
{
if (!context.Request.HasJsonContentType())
{
context.Response.StatusCode = StatusCodes.Status415UnsupportedMediaType;
return;
}

DecryptMasterKeyRequest request = await context.Request.ReadFromJsonAsync<DecryptMasterKeyRequest>(context.RequestAborted);
//TODO: Validate
T provider = context.RequestServices.GetRequiredService<T>();

MasterKeyData data = new MasterKeyData()
{
Data = request.Data,
KeyId = request.KeyId,
Parameters = request.Parameters
};

byte[] masterKey = await provider.DecryptMasterKey(data, context.RequestAborted);
DecryptMasterKeyResponse response = new DecryptMasterKeyResponse()
{
MasterKey = masterKey
};

await context.Response.WriteAsJsonAsync<DecryptMasterKeyResponse>(response, context.RequestAborted);
context.Response.StatusCode = 200;

//TODO: Error handling
});
//TODO: additional actions
}
}
}
Loading

0 comments on commit 2fcf4fc

Please sign in to comment.