From 9c7b564911080ccd5cbbb9851a0757b05e1e9047 Mon Sep 17 00:00:00 2001 From: vnugent Date: Tue, 19 Mar 2024 21:54:49 -0400 Subject: refactor: JWK overhaul & add length getter to FileUpload --- .../src/IdentityUtility/JsonWebKey.cs | 38 ++++++- .../src/IdentityUtility/ReadOnlyJsonWebKey.cs | 120 ++++++++++++--------- 2 files changed, 106 insertions(+), 52 deletions(-) (limited to 'lib/Hashing.Portable') 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 } /// - /// Gets the RSA private key algorithm from the supplied Json Web Key + /// Gets the RSA private key algorithm from the supplied Json Web Key /// /// /// The algorithm if found, or null if the element does not contain private key @@ -303,7 +303,23 @@ namespace VNLib.Hashing.IdentityUtility return rSAParameters.HasValue ? RSA.Create(rSAParameters.Value) : null; } - private static RSAParameters? GetRsaParameters(in TKey jwk, bool includePrivateKey) where TKey : IJsonWebKey + /// + /// Gets the RSA key parameters from the current Json Web Key + /// > + /// + /// A value that indicates that a private key should be parsed and included in the parameters + /// A nullable structure that contains the parsed keys, or null if required properties were empty + public static RSAParameters? GetRsaParameters(this ReadOnlyJsonWebKey jwk, bool includePrivateKey) + => GetRsaParameters(in jwk, includePrivateKey); + + /// + /// Gets the RSA key parameters from the current Json Web Key + /// + /// + /// + /// A value that indicates that a private key should be parsed and included in the parameters + /// A nullable structure that contains the parsed keys, or null if required properties were empty + public static RSAParameters? GetRsaParameters(in TKey jwk, bool includePrivateKey) where TKey : IJsonWebKey { //Get the RSA public key credentials ReadOnlySpan 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(in TKey jwk, bool includePrivate) where TKey : IJsonWebKey + /// + /// Gets the EC key parameters from the current Json Web Key + /// + /// + /// A value that inidcates if private key parameters should be parsed and included + /// The parsed key parameter structure, or null if the key parameters were empty or could not be parsed + public static ECParameters? GetECParameters(this ReadOnlyJsonWebKey jwk, bool includePrivate) => GetECParameters(in jwk, includePrivate); + + /// + /// Gets the EC key parameters from the current Json Web Key + /// + /// + /// + /// A value that inidcates if private key parameters should be parsed and included + /// The parsed key parameter structure, or null if the key parameters were empty or could not be parsed + public static ECParameters? GetECParameters(in TKey jwk, bool includePrivate) where TKey : IJsonWebKey { //Get the RSA public key credentials ReadOnlySpan 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. /// - public sealed class ReadOnlyJsonWebKey : VnDisposeable, IJsonWebKey + public sealed class ReadOnlyJsonWebKey : IJsonWebKey { - private readonly JsonElement _jwk; - private readonly JsonDocument? _doc; + private readonly FrozenDictionary _properties; /// - /// Creates a new instance of from a . - /// This will call on the element and store an internal copy + /// Creates a new instance of from a dictionary of + /// JWK string properties /// - /// The to create the from - public ReadOnlyJsonWebKey(ref readonly JsonElement keyElement) + /// The frozen dictionary instance of parsed JWK properties + public ReadOnlyJsonWebKey(FrozenDictionary 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() @@ -70,6 +66,21 @@ namespace VNLib.Hashing.IdentityUtility }; } + /// + /// Creates a new instance of from a . + /// This will call on the element and store an internal copy + /// + /// The to create the from + 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() + ) + { } + /// /// Creates a new instance of from a raw utf8 encoded json /// binary sequence @@ -77,52 +88,60 @@ namespace VNLib.Hashing.IdentityUtility /// The utf8 encoded json binary sequence /// /// - public ReadOnlyJsonWebKey(ReadOnlySpan rawValue) + public static ReadOnlyJsonWebKey FromUtf8Bytes(ReadOnlySpan 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() - { - { "alg" , Algorithm }, - { "typ" , "JWT" }, - }; + /// + /// Creates a new instance of from a raw utf8 encoded json + /// memory segment + /// + /// The utf8 encoded json binary sequence + /// The readonly JWK object + /// + /// + public static ReadOnlyJsonWebKey FromUtf8Bytes(ReadOnlyMemory 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, - }; + /// + /// Creates a new instance of from a json string + /// + /// The json encoded string to recover the JWK from + /// + public static ReadOnlyJsonWebKey FromJsonString(string jsonString) + { + using JsonDocument doc = JsonDocument.Parse(jsonString); + JsonElement root = doc.RootElement; + return new ReadOnlyJsonWebKey(ref root); } /// /// The key identifier /// - public string? KeyId { get; } + public string? KeyId => _properties.GetValueOrDefault("kid"); + /// /// The key type /// - public string? KeyType { get; } + public string? KeyType => _properties.GetValueOrDefault("kty"); + /// /// The key algorithm /// - public string? Algorithm { get; } + public string? Algorithm => _properties.GetValueOrDefault("alg"); + /// /// The key "use" value /// - public string? Use { get; } + public string? Use => _properties.GetValueOrDefault("use"); /// /// Returns the JWT header that matches this key @@ -133,12 +152,17 @@ namespace VNLib.Hashing.IdentityUtility public JwkKeyUsage KeyUse { get; } /// - public string? GetKeyProperty(string propertyName) => _jwk.GetPropString(propertyName); + public string? GetKeyProperty(string propertyName) => _properties.GetValueOrDefault(propertyName); - /// - protected override void Free() + /// + /// Attemts to erase all property values from memory by securely writing over them with zeros + /// + public void EraseValues() { - _doc?.Dispose(); + foreach(string? value in _properties.Values) + { + PrivateStringManager.EraseString(value); + } } } -- cgit