aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Hashing.Portable/src/IdentityUtility/JsonWebKey.cs38
-rw-r--r--lib/Hashing.Portable/src/IdentityUtility/ReadOnlyJsonWebKey.cs120
-rw-r--r--lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs6
-rw-r--r--lib/Net.Http/src/FileUpload.cs7
-rw-r--r--lib/Utils/src/ArgumentList.cs9
5 files changed, 122 insertions, 58 deletions
diff --git a/lib/Hashing.Portable/src/IdentityUtility/JsonWebKey.cs b/lib/Hashing.Portable/src/IdentityUtility/JsonWebKey.cs
index 65f0837..a237db0 100644
--- a/lib/Hashing.Portable/src/IdentityUtility/JsonWebKey.cs
+++ b/lib/Hashing.Portable/src/IdentityUtility/JsonWebKey.cs
@@ -292,7 +292,7 @@ namespace VNLib.Hashing.IdentityUtility
}
/// <summary>
- /// Gets the RSA private key algorithm from the supplied Json Web Key <see cref="JsonElement"/>
+ /// Gets the RSA private key algorithm from the supplied Json Web Key
/// </summary>
/// <param name="jwk"></param>
/// <returns>The <see cref="RSA"/> algorithm if found, or null if the element does not contain private key</returns>
@@ -303,7 +303,23 @@ namespace VNLib.Hashing.IdentityUtility
return rSAParameters.HasValue ? RSA.Create(rSAParameters.Value) : null;
}
- private static RSAParameters? GetRsaParameters<TKey>(in TKey jwk, bool includePrivateKey) where TKey : IJsonWebKey
+ /// <summary>
+ /// Gets the RSA key parameters from the current Json Web Key
+ /// </summary>>
+ /// <param name="jwk"></param>
+ /// <param name="includePrivateKey">A value that indicates that a private key should be parsed and included in the parameters</param>
+ /// <returns>A nullable structure that contains the parsed keys, or null if required properties were empty</returns>
+ public static RSAParameters? GetRsaParameters(this ReadOnlyJsonWebKey jwk, bool includePrivateKey)
+ => GetRsaParameters(in jwk, includePrivateKey);
+
+ /// <summary>
+ /// Gets the RSA key parameters from the current Json Web Key
+ /// </summary>
+ /// <typeparam name="TKey"></typeparam>
+ /// <param name="jwk"></param>
+ /// <param name="includePrivateKey">A value that indicates that a private key should be parsed and included in the parameters</param>
+ /// <returns>A nullable structure that contains the parsed keys, or null if required properties were empty</returns>
+ public static RSAParameters? GetRsaParameters<TKey>(in TKey jwk, bool includePrivateKey) where TKey : IJsonWebKey
{
//Get the RSA public key credentials
ReadOnlySpan<char> e = jwk.GetKeyProperty("e");
@@ -372,9 +388,23 @@ namespace VNLib.Hashing.IdentityUtility
//Return new alg
return ecParams.HasValue ? ECDsa.Create(ecParams.Value) : null;
}
-
- private static ECParameters? GetECParameters<TKey>(in TKey jwk, bool includePrivate) where TKey : IJsonWebKey
+ /// <summary>
+ /// Gets the EC key parameters from the current Json Web Key
+ /// </summary>
+ /// <param name="jwk"></param>
+ /// <param name="includePrivate">A value that inidcates if private key parameters should be parsed and included </param>
+ /// <returns>The parsed key parameter structure, or null if the key parameters were empty or could not be parsed</returns>
+ public static ECParameters? GetECParameters(this ReadOnlyJsonWebKey jwk, bool includePrivate) => GetECParameters(in jwk, includePrivate);
+
+ /// <summary>
+ /// Gets the EC key parameters from the current Json Web Key
+ /// </summary>
+ /// <typeparam name="TKey"></typeparam>
+ /// <param name="jwk"></param>
+ /// <param name="includePrivate">A value that inidcates if private key parameters should be parsed and included </param>
+ /// <returns>The parsed key parameter structure, or null if the key parameters were empty or could not be parsed</returns>
+ public static ECParameters? GetECParameters<TKey>(in TKey jwk, bool includePrivate) where TKey : IJsonWebKey
{
//Get the RSA public key credentials
ReadOnlySpan<char> x = jwk.GetKeyProperty("x");
diff --git a/lib/Hashing.Portable/src/IdentityUtility/ReadOnlyJsonWebKey.cs b/lib/Hashing.Portable/src/IdentityUtility/ReadOnlyJsonWebKey.cs
index 009d6bf..c97a023 100644
--- a/lib/Hashing.Portable/src/IdentityUtility/ReadOnlyJsonWebKey.cs
+++ b/lib/Hashing.Portable/src/IdentityUtility/ReadOnlyJsonWebKey.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Hashing.Portable
@@ -23,11 +23,12 @@
*/
using System;
+using System.Linq;
using System.Text.Json;
using System.Collections.Generic;
+using System.Collections.Frozen;
-using VNLib.Utils;
-using VNLib.Utils.Extensions;
+using VNLib.Utils.Memory;
namespace VNLib.Hashing.IdentityUtility
{
@@ -35,24 +36,19 @@ namespace VNLib.Hashing.IdentityUtility
/// A readonly Json Web Key (JWK) data structure that may be used for signing
/// or verifying messages.
/// </summary>
- public sealed class ReadOnlyJsonWebKey : VnDisposeable, IJsonWebKey
+ public sealed class ReadOnlyJsonWebKey : IJsonWebKey
{
- private readonly JsonElement _jwk;
- private readonly JsonDocument? _doc;
+ private readonly FrozenDictionary<string, string?> _properties;
/// <summary>
- /// Creates a new instance of <see cref="ReadOnlyJsonWebKey"/> from a <see cref="JsonElement"/>.
- /// This will call <see cref="JsonElement.Clone"/> on the element and store an internal copy
+ /// Creates a new instance of <see cref="ReadOnlyJsonWebKey"/> from a dictionary of
+ /// JWK string properties
/// </summary>
- /// <param name="keyElement">The <see cref="JsonElement"/> to create the <see cref="ReadOnlyJsonWebKey"/> from</param>
- public ReadOnlyJsonWebKey(ref readonly JsonElement keyElement)
+ /// <param name="properties">The frozen dictionary instance of parsed JWK properties</param>
+ public ReadOnlyJsonWebKey(FrozenDictionary<string, string?> properties)
{
- _jwk = keyElement.Clone();
- //Set initial values
- KeyId = _jwk.GetPropString("kid");
- KeyType = _jwk.GetPropString("kty");
- Algorithm = _jwk.GetPropString("alg");
- Use = _jwk.GetPropString("use");
+ ArgumentNullException.ThrowIfNull(properties);
+ _properties = properties;
//Create a JWT header from the values
JwtHeader = new Dictionary<string, string?>()
@@ -71,58 +67,81 @@ namespace VNLib.Hashing.IdentityUtility
}
/// <summary>
+ /// Creates a new instance of <see cref="ReadOnlyJsonWebKey"/> from a <see cref="JsonElement"/>.
+ /// This will call <see cref="JsonElement.Clone"/> on the element and store an internal copy
+ /// </summary>
+ /// <param name="keyElement">The <see cref="JsonElement"/> to create the <see cref="ReadOnlyJsonWebKey"/> from</param>
+ public ReadOnlyJsonWebKey(ref readonly JsonElement keyElement)
+ :this(
+ //Get only top-level string properties and store them in a dictionary
+ keyElement.EnumerateObject()
+ .Where(static k => k.Value.ValueKind == JsonValueKind.String)
+ .ToDictionary(static k => k.Name, v => v.Value.GetString(), StringComparer.OrdinalIgnoreCase)
+ .ToFrozenDictionary()
+ )
+ { }
+
+ /// <summary>
/// Creates a new instance of <see cref="ReadOnlyJsonWebKey"/> from a raw utf8 encoded json
/// binary sequence
/// </summary>
/// <param name="rawValue">The utf8 encoded json binary sequence</param>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="JsonException"></exception>
- public ReadOnlyJsonWebKey(ReadOnlySpan<byte> rawValue)
+ public static ReadOnlyJsonWebKey FromUtf8Bytes(ReadOnlySpan<byte> rawValue)
{
- //Pare the raw value
Utf8JsonReader reader = new (rawValue);
- _doc = JsonDocument.ParseValue(ref reader);
- //store element
- _jwk = _doc.RootElement;
-
- //Set initial values
- KeyId = _jwk.GetPropString("kid");
- KeyType = _jwk.GetPropString("kty");
- Algorithm = _jwk.GetPropString("alg");
- Use = _jwk.GetPropString("use");
+ using JsonDocument doc = JsonDocument.ParseValue(ref reader);
+ JsonElement root = doc.RootElement;
+ return new ReadOnlyJsonWebKey(ref root);
+ }
- //Create a JWT header from the values
- JwtHeader = new Dictionary<string, string?>()
- {
- { "alg" , Algorithm },
- { "typ" , "JWT" },
- };
+ /// <summary>
+ /// Creates a new instance of <see cref="ReadOnlyJsonWebKey"/> from a raw utf8 encoded json
+ /// memory segment
+ /// </summary>
+ /// <param name="rawValue">The utf8 encoded json binary sequence</param>
+ /// <returns>The readonly JWK object</returns>
+ /// <exception cref="ArgumentException"></exception>
+ /// <exception cref="JsonException"></exception>
+ public static ReadOnlyJsonWebKey FromUtf8Bytes(ReadOnlyMemory<byte> rawValue)
+ {
+ using JsonDocument doc = JsonDocument.Parse(rawValue);
+ JsonElement root = doc.RootElement;
+ return new ReadOnlyJsonWebKey(ref root);
+ }
- //Configure key usage
- KeyUse = (Use?.ToLower(null)) switch
- {
- "sig" => JwkKeyUsage.Signature,
- "enc" => JwkKeyUsage.Encryption,
- _ => JwkKeyUsage.None,
- };
+ /// <summary>
+ /// Creates a new instance of <see cref="ReadOnlyJsonWebKey"/> from a json string
+ /// </summary>
+ /// <param name="jsonString">The json encoded string to recover the JWK from</param>
+ /// <returns></returns>
+ public static ReadOnlyJsonWebKey FromJsonString(string jsonString)
+ {
+ using JsonDocument doc = JsonDocument.Parse(jsonString);
+ JsonElement root = doc.RootElement;
+ return new ReadOnlyJsonWebKey(ref root);
}
/// <summary>
/// The key identifier
/// </summary>
- public string? KeyId { get; }
+ public string? KeyId => _properties.GetValueOrDefault("kid");
+
/// <summary>
/// The key type
/// </summary>
- public string? KeyType { get; }
+ public string? KeyType => _properties.GetValueOrDefault("kty");
+
/// <summary>
/// The key algorithm
/// </summary>
- public string? Algorithm { get; }
+ public string? Algorithm => _properties.GetValueOrDefault("alg");
+
/// <summary>
/// The key "use" value
/// </summary>
- public string? Use { get; }
+ public string? Use => _properties.GetValueOrDefault("use");
/// <summary>
/// Returns the JWT header that matches this key
@@ -133,12 +152,17 @@ namespace VNLib.Hashing.IdentityUtility
public JwkKeyUsage KeyUse { get; }
///<inheritdoc/>
- public string? GetKeyProperty(string propertyName) => _jwk.GetPropString(propertyName);
+ public string? GetKeyProperty(string propertyName) => _properties.GetValueOrDefault(propertyName);
- ///<inheritdoc/>
- protected override void Free()
+ /// <summary>
+ /// Attemts to erase all property values from memory by securely writing over them with zeros
+ /// </summary>
+ public void EraseValues()
{
- _doc?.Dispose();
+ foreach(string? value in _properties.Values)
+ {
+ PrivateStringManager.EraseString(value);
+ }
}
}
diff --git a/lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs b/lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs
index c373310..86535c3 100644
--- a/lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs
+++ b/lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Http
@@ -176,7 +176,7 @@ namespace VNLib.Net.Http.Core
/// <param name="lineBuf">The buffer read data from the transport with</param>
/// <returns>0 if the request line was successfully parsed, a status code if the request could not be processed</returns>
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
- public static HttpStatusCode Http1ParseHeaders(this HttpRequest Request, ref Http1ParseState parseState, ref TransportReader reader, in HttpConfig Config, Span<char> lineBuf)
+ public static HttpStatusCode Http1ParseHeaders(this HttpRequest Request, ref Http1ParseState parseState, ref TransportReader reader, ref readonly HttpConfig Config, Span<char> lineBuf)
{
/*
* Evil mutable struct, get a local mutable reference to the request's
@@ -534,7 +534,7 @@ namespace VNLib.Net.Http.Core
/// <param name="reader">The <see cref="VnStreamReader"/> to read lines from the transport</param>
/// <returns>0 if the request line was successfully parsed, a status code if the request could not be processed</returns>
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
- public static HttpStatusCode Http1PrepareEntityBody(this HttpRequest Request, ref Http1ParseState parseState, ref TransportReader reader, in HttpConfig Config)
+ public static HttpStatusCode Http1PrepareEntityBody(this HttpRequest Request, ref Http1ParseState parseState, ref TransportReader reader, ref readonly HttpConfig Config)
{
/*
* Evil mutable struct, get a local mutable reference to the request's
diff --git a/lib/Net.Http/src/FileUpload.cs b/lib/Net.Http/src/FileUpload.cs
index 794c623..d3104fd 100644
--- a/lib/Net.Http/src/FileUpload.cs
+++ b/lib/Net.Http/src/FileUpload.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Http
@@ -45,6 +45,11 @@ namespace VNLib.Net.Http
public readonly record struct FileUpload(Stream FileData, bool DisposeStream, ContentType ContentType, string? FileName)
{
/// <summary>
+ /// Gets the length of the <see cref="FileData"/> stream
+ /// </summary>
+ public long Length => FileData.Length;
+
+ /// <summary>
/// Disposes the stream if the handle is owned
/// </summary>
public readonly void Free()
diff --git a/lib/Utils/src/ArgumentList.cs b/lib/Utils/src/ArgumentList.cs
index 235e62c..c02ebee 100644
--- a/lib/Utils/src/ArgumentList.cs
+++ b/lib/Utils/src/ArgumentList.cs
@@ -24,6 +24,7 @@
using System;
using System.Linq;
+using System.Collections;
using System.Collections.Generic;
namespace VNLib.Utils
@@ -31,7 +32,7 @@ namespace VNLib.Utils
/// <summary>
/// Provides methods for parsing an argument list
/// </summary>
- public class ArgumentList : IIndexable<int, string>
+ public class ArgumentList : IIndexable<int, string>, IEnumerable<string>
{
private readonly List<string> _args;
@@ -96,6 +97,10 @@ namespace VNLib.Utils
return index == -1 || index + 1 >= _args.Count ? null : this[index + 1];
}
-
+ ///<inheritdoc/>
+ public IEnumerator<string> GetEnumerator() => _args.GetEnumerator();
+
+ ///<inheritdoc/>
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
} \ No newline at end of file