Skip to content

Commit

Permalink
Added AttestationFormat enum.
Browse files Browse the repository at this point in the history
  • Loading branch information
KristofferStrube committed Aug 11, 2024
1 parent 7a510e4 commit 539bcbb
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ private async Task CreateCredential()
Timeout = 360000,
Hints = "client-device",
Attestation = AttestationConveyancePreference.Direct,
AttestationFormats = ["tpm"]
AttestationFormats = [AttestationFormat.Packed, AttestationFormat.AndroidKey, AttestationFormat.AndroidSafetyNet, AttestationFormat.TPM]
}
};
credential = await container.CreateAsync(options) is { } c ? new PublicKeyCredential(c) : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,19 @@ internal static AndroidSafetyNetAttestationStatement ReadAttestationStatement(Cb
state = cborReader.PeekState();
if (state is not CborReaderState.TextString)
{
throw new FormatException($"Attestation Statement's packed format's second key was of type '{state}' but '{CborReaderState.TextString}' was expected.");
throw new FormatException($"Attestation Statement's safety net format's second key was of type '{state}' but '{CborReaderState.TextString}' was expected.");
}

label = cborReader.ReadTextString();
if (label is not "response")
{
throw new FormatException($"Attestation Statement's packed format's second key was '{label}' but 'response' was expected.");
throw new FormatException($"Attestation Statement's safety net format's second key was '{label}' but 'response' was expected.");
}

state = cborReader.PeekState();
if (state is not CborReaderState.ByteString)
{
throw new FormatException($"Attestation Statement's packed format's 'response' was of type '{state}' but '{CborReaderState.ByteString}' was expected.");
throw new FormatException($"Attestation Statement's safety net format's 'response' was of type '{state}' but '{CborReaderState.ByteString}' was expected.");
}

byte[] response = cborReader.ReadByteString();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace KristofferStrube.Blazor.WebAuthentication.Converters;

public class AttestationFormatConverter : JsonConverter<AttestationFormat>
{
public override AttestationFormat Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return reader.GetString() switch
{
"packed" => AttestationFormat.Packed,
"tpm" => AttestationFormat.TPM,
"android-key" => AttestationFormat.AndroidKey,
"android-safetynet" => AttestationFormat.AndroidSafetyNet,
"fido-u2f" => AttestationFormat.FidoU2F,
"apple" => AttestationFormat.Apple,
"none" => AttestationFormat.None,
var value => throw new ArgumentException($"Value '{value}' was not a valid {nameof(AttestationFormat)}.")
};
}

public override void Write(Utf8JsonWriter writer, AttestationFormat value, JsonSerializerOptions options)
{
writer.WriteStringValue(value switch
{
AttestationFormat.Packed => "packed",
AttestationFormat.TPM => "tpm",
AttestationFormat.AndroidKey => "android-key",
AttestationFormat.AndroidSafetyNet => "android-safetynet",
AttestationFormat.FidoU2F => "fido-u2f",
AttestationFormat.Apple => "apple",
AttestationFormat.None => "none",
_ => throw new ArgumentException($"Value '{value}' was not a valid {nameof(AttestationFormat)}.")
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using KristofferStrube.Blazor.WebAuthentication.Converters;
using System.Text.Json.Serialization;

namespace KristofferStrube.Blazor.WebAuthentication;

/// <summary>
/// Authenticators may implement various transports for communicating with clients.
/// This enum defines hints as to how clients might communicate with a particular authenticator in order to obtain an assertion for a specific credential.
/// </summary>
/// <remarks><see href="https://www.iana.org/assignments/webauthn/webauthn.xhtml">See the API definition here</see>.</remarks>
[JsonConverter(typeof(AttestationFormatConverter))]
public enum AttestationFormat
{
/// <summary>
/// The "packed" attestation statement format is a WebAuthn-optimized format for attestation. It uses a very compact but still extensible encoding method.
/// This format is implementable by authenticators with limited resources (e.g., secure elements).
/// </summary>
Packed,
/// <summary>
/// The TPM attestation statement format returns an attestation statement in the same format as the packed attestation statement format,
/// although the rawData and signature fields are computed differently.
/// </summary>
TPM,
/// <summary>
/// Platform authenticators on versions "N", and later, may provide this proprietary "hardware attestation" statement.
/// </summary>
AndroidKey,
/// <summary>
/// Android-based platform authenticators MAY produce an attestation statement based on the Android SafetyNet API.
/// </summary>
AndroidSafetyNet,
/// <summary>
/// Used with FIDO U2F authenticators
/// </summary>
FidoU2F,
/// <summary>
/// Used with Apple devices' platform authenticators
/// </summary>
Apple,
/// <summary>
/// Used to replace any authenticator-provided attestation statement when a WebAuthn Relying Party indicates it does not wish to receive attestation information.
/// </summary>
None,
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

namespace KristofferStrube.Blazor.WebAuthentication;

/// <summary>
/// The options specific to the public key of <see cref="CredentialCreationOptions"/>.
/// </summary>
/// <remarks><see href="https://www.w3.org/TR/webauthn-3/#dictdef-publickeycredentialcreationoptions">See the API definition here</see>.</remarks>
public class PublicKeyCredentialCreationOptions
{
[JsonPropertyName("rp")]
Expand All @@ -27,7 +31,12 @@ public class PublicKeyCredentialCreationOptions
[JsonPropertyName("attestation")]
public AttestationConveyancePreference Attestation { get; set; }

/// <summary>
/// The Relying Party can use this optional member to specify a preference regarding the attestation statement format used by the authenticator.
/// Values are ordered from most preferable to least preferable.
/// This parameter is advisory and the authenticator and could use an attestation statement not enumerated in this parameter.
/// </summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("attestationFormats")]
public string[]? AttestationFormats { get; set; }
public AttestationFormat[]? AttestationFormats { get; set; }
}

0 comments on commit 539bcbb

Please sign in to comment.