using System.Buffers; using System.Buffers.Text; using System.Text.Json; using System.Text.Json.Serialization; namespace IdentityShroud.Core.Messages; // https://www.rfc-editor.org/rfc/rfc7517.html public class JsonWebKey { [JsonPropertyName("kty")] public string KeyType { get; set; } = "RSA"; // Common values sig(nature) enc(ryption) [JsonPropertyName("use")] public string? Use { get; set; } = "sig"; // "sig" for signature, "enc" for encryption // Per standard this field is optional, commented out for now as it seems not // have any good use in an identity server. Anyone validating tokens should use // the algorithm specified in the header of the token. // [JsonPropertyName("alg")] // public string? Algorithm { get; set; } = "RS256"; [JsonPropertyName("kid")] public required string KeyId { get; set; } // RSA Public Key Components [JsonPropertyName("n")] public string? Modulus { get; set; } [JsonPropertyName("e")] public string? Exponent { get; set; } // ECdsa public string? Curve { get; set; } [JsonConverter(typeof(Base64UrlConverter))] public byte[]? X { get; set; } [JsonConverter(typeof(Base64UrlConverter))] public byte[]? Y { get; set; } // Optional fields // [JsonPropertyName("x5c")] // [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] // public List? X509CertificateChain { get; set; } // // [JsonPropertyName("x5t")] // [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] // public string? X509CertificateThumbprint { get; set; } } public class Base64UrlConverter : JsonConverter { public override byte[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // GetValueSpan gives you the raw UTF-8 bytes of the JSON string value if (reader.HasValueSequence) { var valueSequence = reader.ValueSequence.ToArray(); return Base64Url.DecodeFromUtf8(valueSequence); } return Base64Url.DecodeFromUtf8(reader.ValueSpan); } public override void Write(Utf8JsonWriter writer, byte[] value, JsonSerializerOptions options) { int encodedLength = Base64Url.GetEncodedLength(value.Length); Span buffer = encodedLength <= 256 ? stackalloc byte[encodedLength] : new byte[encodedLength]; Base64Url.EncodeToUtf8(value, buffer); writer.WriteStringValue(buffer); } }