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>());
        }
Example #9
0
        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);
        }
Example #11
0
        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 }
                    });
                }
            }
        }
Example #12
0
        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);
        }
Example #14
0
        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);
        }
Example #15
0
        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);
        }
Example #16
0
        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);
        }
Example #17
0
        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);
        }