aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/VNLib.Plugins.Extensions.Data/src/Storage/LWStorageDescriptor.cs3
-rw-r--r--lib/VNLib.Plugins.Extensions.Data/src/Storage/LWStorageManager.cs2
-rw-r--r--lib/VNLib.Plugins.Extensions.Loading/src/AssemblyLoader.cs2
-rw-r--r--lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs79
-rw-r--r--lib/VNLib.Plugins.Extensions.Loading/src/PrivateKey.cs23
-rw-r--r--lib/VNLib.Plugins.Extensions.Loading/src/SecretResult.cs4
-rw-r--r--lib/VNLib.Plugins.Extensions.Loading/src/VaultSecrets.cs41
7 files changed, 112 insertions, 42 deletions
diff --git a/lib/VNLib.Plugins.Extensions.Data/src/Storage/LWStorageDescriptor.cs b/lib/VNLib.Plugins.Extensions.Data/src/Storage/LWStorageDescriptor.cs
index 282e969..939d3e3 100644
--- a/lib/VNLib.Plugins.Extensions.Data/src/Storage/LWStorageDescriptor.cs
+++ b/lib/VNLib.Plugins.Extensions.Data/src/Storage/LWStorageDescriptor.cs
@@ -103,7 +103,8 @@ namespace VNLib.Plugins.Extensions.Data.Storage
{
//Calc and alloc decode buffer
int bufferSize = (int)(Entry.Data.Length * 1.75);
- using UnsafeMemoryHandle<byte> decodeBuffer = Memory.UnsafeAlloc<byte>(bufferSize);
+
+ using UnsafeMemoryHandle<byte> decodeBuffer = MemoryUtil.UnsafeAlloc<byte>(bufferSize);
//Decode and deserialize the data
return BrotliDecoder.TryDecompress(Entry.Data, decodeBuffer, out int written)
diff --git a/lib/VNLib.Plugins.Extensions.Data/src/Storage/LWStorageManager.cs b/lib/VNLib.Plugins.Extensions.Data/src/Storage/LWStorageManager.cs
index 4120a8b..8a34ec4 100644
--- a/lib/VNLib.Plugins.Extensions.Data/src/Storage/LWStorageManager.cs
+++ b/lib/VNLib.Plugins.Extensions.Data/src/Storage/LWStorageManager.cs
@@ -265,7 +265,7 @@ namespace VNLib.Plugins.Extensions.Data.Storage
//Convert stream to vnstream
VnMemoryStream vms = (VnMemoryStream)data;
- using (IMemoryHandle<byte> encBuffer = Memory.SafeAlloc<byte>((int)vms.Length))
+ using (IMemoryHandle<byte> encBuffer = MemoryUtil.SafeAlloc<byte>((int)vms.Length))
{
//try to compress
if(!BrotliEncoder.TryCompress(vms.AsSpan(), encBuffer.Span, out int compressed))
diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/AssemblyLoader.cs b/lib/VNLib.Plugins.Extensions.Loading/src/AssemblyLoader.cs
index f3e03dd..2827587 100644
--- a/lib/VNLib.Plugins.Extensions.Loading/src/AssemblyLoader.cs
+++ b/lib/VNLib.Plugins.Extensions.Loading/src/AssemblyLoader.cs
@@ -153,7 +153,7 @@ namespace VNLib.Plugins.Extensions.Loading
conf.PreferSharedTypes = true;
//Share utils asm
- conf.SharedAssemblies.Add(typeof(Utils.Memory.Memory).Assembly.GetName());
+ conf.SharedAssemblies.Add(typeof(Utils.Memory.MemoryUtil).Assembly.GetName());
});
return new(loader, in unloadToken);
diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs b/lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs
index fc88612..46d9585 100644
--- a/lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs
+++ b/lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs
@@ -35,6 +35,7 @@ using VNLib.Utils;
using VNLib.Utils.Logging;
using VNLib.Utils.Extensions;
using VNLib.Plugins.Essentials.Accounts;
+using VNLib.Utils.Memory;
namespace VNLib.Plugins.Extensions.Loading
{
@@ -112,18 +113,12 @@ namespace VNLib.Plugins.Extensions.Loading
private static PasswordHashing LoadPasswords(PluginBase plugin)
{
PasswordHashing Passwords;
- //Get the global password system secret (pepper)
- byte[] pepper = plugin.TryGetSecretAsync(PASSWORD_HASHING_KEY)
- .ToBase64Bytes().Result ?? throw new KeyNotFoundException($"Missing required key '{PASSWORD_HASHING_KEY}' in secrets");
- ERRNO cb(Span<byte> buffer)
- {
- //No longer valid peper if plugin is unloaded as its set to zero, so we need to protect it
- plugin.ThrowIfUnloaded();
+ //Create new session provider
+ SecretProvider secrets = new();
- pepper.CopyTo(buffer);
- return pepper.Length;
- }
+ //Load the secret in the background
+ secrets.LoadSecret(plugin);
//See hashing params are defined
IReadOnlyDictionary<string, JsonElement>? hashingArgs = plugin.TryGetConfig(PASSWORD_HASHING_KEY);
@@ -136,20 +131,13 @@ namespace VNLib.Plugins.Extensions.Loading
uint memoryCost = hashingArgs["memory_cost"].GetUInt32();
uint parallelism = hashingArgs["parallelism"].GetUInt32();
//Load passwords
- Passwords = new(cb, pepper.Length, (int)saltLen, timeCost, memoryCost, parallelism, hashLen);
+ Passwords = new(secrets, (int)saltLen, timeCost, memoryCost, parallelism, hashLen);
}
else
{
//Init default password hashing
- Passwords = new(cb, pepper.Length);
+ Passwords = new(secrets);
}
-
- //Register event to cleanup the password class
- _ = plugin.RegisterForUnload(() =>
- {
- //Zero the pepper
- CryptographicOperations.ZeroMemory(pepper);
- });
//return
return Passwords;
}
@@ -184,7 +172,7 @@ namespace VNLib.Plugins.Extensions.Loading
* assembly, otherwise search all plugins directories
*/
- string? assetDir = config["assets"].GetString();
+ string? assetDir = config.GetPropString("assets");
assetDir ??= config["path"].GetString();
/*
@@ -346,5 +334,56 @@ namespace VNLib.Plugins.Extensions.Loading
return lazyFactory;
}
}
+
+ private sealed class SecretProvider : ISecretProvider
+ {
+ private byte[]? _pepper;
+ private Exception? _error;
+
+ ///<inheritdoc/>
+ public int BufferSize => _error != null ? throw _error : _pepper?.Length ?? 0;
+
+ public ERRNO GetSecret(Span<byte> buffer)
+ {
+ if(_error != null)
+ {
+ throw _error;
+ }
+ //Coppy pepper to buffer
+ _pepper.CopyTo(buffer);
+ //Return pepper length
+ return _pepper!.Length;
+ }
+
+ public void LoadSecret(PluginBase pbase)
+ {
+ _ = pbase.DeferTask(() => LoadSecretInternal(pbase));
+ }
+
+ private async Task LoadSecretInternal(PluginBase pbase)
+ {
+ try
+ {
+ //Get the pepper from secret storage
+ _pepper = await pbase.TryGetSecretAsync(PASSWORD_HASHING_KEY).ToBase64Bytes();
+
+ //Regsiter cleanup
+ _ = pbase.RegisterForUnload(Clear);
+ }
+ catch(Exception ex)
+ {
+ //Store exception for re-propagation
+ _error = ex;
+ }
+ }
+
+ public void Clear()
+ {
+ //Clear the pepper if set
+ MemoryUtil.InitializeBlock(_pepper.AsSpan());
+ }
+
+
+ }
}
}
diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/PrivateKey.cs b/lib/VNLib.Plugins.Extensions.Loading/src/PrivateKey.cs
index b854419..2e5fb7f 100644
--- a/lib/VNLib.Plugins.Extensions.Loading/src/PrivateKey.cs
+++ b/lib/VNLib.Plugins.Extensions.Loading/src/PrivateKey.cs
@@ -49,14 +49,19 @@ namespace VNLib.Plugins.Extensions.Loading
public ECDsa GetECDsa()
{
//Alloc buffer
- using IMemoryHandle<byte> buffer = Memory.SafeAlloc<byte>(_utf8RawData.Length);
+ using IMemoryHandle<byte> buffer = MemoryUtil.SafeAlloc<byte>(_utf8RawData.Length);
+
//Get base64 bytes from utf8
ERRNO count = VnEncoding.Base64UrlDecode(_utf8RawData, buffer.Span);
+
//Parse the private key
ECDsa alg = ECDsa.Create();
+
alg.ImportPkcs8PrivateKey(buffer.Span[..(int)count], out _);
+
//Wipe the buffer
- Memory.InitializeBlock(buffer.Span);
+ MemoryUtil.InitializeBlock(buffer.Span);
+
return alg;
}
@@ -69,14 +74,19 @@ namespace VNLib.Plugins.Extensions.Loading
public RSA GetRSA()
{
//Alloc buffer
- using IMemoryHandle<byte> buffer = Memory.SafeAlloc<byte>(_utf8RawData.Length);
+ using IMemoryHandle<byte> buffer = MemoryUtil.SafeAlloc<byte>(_utf8RawData.Length);
+
//Get base64 bytes from utf8
ERRNO count = VnEncoding.Base64UrlDecode(_utf8RawData, buffer.Span);
+
//Parse the private key
RSA alg = RSA.Create();
+
alg.ImportPkcs8PrivateKey(buffer.Span[..(int)count], out _);
+
//Wipe the buffer
- Memory.InitializeBlock(buffer.Span);
+ MemoryUtil.InitializeBlock(buffer.Span);
+
return alg;
}
@@ -84,19 +94,22 @@ namespace VNLib.Plugins.Extensions.Loading
{
//Alloc and get utf8
byte[] buffer = new byte[secret.Result.Length];
+
int count = Encoding.UTF8.GetBytes(secret.Result, buffer);
+
//Verify length
if(count != buffer.Length)
{
throw new FormatException("UTF8 deocde failed");
}
+
//Store
_utf8RawData = buffer;
}
protected override void Free()
{
- Memory.InitializeBlock(_utf8RawData.AsSpan());
+ MemoryUtil.InitializeBlock(_utf8RawData.AsSpan());
}
}
}
diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/SecretResult.cs b/lib/VNLib.Plugins.Extensions.Loading/src/SecretResult.cs
index 817ef7a..6c1c5f8 100644
--- a/lib/VNLib.Plugins.Extensions.Loading/src/SecretResult.cs
+++ b/lib/VNLib.Plugins.Extensions.Loading/src/SecretResult.cs
@@ -48,13 +48,13 @@ namespace VNLib.Plugins.Extensions.Loading
///<inheritdoc/>
protected override void Free()
{
- Memory.InitializeBlock(_secretChars.AsSpan());
+ MemoryUtil.InitializeBlock(_secretChars.AsSpan());
}
internal static SecretResult ToSecret(string? result)
{
SecretResult res = new(result.AsSpan());
- Memory.UnsafeZeroMemory<char>(result);
+ MemoryUtil.UnsafeZeroMemory<char>(result);
return res;
}
}
diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/VaultSecrets.cs b/lib/VNLib.Plugins.Extensions.Loading/src/VaultSecrets.cs
index 2b6bfd8..d3bdf42 100644
--- a/lib/VNLib.Plugins.Extensions.Loading/src/VaultSecrets.cs
+++ b/lib/VNLib.Plugins.Extensions.Loading/src/VaultSecrets.cs
@@ -328,20 +328,21 @@ namespace VNLib.Plugins.Extensions.Loading
_ = secret ?? throw new ArgumentNullException(nameof(secret));
//Temp buffer
- using UnsafeMemoryHandle<byte> buffer = Memory.UnsafeAlloc<byte>(secret.Result.Length);
+ using UnsafeMemoryHandle<byte> buffer = MemoryUtil.UnsafeAlloc<byte>(secret.Result.Length);
//Get base64
- if(Convert.TryFromBase64Chars(secret.Result, buffer, out int count))
+ if(!Convert.TryFromBase64Chars(secret.Result, buffer, out int count))
{
- //Copy to array
- byte[] value = buffer.Span[..count].ToArray();
- //Clear block before returning
- Memory.InitializeBlock<byte>(buffer);
-
- return value;
+ throw new InternalBufferTooSmallException("internal buffer too small");
}
- throw new InternalBufferTooSmallException("internal buffer too small");
+ //Copy to array
+ byte[] value = buffer.Span[..count].ToArray();
+
+ //Clear block before returning
+ MemoryUtil.InitializeBlock<byte>(buffer);
+
+ return value;
}
/// <summary>
@@ -354,7 +355,9 @@ namespace VNLib.Plugins.Extensions.Loading
public static async Task<byte[]?> ToBase64Bytes(this Task<SecretResult?> secret)
{
_ = secret ?? throw new ArgumentNullException(nameof(secret));
+
using SecretResult? sec = await secret.ConfigureAwait(false);
+
return sec?.GetFromBase64();
}
@@ -378,12 +381,16 @@ namespace VNLib.Plugins.Extensions.Loading
public static JsonDocument GetJsonDocument(this SecretResult secret)
{
_ = secret ?? throw new ArgumentNullException(nameof(secret));
+
//Alloc buffer, utf8 so 1 byte per char
- using IMemoryHandle<byte> buffer = Memory.SafeAlloc<byte>(secret.Result.Length);
+ using IMemoryHandle<byte> buffer = MemoryUtil.SafeAlloc<byte>(secret.Result.Length);
+
//Get utf8 bytes
int count = Encoding.UTF8.GetBytes(secret.Result, buffer.Span);
+
//Reader and parse
Utf8JsonReader reader = new(buffer.Span[..count]);
+
return JsonDocument.ParseValue(ref reader);
}
@@ -396,10 +403,13 @@ namespace VNLib.Plugins.Extensions.Loading
public static PublicKey GetPublicKey(this SecretResult secret)
{
_ = secret ?? throw new ArgumentNullException(nameof(secret));
+
//Alloc buffer, base64 is larger than binary value so char len is large enough
- using IMemoryHandle<byte> buffer = Memory.SafeAlloc<byte>(secret.Result.Length);
+ using IMemoryHandle<byte> buffer = MemoryUtil.SafeAlloc<byte>(secret.Result.Length);
+
//Get base64 bytes
ERRNO count = VnEncoding.TryFromBase64Chars(secret.Result, buffer.Span);
+
//Parse the SPKI from base64
return PublicKey.CreateFromSubjectPublicKeyInfo(buffer.Span[..(int)count], out _);
}
@@ -429,10 +439,13 @@ namespace VNLib.Plugins.Extensions.Loading
public static ReadOnlyJsonWebKey GetJsonWebKey(this SecretResult secret)
{
_ = secret ?? throw new ArgumentNullException(nameof(secret));
+
//Alloc buffer, utf8 so 1 byte per char
- using IMemoryHandle<byte> buffer = Memory.SafeAlloc<byte>(secret.Result.Length);
+ using IMemoryHandle<byte> buffer = MemoryUtil.SafeAlloc<byte>(secret.Result.Length);
+
//Get utf8 bytes
int count = Encoding.UTF8.GetBytes(secret.Result, buffer.Span);
+
return new ReadOnlyJsonWebKey(buffer.Span[..count]);
}
@@ -446,7 +459,9 @@ namespace VNLib.Plugins.Extensions.Loading
public static async Task<ReadOnlyJsonWebKey?> ToJsonWebKey(this Task<SecretResult?> secret)
{
_ = secret ?? throw new ArgumentNullException(nameof(secret));
+
using SecretResult? sec = await secret.ConfigureAwait(false);
+
return sec?.GetJsonWebKey();
}
@@ -464,7 +479,9 @@ namespace VNLib.Plugins.Extensions.Loading
public static async Task<ReadOnlyJsonWebKey> ToJsonWebKey(this Task<SecretResult?> secret, bool required)
{
_ = secret ?? throw new ArgumentNullException(nameof(secret));
+
using SecretResult? sec = await secret.ConfigureAwait(false);
+
//If required is true and result is null, raise an exception
return required && sec == null ? throw new KeyNotFoundException("A required secret was missing") : (sec?.GetJsonWebKey()!);
}