diff --git a/Demo/TestController.cs b/Demo/TestController.cs
index eca9ea6b..045962bb 100644
--- a/Demo/TestController.cs
+++ b/Demo/TestController.cs
@@ -1,5 +1,7 @@
-using System.Text;
+using System.Buffers.Text;
+using System.Text;
using System.Text.Json;
+
using Fido2NetLib;
using Fido2NetLib.Development;
using Fido2NetLib.Objects;
@@ -42,7 +44,7 @@ public OkObjectResult MakeCredentialOptionsTest([FromBody] TEST_MakeCredentialPa
try
{
- username = Base64Url.Decode(opts.Username);
+ username = Base64Url.DecodeFromChars(opts.Username);
}
catch (FormatException)
{
diff --git a/Src/Fido2.Models/Base64Url.cs b/Src/Fido2.Models/Base64Url.cs
deleted file mode 100644
index 2431d0eb..00000000
--- a/Src/Fido2.Models/Base64Url.cs
+++ /dev/null
@@ -1,158 +0,0 @@
-using System.Buffers;
-using System.Buffers.Text;
-
-namespace Fido2NetLib;
-
-///
-/// Helper class to handle Base64Url. Based on Carbon.Jose source code.
-///
-public static class Base64Url
-{
- ///
- /// Converts arg data to a Base64Url encoded string.
- ///
- public static string Encode(ReadOnlySpan arg)
- {
- int base64Length = (int)(((long)arg.Length + 2) / 3 * 4);
-
- char[] pooledBuffer = ArrayPool.Shared.Rent(base64Length);
-
- Convert.TryToBase64Chars(arg, pooledBuffer, out int encodedLength);
-
- Span base64Url = pooledBuffer.AsSpan(0, encodedLength);
-
- for (int i = 0; i < base64Url.Length; i++)
- {
- ref char c = ref base64Url[i];
-
- switch (c)
- {
- case '+':
- c = '-';
- break;
- case '/':
- c = '_';
- break;
- }
- }
-
- int equalIndex = base64Url.IndexOf('=');
-
- if (equalIndex > -1) // remove trailing equal characters
- {
- base64Url = base64Url.Slice(0, equalIndex);
- }
-
- var result = new string(base64Url);
-
- ArrayPool.Shared.Return(pooledBuffer, clearArray: true);
-
- return result;
- }
-
- ///
- /// Decodes a Base64Url encoded string to its raw bytes.
- ///
- public static byte[] Decode(ReadOnlySpan text)
- {
- int padCharCount = (text.Length % 4) switch
- {
- 2 => 2,
- 3 => 1,
- _ => 0
- };
-
- int encodedLength = text.Length + padCharCount;
-
- char[] buffer = ArrayPool.Shared.Rent(encodedLength);
-
- text.CopyTo(buffer);
-
- for (int i = 0; i < text.Length; i++)
- {
- ref char c = ref buffer[i];
-
- switch (c)
- {
- case '-':
- c = '+';
- break;
- case '_':
- c = '/';
- break;
- }
- }
-
- if (padCharCount == 1)
- {
- buffer[encodedLength - 1] = '=';
- }
- else if (padCharCount == 2)
- {
- buffer[encodedLength - 1] = '=';
- buffer[encodedLength - 2] = '=';
- }
-
- var result = Convert.FromBase64CharArray(buffer, 0, encodedLength);
-
- ArrayPool.Shared.Return(buffer, true);
-
- return result;
- }
-
-
- ///
- /// Decodes a Base64Url encoded string to its raw bytes.
- ///
- public static byte[] DecodeUtf8(ReadOnlySpan text)
- {
- int padCharCount = (text.Length % 4) switch
- {
- 2 => 2,
- 3 => 1,
- _ => 0
- };
-
- int encodedLength = text.Length + padCharCount;
-
- byte[] buffer = ArrayPool.Shared.Rent(encodedLength);
-
- text.CopyTo(buffer);
-
- for (int i = 0; i < text.Length; i++)
- {
- ref byte c = ref buffer[i];
-
- switch ((char)c)
- {
- case '-':
- c = (byte)'+';
- break;
- case '_':
- c = (byte)'/';
- break;
- }
- }
-
- if (padCharCount == 1)
- {
- buffer[encodedLength - 1] = (byte)'=';
- }
- else if (padCharCount == 2)
- {
- buffer[encodedLength - 1] = (byte)'=';
- buffer[encodedLength - 2] = (byte)'=';
- }
-
- if (OperationStatus.Done != Base64.DecodeFromUtf8InPlace(buffer.AsSpan(0, encodedLength), out int decodedLength))
- {
- throw new FormatException("The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.");
- }
-
- var result = buffer.AsSpan(0, decodedLength).ToArray();
-
- ArrayPool.Shared.Return(buffer, true);
-
- return result;
- }
-}
diff --git a/Src/Fido2.Models/Converters/Base64UrlConverter.cs b/Src/Fido2.Models/Converters/Base64UrlConverter.cs
index 6ae5f52f..0c2d40ff 100644
--- a/Src/Fido2.Models/Converters/Base64UrlConverter.cs
+++ b/Src/Fido2.Models/Converters/Base64UrlConverter.cs
@@ -1,4 +1,8 @@
-using System.Text.Json;
+#nullable enable
+
+using System.Buffers;
+using System.Buffers.Text;
+using System.Text.Json;
using System.Text.Json.Serialization;
namespace Fido2NetLib;
@@ -8,20 +12,87 @@ namespace Fido2NetLib;
///
public sealed class Base64UrlConverter : JsonConverter
{
+ public static bool EnableRelaxedDecoding { get; set; }
+
public override byte[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
- if (!reader.HasValueSequence)
+ byte[]? rentedBuffer = null;
+
+ scoped ReadOnlySpan source;
+
+ if (!reader.HasValueSequence && !reader.ValueIsEscaped)
{
- return Base64Url.DecodeUtf8(reader.ValueSpan);
+ source = reader.ValueSpan;
}
else
{
- return Base64Url.Decode(reader.GetString());
+ int valueLength = reader.HasValueSequence ? checked((int)reader.ValueSequence.Length) : reader.ValueSpan.Length;
+
+ Span buffer = valueLength <= 32 ? stackalloc byte[32] : (rentedBuffer = ArrayPool.Shared.Rent(valueLength));
+ int bytesRead = reader.CopyString(buffer);
+ source = buffer[..bytesRead];
+ }
+
+ try
+ {
+ return Base64Url.DecodeFromUtf8(source);
+ }
+ catch (Exception ex)
+ {
+ if (Base64.IsValid(source))
+ {
+ static byte[] DecodeBase64FromUtf8(scoped ReadOnlySpan source)
+ {
+ var rentedBuffer = ArrayPool.Shared.Rent(Base64.GetMaxDecodedFromUtf8Length(source.Length));
+
+ try
+ {
+ _ = Base64.DecodeFromUtf8(source, rentedBuffer, out _, out int written);
+
+ return rentedBuffer[0..written];
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(rentedBuffer);
+ }
+ }
+
+ if (EnableRelaxedDecoding)
+ {
+ return DecodeBase64FromUtf8(source);
+ }
+ else
+ {
+ throw new JsonException("Expected data to be in Base64Url format, but received Base64 encoding instead.");
+ }
+ }
+ else
+ {
+ throw new JsonException(ex.Message, ex);
+ }
+ }
+ finally
+ {
+ if (rentedBuffer != null)
+ {
+ ArrayPool.Shared.Return(rentedBuffer);
+ }
}
}
public override void Write(Utf8JsonWriter writer, byte[] value, JsonSerializerOptions options)
{
- writer.WriteStringValue(Base64Url.Encode(value));
+ var rentedBuffer = ArrayPool.Shared.Rent(Base64Url.GetEncodedLength(value.Length));
+
+ try
+ {
+ Base64Url.EncodeToUtf8(value, rentedBuffer, out _, out int written);
+
+ writer.WriteStringValue(rentedBuffer.AsSpan(0..written));
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(rentedBuffer);
+ }
}
}
diff --git a/Src/Fido2.Models/Fido2.Models.csproj b/Src/Fido2.Models/Fido2.Models.csproj
index aff00326..34d32d3c 100644
--- a/Src/Fido2.Models/Fido2.Models.csproj
+++ b/Src/Fido2.Models/Fido2.Models.csproj
@@ -1,4 +1,4 @@
-
+
$(SupportedTargetFrameworks)
@@ -9,4 +9,8 @@
true
+
+
+
+
diff --git a/Src/Fido2.Models/Metadata/BiometricStatusReport.cs b/Src/Fido2.Models/Metadata/BiometricStatusReport.cs
index 5fa85be9..7c12043a 100644
--- a/Src/Fido2.Models/Metadata/BiometricStatusReport.cs
+++ b/Src/Fido2.Models/Metadata/BiometricStatusReport.cs
@@ -1,5 +1,4 @@
-using System.ComponentModel.DataAnnotations;
-using System.Text.Json.Serialization;
+using System.Text.Json.Serialization;
namespace Fido2NetLib;
diff --git a/Src/Fido2/AttestationFormat/AndroidSafetyNet.cs b/Src/Fido2/AttestationFormat/AndroidSafetyNet.cs
index c4d261e7..ccb45728 100644
--- a/Src/Fido2/AttestationFormat/AndroidSafetyNet.cs
+++ b/Src/Fido2/AttestationFormat/AndroidSafetyNet.cs
@@ -1,4 +1,5 @@
using System;
+using System.Buffers.Text;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
@@ -46,7 +47,7 @@ public override async ValueTask VerifyAsync(VerifyAttes
try
{
- jwtHeaderBytes = Base64Url.Decode(jwtComponents[0]);
+ jwtHeaderBytes = Base64Url.DecodeFromChars(jwtComponents[0]);
}
catch (FormatException)
{
diff --git a/Src/Fido2/AuthenticatorAssertionResponse.cs b/Src/Fido2/AuthenticatorAssertionResponse.cs
index 30dc5f6f..bf94b4a5 100644
--- a/Src/Fido2/AuthenticatorAssertionResponse.cs
+++ b/Src/Fido2/AuthenticatorAssertionResponse.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
diff --git a/Src/Fido2/Fido2.csproj b/Src/Fido2/Fido2.csproj
index 04ca19a7..0726c3ea 100644
--- a/Src/Fido2/Fido2.csproj
+++ b/Src/Fido2/Fido2.csproj
@@ -12,9 +12,9 @@
-
+
-
+
diff --git a/Src/Fido2/MakeAssertionParams.cs b/Src/Fido2/MakeAssertionParams.cs
index 312f9b2b..fb01ea52 100644
--- a/Src/Fido2/MakeAssertionParams.cs
+++ b/Src/Fido2/MakeAssertionParams.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
+using System.ComponentModel;
namespace Fido2NetLib;
diff --git a/Src/Fido2/Metadata/ConformanceMetadataRepository.cs b/Src/Fido2/Metadata/ConformanceMetadataRepository.cs
index ba7ef711..5c477fa2 100644
--- a/Src/Fido2/Metadata/ConformanceMetadataRepository.cs
+++ b/Src/Fido2/Metadata/ConformanceMetadataRepository.cs
@@ -1,4 +1,5 @@
using System;
+using System.Buffers.Text;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
@@ -132,7 +133,7 @@ public async Task DeserializeAndValidateBlobAsync(string ra
throw new Fido2MetadataException("The JWT does not have the 3 expected components");
var blobHeader = jwtParts[0];
- using var jsonDoc = JsonDocument.Parse(Base64Url.Decode(blobHeader));
+ using var jsonDoc = JsonDocument.Parse(Base64Url.DecodeFromChars(blobHeader));
var tokenHeader = jsonDoc.RootElement;
var blobAlg = tokenHeader.TryGetProperty("alg", out var algEl)
@@ -235,7 +236,7 @@ public async Task DeserializeAndValidateBlobAsync(string ra
var blobPayload = ((JsonWebToken)validateTokenResult.SecurityToken).EncodedPayload;
- MetadataBLOBPayload blob = JsonSerializer.Deserialize(Base64Url.Decode(blobPayload), FidoModelSerializerContext.Default.MetadataBLOBPayload)!;
+ MetadataBLOBPayload blob = JsonSerializer.Deserialize(Base64Url.DecodeFromChars(blobPayload), FidoModelSerializerContext.Default.MetadataBLOBPayload)!;
blob.JwtAlg = blobAlg;
return blob;
}
diff --git a/Src/Fido2/Metadata/Fido2MetadataServiceRepository.cs b/Src/Fido2/Metadata/Fido2MetadataServiceRepository.cs
index 0e874117..d4dda950 100644
--- a/Src/Fido2/Metadata/Fido2MetadataServiceRepository.cs
+++ b/Src/Fido2/Metadata/Fido2MetadataServiceRepository.cs
@@ -1,4 +1,5 @@
using System;
+using System.Buffers.Text;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
@@ -67,7 +68,7 @@ private async Task DeserializeAndValidateBlobAsync(string r
throw new ArgumentException("The JWT does not have the 3 expected components");
var blobHeaderString = jwtParts[0];
- using var blobHeaderDoc = JsonDocument.Parse(Base64Url.Decode(blobHeaderString));
+ using var blobHeaderDoc = JsonDocument.Parse(Base64Url.DecodeFromChars(blobHeaderString));
var blobHeader = blobHeaderDoc.RootElement;
string blobAlg = blobHeader.TryGetProperty("alg", out var algEl)
@@ -186,7 +187,7 @@ private async Task DeserializeAndValidateBlobAsync(string r
var blobPayload = ((JsonWebToken)validateTokenResult.SecurityToken).EncodedPayload;
- MetadataBLOBPayload blob = JsonSerializer.Deserialize(Base64Url.Decode(blobPayload), FidoModelSerializerContext.Default.MetadataBLOBPayload)!;
+ MetadataBLOBPayload blob = JsonSerializer.Deserialize(Base64Url.DecodeFromChars(blobPayload), FidoModelSerializerContext.Default.MetadataBLOBPayload)!;
blob.JwtAlg = blobAlg;
return blob;
}
diff --git a/Src/Fido2/Objects/CredentialPublicKey.cs b/Src/Fido2/Objects/CredentialPublicKey.cs
index 7913d258..74efcad6 100644
--- a/Src/Fido2/Objects/CredentialPublicKey.cs
+++ b/Src/Fido2/Objects/CredentialPublicKey.cs
@@ -1,7 +1,9 @@
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
+
using Fido2NetLib.Cbor;
+
using NSec.Cryptography;
namespace Fido2NetLib.Objects;
diff --git a/Src/Fido2/TokenBindingDto.cs b/Src/Fido2/TokenBindingDto.cs
index 3651b301..6238940c 100644
--- a/Src/Fido2/TokenBindingDto.cs
+++ b/Src/Fido2/TokenBindingDto.cs
@@ -1,4 +1,5 @@
-using System.Text.Json.Serialization;
+using System.Buffers.Text;
+using System.Text.Json.Serialization;
namespace Fido2NetLib;
public class TokenBindingDto
@@ -25,7 +26,7 @@ public void Verify(byte[]? requestTokenbinding)
case "present":
if (string.IsNullOrEmpty(Id))
throw new Fido2VerificationException("TokenBinding status was present but Id is missing");
- var b64 = Base64Url.Encode(requestTokenbinding);
+ var b64 = Base64Url.EncodeToString(requestTokenbinding);
if (Id != b64)
throw new Fido2VerificationException("Tokenbinding Id does not match");
break;
diff --git a/Tests/Fido2.Tests/Attestation/AndroidSafetyNet.cs b/Tests/Fido2.Tests/Attestation/AndroidSafetyNet.cs
index 0d290e90..1f950aaa 100644
--- a/Tests/Fido2.Tests/Attestation/AndroidSafetyNet.cs
+++ b/Tests/Fido2.Tests/Attestation/AndroidSafetyNet.cs
@@ -1,4 +1,5 @@
-using System.Security.Claims;
+using System.Buffers.Text;
+using System.Security.Claims;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
@@ -278,9 +279,9 @@ public async Task TestAndroidSafetyNetResponseJWTMissingX5c()
{
var response = (byte[])_attestationObject["attStmt"]["response"];
var jwtParts = Encoding.UTF8.GetString(response).Split('.');
- var jwtHeaderJSON = JObject.Parse(Encoding.UTF8.GetString(Base64Url.Decode(jwtParts.First())));
+ var jwtHeaderJSON = JObject.Parse(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(jwtParts.First())));
jwtHeaderJSON.Remove("x5c");
- jwtParts[0] = Base64Url.Encode(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jwtHeaderJSON)));
+ jwtParts[0] = Base64Url.EncodeToString(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jwtHeaderJSON)));
response = Encoding.UTF8.GetBytes(string.Join(".", jwtParts));
var attStmt = (CborMap)_attestationObject["attStmt"];
attStmt.Set("response", new CborByteString(response));
@@ -293,10 +294,10 @@ public async Task TestAndroidSafetyNetResponseJWTX5cNoKeys()
{
var response = (byte[])_attestationObject["attStmt"]["response"];
var jwtParts = Encoding.UTF8.GetString(response).Split('.');
- var jwtHeaderJSON = JObject.Parse(Encoding.UTF8.GetString(Base64Url.Decode(jwtParts.First())));
+ var jwtHeaderJSON = JObject.Parse(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(jwtParts.First())));
jwtHeaderJSON.Remove("x5c");
jwtHeaderJSON.Add("x5c", JToken.FromObject(new List { }));
- jwtParts[0] = Base64Url.Encode(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jwtHeaderJSON)));
+ jwtParts[0] = Base64Url.EncodeToString(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jwtHeaderJSON)));
response = Encoding.UTF8.GetBytes(string.Join(".", jwtParts));
var attStmt = (CborMap)_attestationObject["attStmt"];
attStmt.Set("response", new CborByteString(response));
@@ -309,10 +310,10 @@ public async Task TestAndroidSafetyNetResponseJWTX5cInvalidString()
{
var response = (byte[])_attestationObject["attStmt"]["response"];
var jwtParts = Encoding.UTF8.GetString(response).Split('.');
- var jwtHeaderJSON = JObject.Parse(Encoding.UTF8.GetString(Base64Url.Decode(jwtParts.First())));
+ var jwtHeaderJSON = JObject.Parse(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(jwtParts.First())));
jwtHeaderJSON.Remove("x5c");
jwtHeaderJSON.Add("x5c", JToken.FromObject(new List { "RjFEMA==" }));
- jwtParts[0] = Base64Url.Encode(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jwtHeaderJSON)));
+ jwtParts[0] = Base64Url.EncodeToString(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jwtHeaderJSON)));
response = Encoding.UTF8.GetBytes(string.Join(".", jwtParts));
var attStmt = (CborMap)_attestationObject["attStmt"];
attStmt.Set("response", new CborByteString(response));
@@ -325,7 +326,7 @@ public async Task TestAndroidSafetyNetJwtInvalid()
{
var response = (byte[])_attestationObject["attStmt"]["response"];
var jwtParts = Encoding.UTF8.GetString(response).Split('.');
- var jwtHeaderJSON = JObject.Parse(Encoding.UTF8.GetString(Base64Url.Decode(jwtParts.First())));
+ var jwtHeaderJSON = JObject.Parse(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(jwtParts.First())));
jwtHeaderJSON.Remove("x5c");
byte[] x5c = null;
using (var ecdsaAtt = ECDsa.Create())
@@ -341,7 +342,7 @@ public async Task TestAndroidSafetyNetJwtInvalid()
}
jwtHeaderJSON.Add("x5c", JToken.FromObject(new List { Convert.ToBase64String(x5c) }));
- jwtParts[0] = Base64Url.Encode(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jwtHeaderJSON)));
+ jwtParts[0] = Base64Url.EncodeToString(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jwtHeaderJSON)));
response = Encoding.UTF8.GetBytes(string.Join(".", jwtParts));
var attStmt = (CborMap)_attestationObject["attStmt"];
attStmt.Set("response", new CborByteString(response));
diff --git a/Tests/Fido2.Tests/Attestation/Apple.cs b/Tests/Fido2.Tests/Attestation/Apple.cs
index 6bcc7267..06a8d704 100644
--- a/Tests/Fido2.Tests/Attestation/Apple.cs
+++ b/Tests/Fido2.Tests/Attestation/Apple.cs
@@ -200,11 +200,11 @@ public async Task TestApplePublicKeyMismatch()
var authData = new AuthenticatorData(_rpIdHash, _flags, _signCount, _acd, GetExtensions()).ToByteArray();
_attestationObject.Set("authData", new CborByteString(authData));
- var clientData = new
+ var clientData = new MockClientData
{
- type = "webauthn.create",
- challenge = _challenge,
- origin = "https://www.passwordless.dev",
+ Type = "webauthn.create",
+ Challenge = _challenge,
+ Origin = "https://www.passwordless.dev",
};
var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(clientData);
diff --git a/Tests/Fido2.Tests/AuthenticatorResponse.cs b/Tests/Fido2.Tests/AuthenticatorResponse.cs
index de9c0af5..eca8c4ea 100644
--- a/Tests/Fido2.Tests/AuthenticatorResponse.cs
+++ b/Tests/Fido2.Tests/AuthenticatorResponse.cs
@@ -1,4 +1,5 @@
-using System.Formats.Cbor;
+using System.Buffers.Text;
+using System.Formats.Cbor;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
@@ -21,7 +22,7 @@ public void CanDeserialize()
var response = JsonSerializer.Deserialize("""{"type":"webauthn.get","challenge":"J4fjxBV-BNywGRJRm8JZ7znvdiZo9NINObNBpnKnJQEOtplTMF0ERuIrzrkeoO-dNMoeMZjhzqfar7eWRANvPeNFPrB5Q6zlS1ZFPf37F3suIwpXi9NCpFA_RlBSiygLmvcIOa57_QHubZQD3cv0UWtRTLslJjmgumphMc7EFN8","origin":"https://www.passwordless.dev"}""");
Assert.Equal("webauthn.get", response.Type);
- Assert.Equal(Base64Url.Decode("J4fjxBV-BNywGRJRm8JZ7znvdiZo9NINObNBpnKnJQEOtplTMF0ERuIrzrkeoO-dNMoeMZjhzqfar7eWRANvPeNFPrB5Q6zlS1ZFPf37F3suIwpXi9NCpFA_RlBSiygLmvcIOa57_QHubZQD3cv0UWtRTLslJjmgumphMc7EFN8"), response.Challenge);
+ Assert.Equal(Base64Url.DecodeFromChars("J4fjxBV-BNywGRJRm8JZ7znvdiZo9NINObNBpnKnJQEOtplTMF0ERuIrzrkeoO-dNMoeMZjhzqfar7eWRANvPeNFPrB5Q6zlS1ZFPf37F3suIwpXi9NCpFA_RlBSiygLmvcIOa57_QHubZQD3cv0UWtRTLslJjmgumphMc7EFN8"), response.Challenge);
Assert.Equal("https://www.passwordless.dev", response.Origin);
}
@@ -65,11 +66,11 @@ public async Task TestAuthenticatorOriginsAsync(string origin, string expectedOr
acd
).ToByteArray();
- byte[] clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ byte[] clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
- type = "webauthn.create",
- challenge = challenge,
- origin = rp
+ Type = "webauthn.create",
+ Challenge = challenge,
+ Origin = rp
});
var rawResponse = new AuthenticatorAttestationRawResponse
{
@@ -170,11 +171,11 @@ public async Task TestAuthenticatorOriginsFail(string origin, string expectedOri
0,
acd
).ToByteArray();
- var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
- type = "webauthn.create",
- challenge = challenge,
- origin = rp
+ Type = "webauthn.create",
+ Challenge = challenge,
+ Origin = rp
});
var rawResponse = new AuthenticatorAttestationRawResponse
@@ -242,7 +243,7 @@ public async Task TestAuthenticatorOriginsFail(string origin, string expectedOri
public void TestAuthenticatorAttestationRawResponse()
{
var challenge = RandomNumberGenerator.GetBytes(128);
- var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
Type = "webauthn.create",
Challenge = challenge,
@@ -384,7 +385,7 @@ public async Task TestAuthenticatorAttestationResponseInvalidType()
{
var challenge = RandomNumberGenerator.GetBytes(128);
var rp = "https://www.passwordless.dev";
- var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
Type = "webauthn.get",
Challenge = challenge,
@@ -459,11 +460,11 @@ public async Task TestAuthenticatorAttestationResponseInvalidRawId(byte[] value)
{
var challenge = RandomNumberGenerator.GetBytes(128);
var rp = "https://www.passwordless.dev";
- byte[] clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ byte[] clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
- type = "webauthn.create",
- challenge = challenge,
- origin = rp,
+ Type = "webauthn.create",
+ Challenge = challenge,
+ Origin = rp,
});
var rawResponse = new AuthenticatorAttestationRawResponse
@@ -532,11 +533,11 @@ public async Task TestAuthenticatorAttestationResponseInvalidRawType()
{
var challenge = RandomNumberGenerator.GetBytes(128);
var rp = "https://www.passwordless.dev";
- var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
- type = "webauthn.create",
- challenge = challenge,
- origin = rp,
+ Type = "webauthn.create",
+ Challenge = challenge,
+ Origin = rp,
});
var rawResponse = new AuthenticatorAttestationRawResponse
@@ -612,11 +613,11 @@ public async Task TestAuthenticatorAttestationResponseRpidMismatch()
null
).ToByteArray();
- var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
- type = "webauthn.create",
- challenge = challenge,
- origin = rp,
+ Type = "webauthn.create",
+ Challenge = challenge,
+ Origin = rp
});
var rawResponse = new AuthenticatorAttestationRawResponse
@@ -693,11 +694,11 @@ public async Task TestAuthenticatorAttestationResponseNotUserPresentAsync()
null
).ToByteArray();
- var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
- type = "webauthn.create",
- challenge = challenge,
- origin = rp
+ Type = "webauthn.create",
+ Challenge = challenge,
+ Origin = rp
});
var rawResponse = new AuthenticatorAttestationRawResponse
@@ -776,11 +777,11 @@ public async Task TestAuthenticatorAttestationResponseBackupEligiblePolicyRequir
null
).ToByteArray();
- var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
- type = "webauthn.create",
- challenge = challenge,
- origin = rp,
+ Type = "webauthn.create",
+ Challenge = challenge,
+ Origin = rp,
});
var rawResponse = new AuthenticatorAttestationRawResponse
@@ -857,11 +858,11 @@ public async Task TestAuthenticatorAttestationResponseBackupEligiblePolicyDisall
null
).ToByteArray();
- var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
- type = "webauthn.create",
- challenge = challenge,
- origin = rp,
+ Type = "webauthn.create",
+ Challenge = challenge,
+ Origin = rp,
});
var rawResponse = new AuthenticatorAttestationRawResponse
@@ -938,11 +939,11 @@ public async Task TestAuthenticatorAttestationResponseNoAttestedCredentialData()
null
).ToByteArray();
- var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
- type = "webauthn.create",
- challenge = challenge,
- origin = rp,
+ Type = "webauthn.create",
+ Challenge = challenge,
+ Origin = rp,
});
var rawResponse = new AuthenticatorAttestationRawResponse
@@ -1019,11 +1020,11 @@ public async Task TestAuthenticatorAttestationResponseUnknownAttestationType()
acd
).ToByteArray();
- var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
- type = "webauthn.create",
- challenge = challenge,
- origin = rp,
+ Type = "webauthn.create",
+ Challenge = challenge,
+ Origin = rp
});
var rawResponse = new AuthenticatorAttestationRawResponse
@@ -1100,11 +1101,11 @@ public async Task TestAuthenticatorAttestationResponseNotUniqueCredId()
0,
acd
).ToByteArray();
- var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
- type = "webauthn.create",
- challenge = challenge,
- origin = rp,
+ Type = "webauthn.create",
+ Challenge = challenge,
+ Origin = rp
});
var rawResponse = new AuthenticatorAttestationRawResponse
@@ -1180,11 +1181,11 @@ public async Task TestAuthenticatorAttestationResponseUVRequired()
0,
acd
).ToByteArray();
- var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new
+ var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(new MockClientData
{
- type = "webauthn.create",
- challenge = challenge,
- origin = rp,
+ Type = "webauthn.create",
+ Challenge = challenge,
+ Origin = rp
});
var rawResponse = new AuthenticatorAttestationRawResponse
diff --git a/Tests/Fido2.Tests/Base64UrlTest.cs b/Tests/Fido2.Tests/Base64UrlTest.cs
deleted file mode 100644
index 30518149..00000000
--- a/Tests/Fido2.Tests/Base64UrlTest.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System.Text;
-
-using Fido2NetLib;
-
-namespace fido2_net_lib.Test;
-
-public class Base64UrlTest
-{
- [Theory]
- [MemberData(nameof(GetData))]
- public void EncodeAndDecodeResultsAreEqual(byte[] data)
- {
- // Act
- var encodedString = Base64Url.Encode(data);
- var decodedBytes = Base64Url.Decode(encodedString);
-
- // Assert
- Assert.Equal(data, decodedBytes);
-
- // Ensure this also works with the Utf8 decoder
- Assert.Equal(data, Base64Url.DecodeUtf8(Encoding.UTF8.GetBytes(encodedString)));
- }
-
- public static IEnumerable