public void FromArray() { int[] array = { 1, 2, 3 }; CborArray actual = CborArray.FromCollection(array); Assert.Equal(new CborArray(1, 2, 3), actual); }
public AndroidKey() { _attestationObject = new CborMap { { "fmt", "android-key" } }; X509Certificate2 attestnCert; using (var ecdsaAtt = ECDsa.Create(ECCurve.NamedCurves.nistP256)) { var attRequest = new CertificateRequest("CN=AndroidKeyTesting, OU=Authenticator Attestation, O=FIDO2-NET-LIB, C=US", ecdsaAtt, HashAlgorithmName.SHA256); attRequest.CertificateExtensions.Add(new X509Extension("1.3.6.1.4.1.11129.2.1.17", EncodeAttestationRecord(), false)); using (attestnCert = attRequest.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddDays(2))) { var X5c = new CborArray { attestnCert.RawData }; byte[] signature = SignData(COSE.KeyType.EC2, COSE.Algorithm.ES256, COSE.EllipticCurve.P256, ecdsa: ecdsaAtt); _attestationObject.Add("attStmt", new CborMap { { "alg", COSE.Algorithm.ES256 }, { "x5c", X5c }, { "sig", signature } }); } } }
public void ToArray() { CborArray array = new CborArray(1, 2, 3); int[] actual = array.ToCollection <int[]>(); Assert.Equal(new[] { 1, 2, 3 }, actual); }
public void ArrayComparison() { CborArray array1 = new CborArray(1, 2, 3); CborArray array2 = new CborArray(1, 2, 3); Assert.Equal(0, array1.CompareTo(array2)); Assert.Equal(array1, array2); }
public void WriteEmptyArray() { const string hexBuffer = "80"; CborArray array = new CborArray(); Helper.TestWrite(array, hexBuffer); }
public void ToList() { CborArray array = new CborArray(1, 2, 3); List <int> actual = array.ToCollection <List <int> >(); Assert.Equal(new List <int> { 1, 2, 3 }, actual); }
public void FromList() { List <int> list = new List <int> { 1, 2, 3 }; CborArray actual = CborArray.FromCollection(list); Assert.Equal(new CborArray(1, 2, 3), actual); }
public void ReadObject() { const string hexBuffer = "A666737472696E6763666F6F666E756D626572FB40283D70A3D70A3D64626F6F6CF5646E756C6CF6656172726179820102666F626A656374A162696401"; CborObject actualObject = Helper.Read <CborObject>(hexBuffer); Assert.NotNull(actualObject); // pairs Assert.Equal(6, actualObject.Count); // string Assert.True(actualObject.TryGetValue("string", out CborValue value)); Assert.Equal(CborValueType.String, value.Type); Assert.IsType <CborString>(value); Assert.Equal("foo", value.Value <string>()); // number Assert.True(actualObject.TryGetValue("number", out value)); Assert.Equal(CborValueType.Double, value.Type); Assert.IsType <CborDouble>(value); Assert.Equal(12.12, value.Value <double>(), 3); // bool Assert.True(actualObject.TryGetValue("bool", out value)); Assert.Equal(CborValueType.Boolean, value.Type); Assert.IsType <CborBoolean>(value); Assert.True(value.Value <bool>()); // null Assert.True(actualObject.TryGetValue("null", out value)); Assert.Equal(CborValueType.Null, value.Type); Assert.IsType <CborNull>(value); // array Assert.True(actualObject.TryGetValue("array", out value)); Assert.Equal(CborValueType.Array, value.Type); Assert.IsType <CborArray>(value); CborArray CborArray = (CborArray)value; Assert.Equal(2, CborArray.Count); Assert.Equal(1, CborArray[0].Value <double>()); Assert.Equal(2, CborArray[1].Value <double>()); // object Assert.True(actualObject.TryGetValue("object", out value)); Assert.Equal(CborValueType.Object, value.Type); Assert.IsType <CborObject>(value); CborObject cborObject = (CborObject)value; Assert.True(cborObject.TryGetValue("id", out value)); Assert.Equal(CborValueType.Positive, value.Type); Assert.Equal(1, value.Value <int>()); }
public void TestAppleX5cCountNotOne() { var emptyX5c = new CborArray { new byte[0], new byte[0] }; var attStmt = (CborMap)_attestationObject["attStmt"]; attStmt.Set("x5c", emptyX5c); var ex = Assert.ThrowsAsync <Fido2VerificationException>(() => MakeAttestationResponse()); Assert.Equal("Malformed x5c in Apple attestation", ex.Result.Message); }
public void TestAndroidKeyInvalidPublicKey() { var attestnCert = (byte[])_attestationObject["attStmt"]["x5c"][0]; attestnCert[0] ^= 0xff; var X5c = new CborArray { attestnCert }; var attStmt = (CborMap)_attestationObject["attStmt"]; attStmt.Set("x5c", X5c); var ex = Assert.ThrowsAsync <Fido2VerificationException>(() => MakeAttestationResponse()); Assert.StartsWith("Failed to extract public key from android key: ", ex.Result.Message); }
public FidoU2f() { _aaguid = Guid.Empty; _attestationObject.Add("fmt", "fido-u2f"); X509Certificate2 attestnCert; using (var ecdsaAtt = ECDsa.Create(ECCurve.NamedCurves.nistP256)) { var attRequest = new CertificateRequest("CN=U2FTesting, OU=Authenticator Attestation, O=FIDO2-NET-LIB, C=US", ecdsaAtt, HashAlgorithmName.SHA256); attRequest.CertificateExtensions.Add(notCAExt); using (attestnCert = attRequest.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddDays(2))) { var X5c = new CborArray { attestnCert.RawData }; var ecparams = ecdsaAtt.ExportParameters(true); _credentialPublicKey = Fido2Tests.MakeCredentialPublicKey(COSE.KeyType.EC2, COSE.Algorithm.ES256, COSE.EllipticCurve.P256, ecparams.Q.X, ecparams.Q.Y); var x = (byte[])_credentialPublicKey.GetCborObject()[COSE.KeyTypeParameter.X]; var y = (byte[])_credentialPublicKey.GetCborObject()[COSE.KeyTypeParameter.Y]; byte[] publicKeyU2F = DataHelper.Concat(new byte[1] { 0x4 }, x, y); byte[] verificationData = DataHelper.Concat( new byte[1] { 0x00 }, _rpIdHash, _clientDataHash, _credentialID, publicKeyU2F ); byte[] signature = Fido2Tests.SignData(COSE.KeyType.EC2, COSE.Algorithm.ES256, verificationData, ecdsaAtt, null, null); _attestationObject.Add("attStmt", new CborMap { { "x5c", X5c }, { "sig", signature } }); } } }
public void TestAppleInvalidNonce() { var trustPath = validX5cStrings .Select(x => new X509Certificate2(Convert.FromBase64String(x))) .ToArray(); var x5c = new CborArray { trustPath[0].RawData, trustPath[1].RawData }; var attStmt = (CborMap)_attestationObject["attStmt"]; attStmt.Set("x5c", x5c); var ex = Assert.ThrowsAsync <Fido2VerificationException>(() => MakeAttestationResponse()); Assert.Equal("Mismatch between nonce and credCert attestation extension in Apple attestation", ex.Result.Message); }
public void WriteArray() { string hexBuffer = "8663666F6FFB40283D70A3D70A3DF5F6820102A162696401"; CborArray array = new CborArray { "foo", 12.12, true, null, new CborArray { 1, 2 }, new CborObject { { "id", 1 } } }; Helper.TestWrite(array, hexBuffer); }
public void TestAppleCertCorruptExtension() { var invalidX5cStrings = validX5cStrings; var invalidCert = Convert.FromBase64String(invalidX5cStrings[0]); invalidCert[429] = 0x03; invalidX5cStrings[0] = Convert.ToBase64String(invalidCert); var trustPath = invalidX5cStrings .Select(x => new X509Certificate2(Convert.FromBase64String(x))) .ToArray(); var x5c = new CborArray { trustPath[0].RawData, trustPath[1].RawData }; var attStmt = (CborMap)_attestationObject["attStmt"]; attStmt.Set("x5c", x5c); var ex = Assert.ThrowsAsync <Fido2VerificationException>(() => MakeAttestationResponse()); Assert.Equal("Apple attestation extension has invalid data", ex.Result.Message); }
public void TestAppleCertMissingExtension() { var invalidX5cStrings = validX5cStrings; var invalidCert = Convert.FromBase64String(invalidX5cStrings[0]); invalidCert[424] = 0x42; invalidX5cStrings[0] = Convert.ToBase64String(invalidCert); var trustPath = invalidX5cStrings .Select(x => new X509Certificate2(Convert.FromBase64String(x))) .ToArray(); var x5c = new CborArray { trustPath[0].RawData, trustPath[1].RawData }; var attStmt = (CborMap)_attestationObject["attStmt"]; attStmt.Set("x5c", x5c); var ex = Assert.ThrowsAsync <Fido2VerificationException>(() => MakeAttestationResponse()); Assert.Equal("Extension with OID 1.2.840.113635.100.8.2 not found on Apple attestation credCert", ex.Result.Message); }
public async Task TestApplePublicKeyMismatch() { var cpkBytes = new byte[] { 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x79, 0xfe, 0x59, 0x08, 0xbb, 0x51, 0x29, 0xc8, 0x09, 0x38, 0xb7, 0x54, 0xc0, 0x4d, 0x2b, 0x34, 0x0e, 0xfa, 0x66, 0x15, 0xb9, 0x87, 0x69, 0x8b, 0xf5, 0x9d, 0xa4, 0xe5, 0x3e, 0xa3, 0xe6, 0xfe, 0x22, 0x58, 0x20, 0xfb, 0x03, 0xda, 0xa1, 0x27, 0x0d, 0x58, 0x04, 0xe8, 0xab, 0x61, 0xc1, 0x5a, 0xac, 0xa2, 0x43, 0x5c, 0x7d, 0xbf, 0x36, 0x9d, 0x71, 0xca, 0x15, 0xc5, 0x23, 0xb0, 0x00, 0x4a, 0x1b, 0x75, 0xb7 }; _credentialPublicKey = new CredentialPublicKey(cpkBytes); var authData = new AuthenticatorData(_rpIdHash, _flags, _signCount, _acd, _exts).ToByteArray(); _attestationObject.Set("authData", new CborByteString(authData)); var clientData = new { type = "webauthn.create", challenge = _challenge, origin = "https://www.passwordless.dev", }; var clientDataJson = JsonSerializer.SerializeToUtf8Bytes(clientData); var invalidX5cStrings = StackAllocSha256(authData, clientDataJson); var trustPath = invalidX5cStrings .Select(x => new X509Certificate2(Convert.FromBase64String(x))) .ToArray(); var X5c = new CborArray { { trustPath[0].RawData }, { trustPath[1].RawData } }; ((CborMap)_attestationObject["attStmt"]).Set("x5c", X5c); var attestationResponse = new AuthenticatorAttestationRawResponse { Type = PublicKeyCredentialType.PublicKey, Id = new byte[] { 0xf1, 0xd0 }, RawId = new byte[] { 0xf1, 0xd0 }, Response = new AuthenticatorAttestationRawResponse.ResponseData() { AttestationObject = _attestationObject.Encode(), ClientDataJson = clientDataJson, } }; var origChallenge = new CredentialCreateOptions { Attestation = AttestationConveyancePreference.Direct, AuthenticatorSelection = new AuthenticatorSelection { AuthenticatorAttachment = AuthenticatorAttachment.CrossPlatform, RequireResidentKey = true, UserVerification = UserVerificationRequirement.Discouraged, }, Challenge = _challenge, ErrorMessage = "", PubKeyCredParams = new List <PubKeyCredParam>() { new PubKeyCredParam(COSE.Algorithm.ES256) }, Rp = new PublicKeyCredentialRpEntity("https://www.passwordless.dev", "6cc3c9e7967a.ngrok.io", ""), Status = "ok", User = new Fido2User { Name = "testuser", Id = Encoding.UTF8.GetBytes("testuser"), DisplayName = "Test User", }, Timeout = 60000, }; IsCredentialIdUniqueToUserAsyncDelegate callback = (args, cancellationToken) => { return(Task.FromResult(true)); }; IFido2 lib = new Fido2(new Fido2Configuration() { ServerDomain = "6cc3c9e7967a.ngrok.io", ServerName = "6cc3c9e7967a.ngrok.io", Origins = new HashSet <string> { "https://www.passwordless.dev" }, }); var credentialMakeResult = await lib.MakeNewCredentialAsync(attestationResponse, origChallenge, callback); }
public Apple() { validX5cStrings = new[] { "MIICRDCCAcmgAwIBAgIGAXUCfWGDMAoGCCqGSM49BAMCMEgxHDAaBgNVBAMME0FwcGxlIFdlYkF1dGhuIENBIDExEzARBgNVBAoMCkFwcGxlIEluYy4xEzARBgNVBAgMCkNhbGlmb3JuaWEwHhcNMjAxMDA3MDk0NjEyWhcNMjAxMDA4MDk1NjEyWjCBkTFJMEcGA1UEAwxANjEyNzZmYzAyZDNmZThkMTZiMzNiNTU0OWQ4MTkyMzZjODE3NDZhODNmMmU5NGE2ZTRiZWUxYzcwZjgxYjViYzEaMBgGA1UECwwRQUFBIENlcnRpZmljYXRpb24xEzARBgNVBAoMCkFwcGxlIEluYy4xEzARBgNVBAgMCkNhbGlmb3JuaWEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR5/lkIu1EpyAk4t1TATSs0DvpmFbmHaYv1naTlPqPm/vsD2qEnDVgE6KthwVqsokNcfb82nXHKFcUjsABKG3W3o1UwUzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIE8DAzBgkqhkiG92NkCAIEJjAkoSIEIJxgAhVAs+GYNN/jfsYkRcieGylPeSzka5QTwyMO84aBMAoGCCqGSM49BAMCA2kAMGYCMQDaHBjrI75xAF7SXzyF5zSQB/Lg9PjTdyye+w7stiqy84K6lmo8d3fIptYjLQx81bsCMQCvC8MSN+aewiaU0bMsdxRbdDerCJJj3xJb3KZwloevJ3daCmCcrZrAPYfLp2kDOsg=", "MIICNDCCAbqgAwIBAgIQViVTlcen+0Dr4ijYJghTtjAKBggqhkjOPQQDAzBLMR8wHQYDVQQDDBZBcHBsZSBXZWJBdXRobiBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTIwMDMxODE4MzgwMVoXDTMwMDMxMzAwMDAwMFowSDEcMBoGA1UEAwwTQXBwbGUgV2ViQXV0aG4gQ0EgMTETMBEGA1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIMuhy8mFJGBAiW59fzWu2N4tfVfP8sEW8c1mTR1/VSQRN+b/hkhF2XGmh3aBQs41FCDQBpDT7JNES1Ww+HPv8uYkf7AaWCBvvlsvHfIjd2vRqWu4d1RW1r6q5O+nAsmkaNmMGQwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBQm12TZxXjCWmfRp95rEtAbY/HG1zAdBgNVHQ4EFgQU666CxP+hrFtR1M8kYQUAvmO9d4gwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMQDdixo0gaX62du052V7hB4UTCe3W4dqQYbCsUdXUDNyJ+/lVEV+9kiVDGMuXEg+cMECMCyKYETcIB/P5ZvDTSkwwUh4Udlg7Wp18etKyr44zSW4l9DIBb7wx/eLB6VxxugOBw==" }; _attestationObject = new CborMap { { "fmt", "apple" } }; var(type, alg, crv) = Fido2Tests._validCOSEParameters[0]; X509Certificate2 root, attestnCert; DateTimeOffset notBefore = DateTimeOffset.UtcNow; DateTimeOffset notAfter = notBefore.AddDays(2); var attDN = new X500DistinguishedName("CN=attest.apple.com, OU=Apple Authenticator Attestation, O=FIDO2-NET-LIB, C=US"); using (var ecdsaRoot = ECDsa.Create()) { var rootRequest = new CertificateRequest(rootDN, ecdsaRoot, HashAlgorithmName.SHA256); rootRequest.CertificateExtensions.Add(caExt); ECCurve eCCurve = ECCurve.NamedCurves.nistP256; using (root = rootRequest.CreateSelfSigned( notBefore, notAfter)) using (var ecdsaAtt = ECDsa.Create(eCCurve)) { var attRequest = new CertificateRequest(attDN, ecdsaAtt, HashAlgorithmName.SHA256); byte[] serial = new byte[12]; RandomNumberGenerator.Fill(serial); using (X509Certificate2 publicOnly = attRequest.Create( root, notBefore, notAfter, serial)) { attestnCert = publicOnly.CopyWithPrivateKey(ecdsaAtt); } var ecparams = ecdsaAtt.ExportParameters(true); var cpk = new CborMap { { COSE.KeyCommonParameter.KeyType, type }, { COSE.KeyCommonParameter.Alg, alg }, { COSE.KeyTypeParameter.X, ecparams.Q.X }, { COSE.KeyTypeParameter.Y, ecparams.Q.Y }, { COSE.KeyTypeParameter.Crv, crv } }; var x = (byte[])cpk[COSE.KeyTypeParameter.X]; var y = (byte[])cpk[COSE.KeyTypeParameter.Y]; _credentialPublicKey = new CredentialPublicKey(cpk); var X5c = new CborArray { attestnCert.RawData, root.RawData }; _attestationObject.Add("attStmt", new CborMap { { "x5c", X5c } }); } } }
public void WriteInt32List(string hexBuffer, string value, Type expectedExceptionType) { CborArray array = new CborArray(value.Split(',').Select(s => (CborValue)int.Parse(s))); Helper.TestWrite(array, hexBuffer, expectedExceptionType); }
public void ReadArray() { string hexBuffer = "8663666F6FFB40283D70A3D70A3DF5F6820102A162696401"; CborArray actualArray = Helper.Read <CborArray>(hexBuffer); Assert.NotNull(actualArray); // values Assert.Equal(6, actualArray.Count); // string CborValue actualString = actualArray[0]; Assert.NotNull(actualString); Assert.Equal(CborValueType.String, actualString.Type); Assert.IsType <CborString>(actualString); Assert.Equal("foo", actualString.Value <string>()); // number CborValue actualNumber = actualArray[1]; Assert.NotNull(actualNumber); Assert.Equal(CborValueType.Double, actualNumber.Type); Assert.IsType <CborDouble>(actualNumber); Assert.Equal(12.12, actualNumber.Value <double>(), 3); // bool CborValue actualBool = actualArray[2]; Assert.NotNull(actualBool); Assert.Equal(CborValueType.Boolean, actualBool.Type); Assert.IsType <CborBoolean>(actualBool); Assert.True(actualBool.Value <bool>()); // null CborValue actualNull = actualArray[3]; Assert.NotNull(actualNull); Assert.Equal(CborValueType.Null, actualNull.Type); // array CborValue actualArrayValue = actualArray[4]; Assert.NotNull(actualArrayValue); Assert.Equal(CborValueType.Array, actualArrayValue.Type); Assert.IsType <CborArray>(actualArrayValue); CborArray CborArray = (CborArray)actualArrayValue; Assert.Equal(2, CborArray.Count); Assert.Equal(1, CborArray[0].Value <double>()); Assert.Equal(2, CborArray[1].Value <double>()); // object CborValue actualObject = actualArray[5]; Assert.NotNull(actualObject); Assert.Equal(CborValueType.Object, actualObject.Type); Assert.IsType <CborObject>(actualObject); CborObject cborObject = (CborObject)actualObject; Assert.True(cborObject.TryGetValue("id", out CborValue value)); Assert.Equal(CborValueType.Positive, value.Type); Assert.Equal(1, value.Value <int>()); }
public void ReadInt32List(string hexBuffer, string expectedValue, Type expectedExceptionType) { CborArray array = new CborArray(expectedValue.Split(',').Select(s => (CborValue)int.Parse(s))); Helper.TestRead(hexBuffer, array, expectedExceptionType); }