diff --git a/Directory.Build.props b/Directory.Build.props index 7d2407005..e5f4cc753 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -16,7 +16,7 @@ - net8.0 + net8.0;net10.0 enable true true @@ -29,7 +29,7 @@ - 12 + 13 diff --git a/Src/Fido2.Models/Converters/EnumNameMapper.cs b/Src/Fido2.Models/Converters/EnumNameMapper.cs index 8bd0f56d0..74c46f6e0 100644 --- a/Src/Fido2.Models/Converters/EnumNameMapper.cs +++ b/Src/Fido2.Models/Converters/EnumNameMapper.cs @@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.Serialization; +using System.Text.Json.Serialization; namespace Fido2NetLib; @@ -45,11 +46,15 @@ private static FrozenDictionary GetIdToNameMap() foreach (var field in typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static)) { - var description = field.GetCustomAttribute(false); +#if NET9_0_OR_GREATER + var description = field.GetCustomAttribute(false)?.Name; +#else + var description = field.GetCustomAttribute(false)?.Value; +#endif var value = (TEnum)field.GetValue(null)!; - items.Add(new(value, description is not null ? description.Value! : value.ToString())); + items.Add(new(value, description ?? value.ToString())); } return items.ToFrozenDictionary(); diff --git a/Src/Fido2.Models/Fido2Configuration.cs b/Src/Fido2.Models/Fido2Configuration.cs index 686052e5a..10d10d739 100644 --- a/Src/Fido2.Models/Fido2Configuration.cs +++ b/Src/Fido2.Models/Fido2Configuration.cs @@ -1,6 +1,7 @@ #nullable disable using System.Runtime.Serialization; +using System.Text.Json.Serialization; namespace Fido2NetLib; @@ -114,19 +115,31 @@ public enum CredentialBackupPolicy /// /// This value indicates that the Relying Party requires backup eligible or backed up credentials. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("required")] +#else [EnumMember(Value = "required")] +#endif Required, /// /// This value indicates that the Relying Party allows backup eligible or backed up credentials. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("allowed")] +#else [EnumMember(Value = "allowed")] +#endif Allowed, /// /// This value indicates that the Relying Party does not allow backup eligible or backed up credentials. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("disallowed")] +#else [EnumMember(Value = "disallowed")] +#endif Disallowed } } diff --git a/Src/Fido2.Models/Metadata/UserVerificationMethods.cs b/Src/Fido2.Models/Metadata/UserVerificationMethods.cs index 277def09b..032b6d440 100644 --- a/Src/Fido2.Models/Metadata/UserVerificationMethods.cs +++ b/Src/Fido2.Models/Metadata/UserVerificationMethods.cs @@ -10,72 +10,128 @@ namespace Fido2NetLib; * * https://fidoalliance.org/specs/fido-uaf-v1.0-ps-20141208/fido-uaf-reg-v1.0-ps-20141208.html#user-verification-methods */ +#if NET9_0_OR_GREATER +[JsonConverter(typeof(JsonStringEnumConverter))] +#else [JsonConverter(typeof(FidoEnumConverter))] +#endif public enum UserVerificationMethods { /// /// This flag must be set if the authenticator is able to confirm user presence in any fashion. If this flag and no other is set for user verification, the guarantee is only that the authenticator cannot be operated without some human intervention, not necessarily that the presence verification provides any level of authentication of the human's identity. (e.g. a device that requires a touch to activate) /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("presence_internal")] +#else [EnumMember(Value = "presence_internal")] +#endif PRESENCE_INTERNAL = 1, /// /// This flag must be set if the authenticator uses any type of measurement of a fingerprint for user verification. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("fingerprint_internal")] +#else [EnumMember(Value = "fingerprint_internal")] +#endif FINGERPRINT_INTERNAL = 2, /// /// This flag must be set if the authenticator uses a local-only passcode (i.e. a passcode not known by the server) for user verification. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("passcode_internal")] +#else [EnumMember(Value = "passcode_internal")] +#endif PASSCODE_INTERNAL = 4, /// /// This flag must be set if the authenticator uses a voiceprint (also known as speaker recognition) for user verification. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("voiceprint_internal")] +#else [EnumMember(Value = "voiceprint_internal")] +#endif VOICEPRINT_INTERNAL = 8, /// /// This flag must be set if the authenticator uses any manner of face recognition to verify the user. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("faceprint_internal")] +#else [EnumMember(Value = "faceprint_internal")] +#endif FACEPRINT_INTERNAL = 0x10, /// /// This flag must be set if the authenticator uses any form of location sensor or measurement for user verification. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("location_internal")] +#else [EnumMember(Value = "location_internal")] +#endif LOCATION_INTERNAL = 0x20, /// /// This flag must be set if the authenticator uses any form of eye biometrics for user verification. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("eyeprint_internal")] +#else [EnumMember(Value = "eyeprint_internal")] +#endif EYEPRINT_INTERNAL = 0x40, /// /// This flag must be set if the authenticator uses a drawn pattern for user verification. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("pattern_internal")] +#else [EnumMember(Value = "pattern_internal")] +#endif PATTERN_INTERNAL = 0x80, /// /// This flag must be set if the authenticator uses any measurement of a full hand (including palm-print, hand geometry or vein geometry) for user verification. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("handprint_internal")] +#else [EnumMember(Value = "handprint_internal")] +#endif HANDPRINT_INTERNAL = 0x100, /// /// This flag must be set if the authenticator uses a local-only passcode (i.e. a passcode not known by the server) for user verification that might be gathered outside the authenticator boundary. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("passcode_external")] +#else [EnumMember(Value = "passcode_external")] +#endif PASSCODE_EXTERNAL = 0x800, /// /// This flag must be set if the authenticator uses a drawn pattern for user verification that might be gathered outside the authenticator boundary. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("pattern_external")] +#else [EnumMember(Value = "pattern_external")] +#endif PATTERN_EXTERNAL = 0x1000, /// /// This flag must be set if the authenticator will respond without any user interaction (e.g. Silent Authenticator). /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("none")] +#else [EnumMember(Value = "none")] +#endif NONE = 0x200, /// /// If an authenticator sets multiple flags for user verification types, it may also set this flag to indicate that all verification methods will be enforced (e.g. faceprint AND voiceprint). If flags for multiple user verification methods are set and this flag is not set, verification with only one is necessary (e.g. fingerprint OR passcode). /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("all")] +#else [EnumMember(Value = "all")] +#endif ALL = 0x400, } diff --git a/Src/Fido2.Models/Objects/AttestationConveyancePreference.cs b/Src/Fido2.Models/Objects/AttestationConveyancePreference.cs index 517fd21e2..ecc502d08 100644 --- a/Src/Fido2.Models/Objects/AttestationConveyancePreference.cs +++ b/Src/Fido2.Models/Objects/AttestationConveyancePreference.cs @@ -7,31 +7,51 @@ namespace Fido2NetLib.Objects; /// AttestationConveyancePreference /// https://www.w3.org/TR/webauthn-2/#enum-attestation-convey /// +#if NET9_0_OR_GREATER +[JsonConverter(typeof(JsonStringEnumConverter))] +#else [JsonConverter(typeof(FidoEnumConverter))] +#endif public enum AttestationConveyancePreference { /// /// This value indicates that the Relying Party is not interested in authenticator attestation. For example, in order to potentially avoid having to obtain user consent to relay identifying information to the Relying Party, or to save a roundtrip to an Attestation CA. /// This is the default value. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("none")] +#else [EnumMember(Value = "none")] +#endif None, /// /// This value indicates that the Relying Party prefers an attestation conveyance yielding verifiable attestation statements, but allows the client to decide how to obtain such attestation statements. The client MAY replace the authenticator-generated attestation statements with attestation statements generated by an Anonymization CA, in order to protect the user’s privacy, or to assist Relying Parties with attestation verification in a heterogeneous ecosystem. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("indirect")] +#else [EnumMember(Value = "indirect")] +#endif Indirect, /// /// This value indicates that the Relying Party wants to receive the attestation statement as generated by the authenticator. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("direct")] +#else [EnumMember(Value = "direct")] +#endif Direct, /// /// This value indicates that the Relying Party wants to receive an attestation statement that may include uniquely identifying information. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("enterprise")] +#else [EnumMember(Value = "enterprise")] +#endif Enterprise } diff --git a/Src/Fido2.Models/Objects/AttestationStatementFormatIdentifier.cs b/Src/Fido2.Models/Objects/AttestationStatementFormatIdentifier.cs index 02201a828..3bc779cfc 100644 --- a/Src/Fido2.Models/Objects/AttestationStatementFormatIdentifier.cs +++ b/Src/Fido2.Models/Objects/AttestationStatementFormatIdentifier.cs @@ -7,49 +7,81 @@ namespace Fido2NetLib.Objects; /// The attestation statement format identifier in WebAuthn specifies the format of the attestation statement that is used to attest to the authenticity of a credential created by a WebAuthn authenticator. /// https://www.iana.org/assignments/webauthn/webauthn.xhtml /// +#if NET9_0_OR_GREATER +[JsonConverter(typeof(JsonStringEnumConverter))] +#else [JsonConverter(typeof(FidoEnumConverter))] +#endif public enum AttestationStatementFormatIdentifier { /// /// 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). /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("packed")] +#else [EnumMember(Value = "packed")] +#endif Packed, /// /// 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. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("tpm")] +#else [EnumMember(Value = "tpm")] +#endif Tpm, /// /// Platform authenticators on versions "N", and later, may provide this proprietary "hardware attestation" statement. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("android-key")] +#else [EnumMember(Value = "android-key")] +#endif AndroidKey, /// /// Android-based platform authenticators MAY produce an attestation statement based on the Android SafetyNet API. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("android-safetynet")] +#else [EnumMember(Value = "android-safetynet")] +#endif AndroidSafetyNet, /// /// Used with FIDO U2F authenticators. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("fido-u2f")] +#else [EnumMember(Value = "fido-u2f")] +#endif FidoU2f, /// /// Used with Apple devices' platform authenticators. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("apple")] +#else [EnumMember(Value = "apple")] +#endif Apple, /// /// Used to replace any authenticator-provided attestation statement when a WebAuthn Relying Party indicates it does not wish to receive attestation information. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("none")] +#else [EnumMember(Value = "none")] +#endif None } diff --git a/Src/Fido2.Models/Objects/AuthenticatorAttachment.cs b/Src/Fido2.Models/Objects/AuthenticatorAttachment.cs index 9833a353d..925afaa6b 100644 --- a/Src/Fido2.Models/Objects/AuthenticatorAttachment.cs +++ b/Src/Fido2.Models/Objects/AuthenticatorAttachment.cs @@ -12,18 +12,30 @@ namespace Fido2NetLib.Objects; /// Note: An authenticator attachment modality selection option is available only in the [[Create]](origin, options, sameOriginWithAncestors) operation. The Relying Party may use it to, for example, ensure the user has a roaming credential for authenticating on another client device; or to specifically register a platform credential for easier reauthentication using a particular client device. The [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) operation has no authenticator attachment modality selection option, so the Relying Party SHOULD accept any of the user’s registered credentials. The client and user will then use whichever is available and convenient at the time. /// https://www.w3.org/TR/webauthn-2/#enum-attachment /// +#if NET9_0_OR_GREATER +[JsonConverter(typeof(JsonStringEnumConverter))] +#else [JsonConverter(typeof(FidoEnumConverter))] +#endif public enum AuthenticatorAttachment { /// /// This value indicates platform attachment /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("platform")] +#else [EnumMember(Value = "platform")] +#endif Platform, /// /// This value indicates cross-platform attachment. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("cross-platform")] +#else [EnumMember(Value = "cross-platform")] +#endif CrossPlatform } diff --git a/Src/Fido2.Models/Objects/AuthenticatorTransport.cs b/Src/Fido2.Models/Objects/AuthenticatorTransport.cs index 03200a628..69ef45f75 100644 --- a/Src/Fido2.Models/Objects/AuthenticatorTransport.cs +++ b/Src/Fido2.Models/Objects/AuthenticatorTransport.cs @@ -11,44 +11,72 @@ namespace Fido2NetLib.Objects; /// A Relying Party will typically learn of the supported transports for a public key credential via getTransports(). /// https://www.w3.org/TR/webauthn-2/#enum-transport /// +#if NET9_0_OR_GREATER +[JsonConverter(typeof(JsonStringEnumConverter))] +#else [JsonConverter(typeof(FidoEnumConverter))] +#endif public enum AuthenticatorTransport { /// /// Indicates the respective authenticator can be contacted over removable USB. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("usb")] +#else [EnumMember(Value = "usb")] +#endif Usb, /// /// Indicates the respective authenticator can be contacted over Near Field Communication (NFC). /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("nfc")] +#else [EnumMember(Value = "nfc")] +#endif Nfc, /// /// Indicates the respective authenticator can be contacted over Bluetooth Smart (Bluetooth Low Energy / BLE). /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("ble")] +#else [EnumMember(Value = "ble")] +#endif Ble, /// /// Indicates the respective authenticator can be contacted over over ISO/IEC 7816 smart card with contacts. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("smart-card")] +#else [EnumMember(Value = "smart-card")] +#endif SmartCard, /// /// Indicates the respective authenticator can be contacted using a combination of (often separate) data-transport /// and proximity mechanisms. This supports, for example, authentication on a desktop computer using a smartphone. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("hybrid")] +#else [EnumMember(Value = "hybrid")] +#endif Hybrid, /// /// Indicates the respective authenticator is contacted using a client device-specific transport, i.e., it is a platform authenticator. /// These authenticators are not removable from the client device. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("internal")] +#else [EnumMember(Value = "internal")] +#endif Internal, } diff --git a/Src/Fido2.Models/Objects/CredentialProtectionPolicy.cs b/Src/Fido2.Models/Objects/CredentialProtectionPolicy.cs index 298f32323..294b88067 100644 --- a/Src/Fido2.Models/Objects/CredentialProtectionPolicy.cs +++ b/Src/Fido2.Models/Objects/CredentialProtectionPolicy.cs @@ -7,25 +7,41 @@ namespace Fido2NetLib.Objects; /// CredentialProtectionPolicy /// https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#sctn-credProtect-extension /// +#if NET9_0_OR_GREATER +[JsonConverter(typeof(JsonStringEnumConverter))] +#else [JsonConverter(typeof(FidoEnumConverter))] +#endif public enum CredentialProtectionPolicy { /// /// This reflects "FIDO_2_0" semantics. In this configuration, performing some form of user verification is OPTIONAL with or without credentialID list. /// This is the default state of the credential if the extension is not specified /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("userVerificationOptional")] +#else [EnumMember(Value = "userVerificationOptional")] +#endif UserVerificationOptional = 0x01, /// /// In this configuration, credential is discovered only when its credentialID is provided by the platform or when some form of user verification is performed. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("userVerificationOptionalWithCredentialIDList")] +#else [EnumMember(Value = "userVerificationOptionalWithCredentialIDList")] +#endif UserVerificationOptionalWithCredentialIdList = 0x02, /// /// TThis reflects that discovery and usage of the credential MUST be preceded by some form of user verification. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("userVerificationRequired")] +#else [EnumMember(Value = "userVerificationRequired")] +#endif UserVerificationRequired = 0x03 } diff --git a/Src/Fido2.Models/Objects/KeyProtection.cs b/Src/Fido2.Models/Objects/KeyProtection.cs index 78a3e7bb6..b3e34f257 100644 --- a/Src/Fido2.Models/Objects/KeyProtection.cs +++ b/Src/Fido2.Models/Objects/KeyProtection.cs @@ -11,36 +11,60 @@ namespace Fido2NetLib; * https://fidoalliance.org/specs/fido-uaf-v1.0-ps-20141208/fido-uaf-reg-v1.0-ps-20141208.html#key-protection-types * type {Object} */ +#if NET9_0_OR_GREATER +[JsonConverter(typeof(JsonStringEnumConverter))] +#else [JsonConverter(typeof(FidoEnumConverter))] +#endif public enum KeyProtection { /// /// This flag must be set if the authenticator uses software-based key management. Exclusive in authenticator metadata with KEY_PROTECTION_HARDWARE, KEY_PROTECTION_TEE, KEY_PROTECTION_SECURE_ELEMENT /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("software")] +#else [EnumMember(Value = "software")] +#endif SOFTWARE = 1, /// /// This flag should be set if the authenticator uses hardware-based key management. Exclusive in authenticator metadata with KEY_PROTECTION_SOFTWARE /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("hardware")] +#else [EnumMember(Value = "hardware")] +#endif HARDWARE = 2, /// /// This flag should be set if the authenticator uses the Trusted Execution Environment [TEE] for key management. In authenticator metadata, this flag should be set in conjunction with KEY_PROTECTION_HARDWARE. Exclusive in authenticator metadata with KEY_PROTECTION_SOFTWARE, KEY_PROTECTION_SECURE_ELEMENT /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("tee")] +#else [EnumMember(Value = "tee")] +#endif TEE = 4, /// /// This flag should be set if the authenticator uses a Secure Element [SecureElement] for key management. In authenticator metadata, this flag should be set in conjunction with KEY_PROTECTION_HARDWARE. Exclusive in authenticator metadata with KEY_PROTECTION_TEE, KEY_PROTECTION_SOFTWARE /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("secure_element")] +#else [EnumMember(Value = "secure_element")] +#endif SECURE_ELEMENT = 0x8, /// /// This flag must be set if the authenticator does not store (wrapped) UAuth keys at the client, but relies on a server-provided key handle. This flag must be set in conjunction with one of the other KEY_PROTECTION flags to indicate how the local key handle wrapping key and operations are protected. Servers may unset this flag in authenticator policy if they are not prepared to store and return key handles, for example, if they have a requirement to respond indistinguishably to authentication attempts against userIDs that do and do not exist. Refer to [UAFProtocol] for more details. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("remote_handle")] +#else [EnumMember(Value = "remote_handle")] +#endif REMOTE_HANDLE = 0x10, } diff --git a/Src/Fido2.Models/Objects/LargeBlobSupport.cs b/Src/Fido2.Models/Objects/LargeBlobSupport.cs index 33685c8e4..49bcdc6de 100644 --- a/Src/Fido2.Models/Objects/LargeBlobSupport.cs +++ b/Src/Fido2.Models/Objects/LargeBlobSupport.cs @@ -8,18 +8,30 @@ namespace Fido2NetLib.Objects; /// /// https://w3c.github.io/webauthn/#sctn-large-blob-extension /// +#if NET9_0_OR_GREATER +[JsonConverter(typeof(JsonStringEnumConverter))] +#else [JsonConverter(typeof(FidoEnumConverter))] +#endif public enum LargeBlobSupport { /// /// largeBlob support is required -- credential creation will fail if largeBlob is not supported /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("required")] +#else [EnumMember(Value = "required")] +#endif Required, /// /// largeBlob support is preferred -- credential creation will succeed even if largeBlob is not supported. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("preferred")] +#else [EnumMember(Value = "preferred")] +#endif Preferred } diff --git a/Src/Fido2.Models/Objects/PublicKeyCredentialHint.cs b/Src/Fido2.Models/Objects/PublicKeyCredentialHint.cs index 9634174ab..073706fbd 100644 --- a/Src/Fido2.Models/Objects/PublicKeyCredentialHint.cs +++ b/Src/Fido2.Models/Objects/PublicKeyCredentialHint.cs @@ -7,24 +7,40 @@ namespace Fido2NetLib.Objects; /// WebAuthn Relying Parties may use this enumeration to communicate hints to the user-agent about how a request may be best completed. These hints are not requirements, and do not bind the user-agent, but may guide it in providing the best experience by using contextual information that the Relying Party has about the request. Hints are provided in order of decreasing preference so, if two hints are contradictory, the first one controls. Hints may also overlap: if a more-specific hint is defined a Relying Party may still wish to send less specific ones for user-agents that may not recognise the more specific one. In this case the most specific hint should be sent before the less-specific ones. /// Hints MAY contradict information contained in credential transports and authenticatorAttachment. When this occurs, the hints take precedence. (Note that transports values are not provided when using discoverable credentials, leaving hints as the only avenue for expressing some aspects of such a request.) /// +#if NET9_0_OR_GREATER +[JsonConverter(typeof(JsonStringEnumConverter))] +#else [JsonConverter(typeof(FidoEnumConverter))] +#endif public enum PublicKeyCredentialHint { /// /// Indicates that the Relying Party believes that users will satisfy this request with a physical security key. For example, an enterprise Relying Party may set this hint if they have issued security keys to their employees and will only accept those authenticators for registration and authentication. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("security-key")] +#else [EnumMember(Value = "security-key")] +#endif SecurityKey, /// /// Indicates that the Relying Party believes that users will satisfy this request with a platform authenticator attached to the client device. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("client-device")] +#else [EnumMember(Value = "client-device")] +#endif ClientDevice, /// /// Indicates that the Relying Party believes that users will satisfy this request with general-purpose authenticators such as smartphones. For example, a consumer Relying Party may believe that only a small fraction of their customers possesses dedicated security keys. This option also implies that the local platform authenticator should not be promoted in the UI. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("hybrid")] +#else [EnumMember(Value = "hybrid")] +#endif Hybrid, } diff --git a/Src/Fido2.Models/Objects/PublicKeyCredentialType.cs b/Src/Fido2.Models/Objects/PublicKeyCredentialType.cs index 42aba210d..15e17d6af 100644 --- a/Src/Fido2.Models/Objects/PublicKeyCredentialType.cs +++ b/Src/Fido2.Models/Objects/PublicKeyCredentialType.cs @@ -7,12 +7,24 @@ namespace Fido2NetLib.Objects; /// PublicKeyCredentialType. /// https://www.w3.org/TR/webauthn-2/#enum-credentialType /// +#if NET9_0_OR_GREATER +[JsonConverter(typeof(JsonStringEnumConverter))] +#else [JsonConverter(typeof(FidoEnumConverter))] +#endif public enum PublicKeyCredentialType { +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("public-key")] +#else [EnumMember(Value = "public-key")] +#endif PublicKey, +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("invalid")] +#else [EnumMember(Value = "invalid")] +#endif Invalid } diff --git a/Src/Fido2.Models/Objects/ResidentKeyRequirement.cs b/Src/Fido2.Models/Objects/ResidentKeyRequirement.cs index 21763d25e..448735406 100644 --- a/Src/Fido2.Models/Objects/ResidentKeyRequirement.cs +++ b/Src/Fido2.Models/Objects/ResidentKeyRequirement.cs @@ -7,24 +7,40 @@ namespace Fido2NetLib.Objects; /// This enumeration’s values describe the Relying Party's requirements for client-side discoverable credentials (formerly known as resident credentials or resident keys). /// https://www.w3.org/TR/webauthn-2/#enum-residentKeyRequirement /// +#if NET9_0_OR_GREATER +[JsonConverter(typeof(JsonStringEnumConverter))] +#else [JsonConverter(typeof(FidoEnumConverter))] +#endif public enum ResidentKeyRequirement { /// /// The Relying Party requires a client-side discoverable credential. The client MUST return an error if a client-side discoverable credential cannot be created. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("required")] +#else [EnumMember(Value = "required")] +#endif Required, /// /// The Relying Party strongly prefers creating a client-side discoverable credential, but will accept a server-side credential. The client and authenticator SHOULD create a discoverable credential if possible. For example, the client SHOULD guide the user through setting up user verification if needed to create a discoverable credential. This takes precedence over the setting of userVerification. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("preferred")] +#else [EnumMember(Value = "preferred")] +#endif Preferred, /// /// The Relying Party prefers creating a server-side credential, but will accept a client-side discoverable credential. The client and authenticator SHOULD create a server-side credential if possible. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("discouraged")] +#else [EnumMember(Value = "discouraged")] +#endif Discouraged } diff --git a/Src/Fido2.Models/Objects/UserVerificationRequirement.cs b/Src/Fido2.Models/Objects/UserVerificationRequirement.cs index dde8ce4df..f4ae53009 100644 --- a/Src/Fido2.Models/Objects/UserVerificationRequirement.cs +++ b/Src/Fido2.Models/Objects/UserVerificationRequirement.cs @@ -8,27 +8,43 @@ namespace Fido2NetLib.Objects; /// and may use this type to express its needs. /// https://www.w3.org/TR/webauthn-2/#enumdef-userverificationrequirement /// +#if NET9_0_OR_GREATER +[JsonConverter(typeof(JsonStringEnumConverter))] +#else [JsonConverter(typeof(FidoEnumConverter))] +#endif public enum UserVerificationRequirement { /// /// This value indicates that the Relying Party requires user verification for the operation /// and will fail the operation if the response does not have the UV flag set. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("required")] +#else [EnumMember(Value = "required")] +#endif Required, /// /// This value indicates that the Relying Party prefers user verification for the operation if possible, /// but will not fail the operation if the response does not have the UV flag set. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("preferred")] +#else [EnumMember(Value = "preferred")] +#endif Preferred, /// /// This value indicates that the Relying Party does not want user verification employed during the operation /// (e.g., in the interest of minimizing disruption to the user interaction flow). /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("discouraged")] +#else [EnumMember(Value = "discouraged")] +#endif Discouraged } diff --git a/Src/Fido2/AttestationFormat/AndroidKey.cs b/Src/Fido2/AttestationFormat/AndroidKey.cs index 53b5194ca..cebeed843 100644 --- a/Src/Fido2/AttestationFormat/AndroidKey.cs +++ b/Src/Fido2/AttestationFormat/AndroidKey.cs @@ -158,7 +158,7 @@ public override ValueTask VerifyAsync(VerifyAttestation { try { - trustPath[i] = new X509Certificate2(x5cObject.Value); + trustPath[i] = X509CertificateHelper.CreateFromRawData(x5cObject.Value); } catch (Exception ex) when (i is 0) { diff --git a/Src/Fido2/AttestationFormat/Apple.cs b/Src/Fido2/AttestationFormat/Apple.cs index b7ee6eb54..9f108653d 100644 --- a/Src/Fido2/AttestationFormat/Apple.cs +++ b/Src/Fido2/AttestationFormat/Apple.cs @@ -56,7 +56,7 @@ public override ValueTask VerifyAsync(VerifyAttestation for (int i = 0; i < trustPath.Length; i++) { - trustPath[i] = new X509Certificate2((byte[])x5cArray[i]); + trustPath[i] = X509CertificateHelper.CreateFromRawData((byte[])x5cArray[i]); } // credCert is the first certificate in the trust path diff --git a/Src/Fido2/AttestationFormat/AppleAppAttest.cs b/Src/Fido2/AttestationFormat/AppleAppAttest.cs index 972efb4ef..1ee418149 100644 --- a/Src/Fido2/AttestationFormat/AppleAppAttest.cs +++ b/Src/Fido2/AttestationFormat/AppleAppAttest.cs @@ -59,10 +59,10 @@ public override async ValueTask VerifyAsync(VerifyAttes chain.ChainPolicy.CustomTrustStore.Add(AppleAppAttestRootCA); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; - X509Certificate2 intermediateCert = new((byte[])x5cArray[1]); + X509Certificate2 intermediateCert = X509CertificateHelper.CreateFromRawData((byte[])x5cArray[1]); chain.ChainPolicy.ExtraStore.Add(intermediateCert); - X509Certificate2 credCert = new((byte[])x5cArray[0]); + X509Certificate2 credCert = X509CertificateHelper.CreateFromRawData((byte[])x5cArray[0]); if (request.AuthData.AttestedCredentialData!.AaGuid.Equals(devAaguid)) { // Allow expired leaf cert in development environment diff --git a/Src/Fido2/AttestationFormat/FidoU2f.cs b/Src/Fido2/AttestationFormat/FidoU2f.cs index cb2f75407..3723e27e0 100644 --- a/Src/Fido2/AttestationFormat/FidoU2f.cs +++ b/Src/Fido2/AttestationFormat/FidoU2f.cs @@ -27,7 +27,7 @@ public override ValueTask VerifyAsync(VerifyAttestation throw new Fido2VerificationException(Fido2ErrorCode.InvalidAttestation, Fido2ErrorMessages.MalformedX5c_FidoU2fAttestation); } - var attCert = new X509Certificate2((byte[])x5cArray[0]); + var attCert = X509CertificateHelper.CreateFromRawData((byte[])x5cArray[0]); // TODO : Check why this variable isn't used. Remove it or use it. var u2fTransports = U2FTransportsFromAttnCert(attCert.Extensions); diff --git a/Src/Fido2/AttestationFormat/MetadataAttestationType.cs b/Src/Fido2/AttestationFormat/MetadataAttestationType.cs index 90bab13f1..b1af8dfd1 100644 --- a/Src/Fido2/AttestationFormat/MetadataAttestationType.cs +++ b/Src/Fido2/AttestationFormat/MetadataAttestationType.cs @@ -3,7 +3,11 @@ namespace Fido2NetLib; +#if NET9_0_OR_GREATER +[JsonConverter(typeof(JsonStringEnumConverter))] +#else [JsonConverter(typeof(FidoEnumConverter))] +#endif internal enum MetadataAttestationType { /// @@ -12,7 +16,11 @@ internal enum MetadataAttestationType /// The attestation trust anchor is shared with FIDO Servers out of band (as part of the Metadata). /// This sharing process shouldt be done according to [UAFMetadataService]. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("basic_full")] +#else [EnumMember(Value = "basic_full")] +#endif ATTESTATION_BASIC_FULL = 0x3e07, /// @@ -21,29 +29,49 @@ internal enum MetadataAttestationType /// As a consequence it does not provide a cryptographic proof of the security characteristics. /// But it is the best thing we can do if the authenticator is not able to have an attestation private key. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("basic_surrogate")] +#else [EnumMember(Value = "basic_surrogate")] +#endif ATTESTATION_BASIC_SURROGATE = 0x3e08, /// /// Indicates use of elliptic curve based direct anonymous attestation as defined in [FIDOEcdaaAlgorithm]. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("ecdaa")] +#else [EnumMember(Value = "ecdaa")] +#endif [Fido2Standard(Optional = true)] ATTESTATION_ECDAA = 0x3e09, /// /// Indicates PrivacyCA attestation as defined in [TCG-CMCProfile-AIKCertEnroll]. /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("attca")] +#else [EnumMember(Value = "attca")] +#endif [Fido2Standard(Optional = true)] ATTESTATION_PRIVACY_CA = 0x3e10, /// /// Anonymization CA (AnonCA) /// +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("anonca")] +#else [EnumMember(Value = "anonca")] +#endif ATTESTATION_ANONCA = 0x3e0c, +#if NET9_0_OR_GREATER + [JsonStringEnumMemberName("none")] +#else [EnumMember(Value = "none")] +#endif ATTESTATION_NONE = 0x3e0b } diff --git a/Src/Fido2/AttestationFormat/Packed.cs b/Src/Fido2/AttestationFormat/Packed.cs index 6a789be7f..4f1711f04 100644 --- a/Src/Fido2/AttestationFormat/Packed.cs +++ b/Src/Fido2/AttestationFormat/Packed.cs @@ -62,7 +62,7 @@ public override ValueTask VerifyAsync(VerifyAttestation { if (x5cArray[i] is CborByteString { Length: > 0 } x5cObject) { - var x5cCert = new X509Certificate2(x5cObject.Value); + var x5cCert = X509CertificateHelper.CreateFromRawData(x5cObject.Value); // X509Certificate2.NotBefore/.NotAfter return LOCAL DateTimes, so // it's correct to compare using DateTime.Now. diff --git a/Src/Fido2/AttestationFormat/Tpm.cs b/Src/Fido2/AttestationFormat/Tpm.cs index a105f4a6b..2575bdbfd 100644 --- a/Src/Fido2/AttestationFormat/Tpm.cs +++ b/Src/Fido2/AttestationFormat/Tpm.cs @@ -135,7 +135,7 @@ public override ValueTask VerifyAsync(VerifyAttestation { if (x5cArray[i] is CborByteString { Length: > 0 } x5cObject) { - trustPath[i] = new X509Certificate2(x5cObject.Value); + trustPath[i] = X509CertificateHelper.CreateFromRawData(x5cObject.Value); } else { diff --git a/Src/Fido2/Extensions/X509CertificateHelper.cs b/Src/Fido2/Extensions/X509CertificateHelper.cs index 0d850735e..7fe4ec30b 100644 --- a/Src/Fido2/Extensions/X509CertificateHelper.cs +++ b/Src/Fido2/Extensions/X509CertificateHelper.cs @@ -30,13 +30,10 @@ public static X509Certificate2 CreateFromBase64String(ReadOnlySpan base64S public static X509Certificate2 CreateFromRawData(ReadOnlySpan rawData) { - try - { - return new X509Certificate2(rawData); - } - catch (Exception ex) - { - throw new Exception("Could not parse X509 certificate", ex); - } +#if NET9_0_OR_GREATER + return X509CertificateLoader.LoadCertificate(rawData); +#else + return new X509Certificate2(rawData); +#endif } } diff --git a/Src/Fido2/TrustAnchor.cs b/Src/Fido2/TrustAnchor.cs index ce135011b..918f3753f 100644 --- a/Src/Fido2/TrustAnchor.cs +++ b/Src/Fido2/TrustAnchor.cs @@ -26,7 +26,7 @@ static bool ContainsAttestationType(MetadataBLOBPayloadEntry entry, MetadataAtte for (int i = 0; i < attestationRootCertificates.Length; i++) { - attestationRootCertificates[i] = new X509Certificate2(Convert.FromBase64String(certStrings[i])); + attestationRootCertificates[i] = X509CertificateHelper.CreateFromRawData(Convert.FromBase64String(certStrings[i])); } if (trustPath.Length > 1 && attestationRootCertificates.Any(c => string.Equals(c.Thumbprint, trustPath[^1].Thumbprint, StringComparison.Ordinal))) diff --git a/Tests/Fido2.Tests/Attestation/AndroidSafetyNet.cs b/Tests/Fido2.Tests/Attestation/AndroidSafetyNet.cs index 1f950aaab..aed6b6e0e 100644 --- a/Tests/Fido2.Tests/Attestation/AndroidSafetyNet.cs +++ b/Tests/Fido2.Tests/Attestation/AndroidSafetyNet.cs @@ -317,8 +317,7 @@ public async Task TestAndroidSafetyNetResponseJWTX5cInvalidString() response = Encoding.UTF8.GetBytes(string.Join(".", jwtParts)); var attStmt = (CborMap)_attestationObject["attStmt"]; attStmt.Set("response", new CborByteString(response)); - var ex = await Assert.ThrowsAnyAsync(MakeAttestationResponseAsync); - Assert.Equal("Could not parse X509 certificate", ex.Message); + await Assert.ThrowsAnyAsync(MakeAttestationResponseAsync); } [Fact] diff --git a/Tests/Fido2.Tests/Attestation/Apple.cs b/Tests/Fido2.Tests/Attestation/Apple.cs index 22ceaf1f8..14cf146dc 100644 --- a/Tests/Fido2.Tests/Attestation/Apple.cs +++ b/Tests/Fido2.Tests/Attestation/Apple.cs @@ -138,7 +138,7 @@ public async Task TestAppleCertMissingExtension() invalidX5cStrings[0] = Convert.ToBase64String(invalidCert); var trustPath = invalidX5cStrings - .Select(x => new X509Certificate2(Convert.FromBase64String(x))) + .Select(x => X509CertificateHelper.CreateFromRawData(Convert.FromBase64String(x))) .ToArray(); var x5c = new CborArray { @@ -160,7 +160,7 @@ public async Task TestAppleCertCorruptExtension() invalidX5cStrings[0] = Convert.ToBase64String(invalidCert); var trustPath = invalidX5cStrings - .Select(x => new X509Certificate2(Convert.FromBase64String(x))) + .Select(x => X509CertificateHelper.CreateFromRawData(Convert.FromBase64String(x))) .ToArray(); var x5c = new CborArray { @@ -179,7 +179,7 @@ public async Task TestAppleCertCorruptExtension() public async Task TestAppleInvalidNonce() { var trustPath = validX5cStrings - .Select(x => new X509Certificate2(Convert.FromBase64String(x))) + .Select(x => X509CertificateHelper.CreateFromRawData(Convert.FromBase64String(x))) .ToArray(); var x5c = new CborArray { @@ -211,7 +211,7 @@ public async Task TestApplePublicKeyMismatch() var invalidX5cStrings = StackAllocSha256(authData, clientDataJson); var trustPath = invalidX5cStrings - .Select(x => new X509Certificate2(Convert.FromBase64String(x))) + .Select(x => X509CertificateHelper.CreateFromRawData(Convert.FromBase64String(x))) .ToArray(); var X5c = new CborArray { diff --git a/Tests/Fido2.Tests/Converters/FidoEnumConverterTests.cs b/Tests/Fido2.Tests/Converters/FidoEnumConverterTests.cs index e07e691e0..356817933 100644 --- a/Tests/Fido2.Tests/Converters/FidoEnumConverterTests.cs +++ b/Tests/Fido2.Tests/Converters/FidoEnumConverterTests.cs @@ -33,8 +33,11 @@ public void CorrectlyFallsBackToMemberName() public void CorrectlyDeserializesNumericEnumValue() { Assert.Equal(CredentialProtectionPolicy.UserVerificationRequired, JsonSerializer.Deserialize($"{CredentialProtectionPolicy.UserVerificationRequired:d}")); + +#if NET8_0 Assert.Throws(() => JsonSerializer.Deserialize($"99")); Assert.Throws(() => JsonSerializer.Deserialize($"99.7")); +#endif } [Fact] diff --git a/Tests/Fido2.Tests/CryptoUtilsTests.cs b/Tests/Fido2.Tests/CryptoUtilsTests.cs index 505f75db7..2cd94aff3 100644 --- a/Tests/Fido2.Tests/CryptoUtilsTests.cs +++ b/Tests/Fido2.Tests/CryptoUtilsTests.cs @@ -13,7 +13,7 @@ public void TestCertInCRLFalseCase() byte[] crl = Convert.FromBase64String("MIIB7DCCAZICAQEwCgYIKoZIzj0EAwIwbzELMAkGA1UEBhMCVVMxFjAUBgNVBAoMDUZJRE8gQWxsaWFuY2UxLzAtBgNVBAsMJkZBS0UgTWV0YWRhdGEgMyBCTE9CIElOVEVSTUVESUFURSBGQUtFMRcwFQYDVQQDDA5GQUtFIENBLTEgRkFLRRcNMTgwMjAxMDAwMDAwWhcNMjIwMjAxMDAwMDAwWjCBwDAuAg8ELS9CzLtxNJTOFTHXiV8XDTE2MDQxMzAwMDAwMFowDDAKBgNVHRUEAwoBADAuAg8ExejzukpclaXnFLGvxDEXDTE3MDMyNTAwMDAwMFowDDAKBgNVHRUEAwoBADAuAg8Er13ouX8KNf3VOr4OzQEXDTE2MDMwMTAwMDAwMFowDDAKBgNVHRUEAwoBADAuAg8EgGdJ3jB7vVF1om1z9fMXDTE4MDMyNTAwMDAwMFowDDAKBgNVHRUEAwoBAKAvMC0wCgYDVR0UBAMCAQEwHwYDVR0jBBgwFoAUo4SnpGSiiTwKvxeeog3wEhqm18swCgYIKoZIzj0EAwIDSAAwRQIgDgtshLf5/82mHcOgl2TsUizHsjLCslmQVDdSPcolS8UCIQDa5MSjQbX1v8MkCPpzxbrBb1I510aSTuZB0RUuwPnOYw=="); - var cert = new X509Certificate2(certBytes); + var cert = X509CertificateHelper.CreateFromRawData(certBytes); Assert.False(CryptoUtils.IsCertInCRL(crl, cert)); } @@ -25,7 +25,7 @@ public void TestCertInCRLTrueCase() byte[] crl = Convert.FromBase64String("MIIB7DCCAZICAQEwCgYIKoZIzj0EAwIwbzELMAkGA1UEBhMCVVMxFjAUBgNVBAoMDUZJRE8gQWxsaWFuY2UxLzAtBgNVBAsMJkZBS0UgTWV0YWRhdGEgMyBCTE9CIElOVEVSTUVESUFURSBGQUtFMRcwFQYDVQQDDA5GQUtFIENBLTEgRkFLRRcNMTgwMjAxMDAwMDAwWhcNMjIwMjAxMDAwMDAwWjCBwDAuAg8ELS9CzLtxNJTOFTHXiV8XDTE2MDQxMzAwMDAwMFowDDAKBgNVHRUEAwoBADAuAg8ExejzukpclaXnFLGvxDEXDTE3MDMyNTAwMDAwMFowDDAKBgNVHRUEAwoBADAuAg8Er13ouX8KNf3VOr4OzQEXDTE2MDMwMTAwMDAwMFowDDAKBgNVHRUEAwoBADAuAg8EgGdJ3jB7vVF1om1z9fMXDTE4MDMyNTAwMDAwMFowDDAKBgNVHRUEAwoBAKAvMC0wCgYDVR0UBAMCAQEwHwYDVR0jBBgwFoAUo4SnpGSiiTwKvxeeog3wEhqm18swCgYIKoZIzj0EAwIDSAAwRQIgDgtshLf5/82mHcOgl2TsUizHsjLCslmQVDdSPcolS8UCIQDa5MSjQbX1v8MkCPpzxbrBb1I510aSTuZB0RUuwPnOYw=="); - var cert = new X509Certificate2(certBytes); + var cert = X509CertificateHelper.CreateFromRawData(certBytes); Assert.True(CryptoUtils.IsCertInCRL(crl, cert)); } @@ -35,15 +35,15 @@ public void TestValidateTrustChainRootAnchor() { var attestationRootCertificates = new X509Certificate2[3] { - new X509Certificate2(Convert.FromBase64String("MIIBfjCCASWgAwIBAgIBATAKBggqhkjOPQQDAjAXMRUwEwYDVQQDDAxGVCBGSURPIDAyMDAwIBcNMTYwNTAxMDAwMDAwWhgPMjA1MDA1MDEwMDAwMDBaMBcxFTATBgNVBAMMDEZUIEZJRE8gMDIwMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNBmrRqVOxztTJVN19vtdqcL7tKQeol2nnM2/yYgvksZnr50SKbVgIEkzHQVOu80LVEE3lVheO1HjggxAlT6o4WjYDBeMB0GA1UdDgQWBBRJFWQt1bvG3jM6XgmV/IcjNtO/CzAfBgNVHSMEGDAWgBRJFWQt1bvG3jM6XgmV/IcjNtO/CzAMBgNVHRMEBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAgNHADBEAiAwfPqgIWIUB+QBBaVGsdHy0s5RMxlkzpSX/zSyTZmUpQIgB2wJ6nZRM8oX/nA43Rh6SJovM2XwCCH//+LirBAbB0M=")), - new X509Certificate2(Convert.FromBase64String("MIIB2DCCAX6gAwIBAgIQFZ97ws2JGPEoa5NI+p8z1jAKBggqhkjOPQQDAjBLMQswCQYDVQQGEwJDTjEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxHTAbBgNVBAMMFEZlaXRpYW4gRklETyBSb290IENBMCAXDTE4MDQwMTAwMDAwMFoYDzIwNDgwMzMxMjM1OTU5WjBLMQswCQYDVQQGEwJDTjEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxHTAbBgNVBAMMFEZlaXRpYW4gRklETyBSb290IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnfAKbjvMX1Ey1b6k+WQQdNVMt9JgGWyJ3PvM4BSK5XqTfo++0oAj/4tnwyIL0HFBR9St+ktjqSXDfjiXAurs86NCMEAwHQYDVR0OBBYEFNGhmE2Bf8O5a/YHZ71QEv6QRfFUMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMCA0gAMEUCIQC3sT1lBjGeF+xKTpzV1KYU2ckahTd4mLJyzYOhaHv4igIgD2JYkfyH5Q4Bpo8rroO0It7oYjF2kgy/eSZ3U9Glaqw=")), - new X509Certificate2(Convert.FromBase64String("MIIB2DCCAX6gAwIBAgIQGBUrQbdDrm20FZnDsX2CBTAKBggqhkjOPQQDAjBLMQswCQYDVQQGEwJVUzEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxHTAbBgNVBAMMFEZlaXRpYW4gRklETyBSb290IENBMCAXDTE4MDQwMTAwMDAwMFoYDzIwNDgwMzMxMjM1OTU5WjBLMQswCQYDVQQGEwJVUzEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxHTAbBgNVBAMMFEZlaXRpYW4gRklETyBSb290IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsFYEEhiJuqqnMgQjSiivBjV7DGCTf4XBBH/B7uvZsKxXShF0L8uDISWUvcExixRs6gB3oldSrjox6L8T94NOzqNCMEAwHQYDVR0OBBYEFEu9hyYRrRyJzwRYvnDSCIxrFiO3MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMCA0gAMEUCIDHSb2mbNDAUNXvpPU0oWKeNye0fQ2l9D01AR2+sLZdhAiEAo3wz684IFMVsCCRmuJqxH6FQRESNqezuo1E+KkGxWuM=")) + X509CertificateHelper.CreateFromRawData(Convert.FromBase64String("MIIBfjCCASWgAwIBAgIBATAKBggqhkjOPQQDAjAXMRUwEwYDVQQDDAxGVCBGSURPIDAyMDAwIBcNMTYwNTAxMDAwMDAwWhgPMjA1MDA1MDEwMDAwMDBaMBcxFTATBgNVBAMMDEZUIEZJRE8gMDIwMDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNBmrRqVOxztTJVN19vtdqcL7tKQeol2nnM2/yYgvksZnr50SKbVgIEkzHQVOu80LVEE3lVheO1HjggxAlT6o4WjYDBeMB0GA1UdDgQWBBRJFWQt1bvG3jM6XgmV/IcjNtO/CzAfBgNVHSMEGDAWgBRJFWQt1bvG3jM6XgmV/IcjNtO/CzAMBgNVHRMEBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAgNHADBEAiAwfPqgIWIUB+QBBaVGsdHy0s5RMxlkzpSX/zSyTZmUpQIgB2wJ6nZRM8oX/nA43Rh6SJovM2XwCCH//+LirBAbB0M=")), + X509CertificateHelper.CreateFromRawData(Convert.FromBase64String("MIIB2DCCAX6gAwIBAgIQFZ97ws2JGPEoa5NI+p8z1jAKBggqhkjOPQQDAjBLMQswCQYDVQQGEwJDTjEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxHTAbBgNVBAMMFEZlaXRpYW4gRklETyBSb290IENBMCAXDTE4MDQwMTAwMDAwMFoYDzIwNDgwMzMxMjM1OTU5WjBLMQswCQYDVQQGEwJDTjEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxHTAbBgNVBAMMFEZlaXRpYW4gRklETyBSb290IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnfAKbjvMX1Ey1b6k+WQQdNVMt9JgGWyJ3PvM4BSK5XqTfo++0oAj/4tnwyIL0HFBR9St+ktjqSXDfjiXAurs86NCMEAwHQYDVR0OBBYEFNGhmE2Bf8O5a/YHZ71QEv6QRfFUMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMCA0gAMEUCIQC3sT1lBjGeF+xKTpzV1KYU2ckahTd4mLJyzYOhaHv4igIgD2JYkfyH5Q4Bpo8rroO0It7oYjF2kgy/eSZ3U9Glaqw=")), + X509CertificateHelper.CreateFromRawData(Convert.FromBase64String("MIIB2DCCAX6gAwIBAgIQGBUrQbdDrm20FZnDsX2CBTAKBggqhkjOPQQDAjBLMQswCQYDVQQGEwJVUzEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxHTAbBgNVBAMMFEZlaXRpYW4gRklETyBSb290IENBMCAXDTE4MDQwMTAwMDAwMFoYDzIwNDgwMzMxMjM1OTU5WjBLMQswCQYDVQQGEwJVUzEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxHTAbBgNVBAMMFEZlaXRpYW4gRklETyBSb290IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsFYEEhiJuqqnMgQjSiivBjV7DGCTf4XBBH/B7uvZsKxXShF0L8uDISWUvcExixRs6gB3oldSrjox6L8T94NOzqNCMEAwHQYDVR0OBBYEFEu9hyYRrRyJzwRYvnDSCIxrFiO3MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMCA0gAMEUCIDHSb2mbNDAUNXvpPU0oWKeNye0fQ2l9D01AR2+sLZdhAiEAo3wz684IFMVsCCRmuJqxH6FQRESNqezuo1E+KkGxWuM=")) }; var trustPath = new X509Certificate2[2] { - new X509Certificate2(Convert.FromBase64String("MIICQzCCAemgAwIBAgIQHfK1WlHcS2iFo9meaX/tFjAKBggqhkjOPQQDAjBJMQswCQYDVQQGEwJVUzEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxGzAZBgNVBAMMEkZlaXRpYW4gRklETyBDQSAwMzAgFw0xODEyMjUwMDAwMDBaGA8yMDMzMTIyNDIzNTk1OVowcDELMAkGA1UEBhMCVVMxHTAbBgNVBAoMFEZlaXRpYW4gVGVjaG5vbG9naWVzMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0aW9uMR4wHAYDVQQDDBVGVCBCaW9QYXNzIEZJRE8yIDA0NzAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS62hIbyenH9WPnzYHehaBR3C7qswomZkaPzGyUlFRiJIMo3uITeImFOFfNcDuOzoq1wcXXGTmEtEtxF2wo9noko4GJMIGGMB0GA1UdDgQWBBSBI1XoLDY1/HJaba+W32nxhxp3WjAfBgNVHSMEGDAWgBRBt/xNdcqO0p8s0xebzYNRinnYqTAMBgNVHRMBAf8EAjAAMBMGCysGAQQBguUcAgEBBAQDAgRwMCEGCysGAQQBguUcAQEEBBIEEBLe10VL7UfUq6rnE/UdY5MwCgYIKoZIzj0EAwIDSAAwRQIhAI6GSVi10r673uqtso+2oB6f5S5gE0ff44t3NcQ+TN9NAiAC/SCP+eKw1BnmcSgbxcQpYuWjBPMVDfqeg8pbmOdHKw==")), - new X509Certificate2(Convert.FromBase64String("MIIB+TCCAaCgAwIBAgIQGBUrQbdDrm20FZnDsX2CCDAKBggqhkjOPQQDAjBLMQswCQYDVQQGEwJVUzEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxHTAbBgNVBAMMFEZlaXRpYW4gRklETyBSb290IENBMCAXDTE4MDUyMDAwMDAwMFoYDzIwMzgwNTE5MjM1OTU5WjBJMQswCQYDVQQGEwJVUzEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxGzAZBgNVBAMMEkZlaXRpYW4gRklETyBDQSAwMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJts1KYQuj66rAszKKLfsOay91gO11vSvfcYd/dQfeTjpSNb55ffoLijQbRXspqE5Uj2NVylED61pjo2tpytOfijZjBkMB0GA1UdDgQWBBRBt/xNdcqO0p8s0xebzYNRinnYqTAfBgNVHSMEGDAWgBRLvYcmEa0cic8EWL5w0giMaxYjtzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAgNHADBEAiAnSuhaqHgV3Sds/OrwiqLNUWMmU8Lji9Vy7s5hSEg22AIgE1lIdBjq0N+QcZq995uOE4XWxBIrVUio3RAwgDn8KgI=")) + X509CertificateHelper.CreateFromRawData(Convert.FromBase64String("MIICQzCCAemgAwIBAgIQHfK1WlHcS2iFo9meaX/tFjAKBggqhkjOPQQDAjBJMQswCQYDVQQGEwJVUzEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxGzAZBgNVBAMMEkZlaXRpYW4gRklETyBDQSAwMzAgFw0xODEyMjUwMDAwMDBaGA8yMDMzMTIyNDIzNTk1OVowcDELMAkGA1UEBhMCVVMxHTAbBgNVBAoMFEZlaXRpYW4gVGVjaG5vbG9naWVzMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0aW9uMR4wHAYDVQQDDBVGVCBCaW9QYXNzIEZJRE8yIDA0NzAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS62hIbyenH9WPnzYHehaBR3C7qswomZkaPzGyUlFRiJIMo3uITeImFOFfNcDuOzoq1wcXXGTmEtEtxF2wo9noko4GJMIGGMB0GA1UdDgQWBBSBI1XoLDY1/HJaba+W32nxhxp3WjAfBgNVHSMEGDAWgBRBt/xNdcqO0p8s0xebzYNRinnYqTAMBgNVHRMBAf8EAjAAMBMGCysGAQQBguUcAgEBBAQDAgRwMCEGCysGAQQBguUcAQEEBBIEEBLe10VL7UfUq6rnE/UdY5MwCgYIKoZIzj0EAwIDSAAwRQIhAI6GSVi10r673uqtso+2oB6f5S5gE0ff44t3NcQ+TN9NAiAC/SCP+eKw1BnmcSgbxcQpYuWjBPMVDfqeg8pbmOdHKw==")), + X509CertificateHelper.CreateFromRawData(Convert.FromBase64String("MIIB+TCCAaCgAwIBAgIQGBUrQbdDrm20FZnDsX2CCDAKBggqhkjOPQQDAjBLMQswCQYDVQQGEwJVUzEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxHTAbBgNVBAMMFEZlaXRpYW4gRklETyBSb290IENBMCAXDTE4MDUyMDAwMDAwMFoYDzIwMzgwNTE5MjM1OTU5WjBJMQswCQYDVQQGEwJVUzEdMBsGA1UECgwURmVpdGlhbiBUZWNobm9sb2dpZXMxGzAZBgNVBAMMEkZlaXRpYW4gRklETyBDQSAwMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJts1KYQuj66rAszKKLfsOay91gO11vSvfcYd/dQfeTjpSNb55ffoLijQbRXspqE5Uj2NVylED61pjo2tpytOfijZjBkMB0GA1UdDgQWBBRBt/xNdcqO0p8s0xebzYNRinnYqTAfBgNVHSMEGDAWgBRLvYcmEa0cic8EWL5w0giMaxYjtzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAgNHADBEAiAnSuhaqHgV3Sds/OrwiqLNUWMmU8Lji9Vy7s5hSEg22AIgE1lIdBjq0N+QcZq995uOE4XWxBIrVUio3RAwgDn8KgI=")) }; Assert.True(CryptoUtils.ValidateTrustChain(trustPath, attestationRootCertificates)); Assert.False(CryptoUtils.ValidateTrustChain(trustPath, trustPath)); @@ -59,10 +59,10 @@ public void TestValidateTrustChainSubAnchor() return; byte[] attRootCertBytes = Convert.FromBase64String("MIIDCDCCAq+gAwIBAgIQQAFqUNTHZ8kBN8u/bCk+xDAKBggqhkjOPQQDAjBrMQswCQYDVQQGEwJVUzETMBEGA1UEChMKSElEIEdsb2JhbDEiMCAGA1UECxMZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjEjMCEGA1UEAxMaRklETyBBdHRlc3RhdGlvbiBSb290IENBIDEwHhcNMTkwNDI0MTkzMTIzWhcNNDQwNDI3MTkzMTIzWjBmMQswCQYDVQQGEwJVUzETMBEGA1UEChMKSElEIEdsb2JhbDEiMCAGA1UECxMZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjEeMBwGA1UEAxMVRklETyBBdHRlc3RhdGlvbiBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4nK9ctzk6GEGFNQBcrnBBmWU+dCnuHQAARrB2Eyc8MbsljkSFhZtfz/Rw6SuVIDk5VakDzrKBAOJ9v0Rvg/406OCATgwggE0MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMIGEBggrBgEFBQcBAQR4MHYwLgYIKwYBBQUHMAGGImh0dHA6Ly9oaWQuZmlkby5vY3NwLmlkZW50cnVzdC5jb20wRAYIKwYBBQUHMAKGOGh0dHA6Ly92YWxpZGF0aW9uLmlkZW50cnVzdC5jb20vcm9vdHMvSElERklET1Jvb3RjYTEucDdjMB8GA1UdIwQYMBaAFB2m3iwWSYHvWTHbJiHAyKDp+CSjMEcGA1UdHwRAMD4wPKA6oDiGNmh0dHA6Ly92YWxpZGF0aW9uLmlkZW50cnVzdC5jb20vY3JsL0hJREZJRE9Sb290Y2ExLmNybDAdBgNVHQ4EFgQUDLCbuLslcclrOZIz57Fu0imSMQ8wCgYIKoZIzj0EAwIDRwAwRAIgDCW5IrbjEI/y35lPjx9a+/sF4lPSoZdBHgFgTWC+8VICIEqs2SPzUHgHVh65Ajl1oIUmhh0C2lyR/Zdk7O3u1TIK"); - var attestationRootCertificates = new X509Certificate2[1] { new X509Certificate2(attRootCertBytes) }; + var attestationRootCertificates = new X509Certificate2[1] { X509CertificateHelper.CreateFromRawData(attRootCertBytes) }; byte[] attCert = Convert.FromBase64String("MIIDLjCCAtSgAwIBAgIQQAFs2JXwQcL5Eh4rnp2ASjAKBggqhkjOPQQDAjBmMQswCQYDVQQGEwJVUzETMBEGA1UEChMKSElEIEdsb2JhbDEiMCAGA1UECxMZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjEeMBwGA1UEAxMVRklETyBBdHRlc3RhdGlvbiBDQSAyMB4XDTE5MDgyODE0MTY0MFoXDTM5MDgyMzE0MTY0MFowaTELMAkGA1UEBhMCVVMxHzAdBgNVBAoTFkhJRCBHbG9iYWwgQ29ycG9yYXRpb24xIjAgBgNVBAsTGUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xFTATBgNVBAMTDENyZXNjZW5kb0tleTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAGouI654w6qbGonSTStO2cESYTo8Ezr8OJiPkMl02d6K6i44wXCKV2i+w+bpR6vgYQZ/cKQxMS4uGytqPRNPIejggFfMIIBWzAOBgNVHQ8BAf8EBAMCB4AwgYAGCCsGAQUFBwEBBHQwcjAuBggrBgEFBQcwAYYiaHR0cDovL2hpZC5maWRvLm9jc3AuaWRlbnRydXN0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL3ZhbGlkYXRpb24uaWRlbnRydXN0LmNvbS9jZXJ0cy9oaWRmaWRvY2EyLnA3YzAfBgNVHSMEGDAWgBQMsJu4uyVxyWs5kjPnsW7SKZIxDzAJBgNVHRMEAjAAMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly92YWxpZGF0aW9uLmlkZW50cnVzdC5jb20vY3JsL2hpZGZpZG9jYTIuY3JsMBMGCysGAQQBguUcAgEBBAQDAgQwMB0GA1UdDgQWBBR9h/lCWeTiMUhRS1tj31hBXaOurzAhBgsrBgEEAYLlHAEBBAQSBBBpLbVJeuVE1aHl3SCkk7cjMAoGCCqGSM49BAMCA0gAMEUCIQDpDa1ZbAfCTlBMiDUuB5XH8hnhZUF1JCuCmc+ShI4ZTwIga/ApAudL5R8HxOOHgk8AA/JpgCkMmYDQLVq0QF6oxrU="); - var trustPath = new X509Certificate2[1] { new X509Certificate2(attCert) }; + var trustPath = new X509Certificate2[1] { X509CertificateHelper.CreateFromRawData(attCert) }; Assert.False(0 == attestationRootCertificates[0].Issuer.CompareTo(attestationRootCertificates[0].Subject)); Assert.True(CryptoUtils.ValidateTrustChain(trustPath, attestationRootCertificates)); @@ -75,10 +75,10 @@ public void TestValidateTrustChainSubAnchor() public void TestValidateTrustChainSelf() { byte[] certBytes = Convert.FromBase64String("MIIBzTCCAXOgAwIBAgIJALS3SibGDXTPMAoGCCqGSM49BAMCMDsxIDAeBgNVBAMMF0dvVHJ1c3QgRklETzIgUm9vdCBDQSAxMRcwFQYDVQQKDA5Hb1RydXN0SUQgSW5jLjAeFw0xOTEyMDQwNjU5NDBaFw00OTExMjYwNjU5NDBaMDsxIDAeBgNVBAMMF0dvVHJ1c3QgRklETzIgUm9vdCBDQSAxMRcwFQYDVQQKDA5Hb1RydXN0SUQgSW5jLjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABA5mjYsjowAI0jnpi//CJ3KnzhGbTUmstNWqN78ioG1CTK9gPgPl9UiFOJO/v+FfFK+Pxv10c604dvlIDAbKw+ijYDBeMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSgWtY0nEcmPmGDLuCwceKeJPScozAfBgNVHSMEGDAWgBSgWtY0nEcmPmGDLuCwceKeJPScozAKBggqhkjOPQQDAgNIADBFAiAxoVs6qj7DX2xixCjjcDUdxBTJmSTLb0f1rRGwrABzTQIhAPt0P32qzAeepF4//tgzxqNoKkWDcaPPSXrg+xzrlVHw"); - var certs = new X509Certificate2[1] { new X509Certificate2(certBytes) }; + var certs = new X509Certificate2[1] { X509CertificateHelper.CreateFromRawData(certBytes) }; byte[] otherCertBytes = Convert.FromBase64String("MIIDRjCCAu2gAwIBAgIUZPhSDtxI5lg2qgy+7IGDJhGqPOgwCgYIKoZIzj0EAwIwgYcxCzAJBgNVBAYTAlRXMQ8wDQYDVQQIDAZUYWlwZWkxEjAQBgNVBAcMCVNvbWV3aGVyZTEWMBQGA1UECgwNV2lTRUNVUkUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5vcmcxGTAXBgNVBAMMEFdpU0VDVVJFIFJvb3QgQ0EwHhcNMjEwMTI4MDgyNzIwWhcNMzEwMTI2MDgyNzIwWjCBhzELMAkGA1UEBhMCVFcxDzANBgNVBAgMBlRhaXBlaTESMBAGA1UEBwwJU29tZXdoZXJlMRYwFAYDVQQKDA1XaVNFQ1VSRSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLm9yZzEZMBcGA1UEAwwQV2lTRUNVUkUgUm9vdCBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBiWvFaf/IhFMOWNqlweqr4GfO0mu/1B18J03OG+pSltRix9GjRojBya4LARyXMP8nw2Xh9PvwOBm9QedMC66XGjggEzMIIBLzAdBgNVHQ4EFgQUd+Yvj6I3Y8cKH3QRNLlC8/Op97cwgccGA1UdIwSBvzCBvIAUd+Yvj6I3Y8cKH3QRNLlC8/Op97ehgY2kgYowgYcxCzAJBgNVBAYTAlRXMQ8wDQYDVQQIDAZUYWlwZWkxEjAQBgNVBAcMCVNvbWV3aGVyZTEWMBQGA1UECgwNV2lTRUNVUkUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5vcmcxGTAXBgNVBAMMEFdpU0VDVVJFIFJvb3QgQ0GCFGT4Ug7cSOZYNqoMvuyBgyYRqjzoMAwGA1UdEwEB/wQCMAAwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL3d3dy5leGFtcGxlLm9yZy9leGFtcGxlX2NhLmNybDAKBggqhkjOPQQDAgNHADBEAiBf3p8LJ3PlfMsxTzWgjHaal6uzIo5tx3o+EUybdDY4ogIgV6nR1MUE1wKz1uC7/kENg/FpJOetFaJePcgoneEwsKA="); - var otherCerts = new X509Certificate2[1] { new X509Certificate2(otherCertBytes) }; + var otherCerts = new X509Certificate2[1] { X509CertificateHelper.CreateFromRawData(otherCertBytes) }; Assert.True(CryptoUtils.ValidateTrustChain(certs, certs)); Assert.False(CryptoUtils.ValidateTrustChain(certs, otherCerts)); diff --git a/nuget.config b/nuget.config index 6f121ee8b..e9efcab21 100644 --- a/nuget.config +++ b/nuget.config @@ -1,4 +1,4 @@ - +