public void WrongCertificateThrowsError()
        {
			var options = new ECCertificateBuilderOptions
			{
				ECCurve = ECNamedCurves.P256,
				FullSubjectName = "CN=Test"
			};
			var cert = ECCertificateBuilder.CreateNewSigningCertificate(options);
			string headerJson;
	        var token = JsonWebToken.EncodeUsingECDSA(new {id = 1, org = 2}, cert, out headerJson);

			options = new ECCertificateBuilderOptions
			{
				ECCurve = ECNamedCurves.P256,
				FullSubjectName = "CN=Test"
			};
			cert = ECCertificateBuilder.CreateNewSigningCertificate(options);

            try
            {
	            string payloadJson;
	            JsonWebToken.DecodeUsingECDSA<object>(token, cert, out headerJson, out payloadJson);
            }
            catch (SignatureVerificationException ex)
            {
                Assert.AreEqual("Token does not match signature", ex.Message);
                return;
            }

            Assert.Fail();
        }
        public void ParseBackAndForthWorks()
        {
			var options = new ECCertificateBuilderOptions
			{
				ECCurve = ECNamedCurves.P256,
				FullSubjectName = "CN=Test"
			};
			var cert = ECCertificateBuilder.CreateNewSigningCertificate(options);

	        string headerJson;
	        var token = JsonWebToken.EncodeUsingECDSA(new {id = 1, org = 2}, cert, out headerJson);

	        string headerJsonDecoded;
	        string payloadJsonDecoded;

	        dynamic result = JsonWebToken.DecodeUsingECDSA<object>(token, cert, out headerJsonDecoded,
		        out payloadJsonDecoded);

            Assert.AreEqual(1, (int)result.id);
            Assert.AreEqual(2, (int)result.org);
			
			Assert.IsFalse(string.IsNullOrWhiteSpace(headerJsonDecoded));
	        Assert.IsTrue(string.Equals(headerJson, headerJsonDecoded));
			Assert.IsFalse(string.IsNullOrWhiteSpace(payloadJsonDecoded));
	        

        }
        public void CreateWithSha384Hash()
        {
            var options = new ECCertificateBuilderOptions
            {
                FullSubjectName = "CN=Test",
                HashingMethod = HashingMethods.Sha384
            };

            var cert = ECCertificateBuilder.CreateNewSigningCertificate(options);

            Assert.AreEqual("CN=Test", cert.Subject);
            Assert.AreEqual("sha384ECDSA", cert.SignatureAlgorithm.FriendlyName);
            Assert.IsTrue(cert.HasPrivateKey);
        }
        public void CreateWithP256Curve()
        {
            var options = new ECCertificateBuilderOptions
            {
                FullSubjectName = "CN=Test",
                ECCurve = ECNamedCurves.P256
            };

            var cert = ECCertificateBuilder.CreateNewSigningCertificate(options);

            Assert.AreEqual("CN=Test", cert.Subject);
            Assert.AreEqual("sha256ECDSA", cert.SignatureAlgorithm.FriendlyName);
            Assert.IsTrue(cert.HasPrivateKey);
        }
            public void P521CertificateCorrectlyParses()
            {
                var options = new ECCertificateBuilderOptions
                {
                    FullSubjectName = "CN=Test",
                    ECCurve = ECNamedCurves.P521
                };

                var cert = ECCertificateBuilder.CreateNewSigningCertificate(options);

                var cng = ECDSACertificateParser.ParsePublicCertificate(cert);

                Assert.IsNotNull(cng);
            }
        public void HeaderAndPayloadParsesCorrectly()
        {
			var options = new ECCertificateBuilderOptions
			{
				ECCurve = ECNamedCurves.P256,
				FullSubjectName = "CN=Test"
			};
			var cert = ECCertificateBuilder.CreateNewSigningCertificate(options);

	        string headerJson;
	        var token = JsonWebToken.EncodeUsingECDSA(
		        new {id = 1, org = 1},
		        cert,
		        new Dictionary<string, object> {{"alg", "ES256"}},
		        new JsonSerializerSettings(),
		        out headerJson);

            var bits = token.Split('.');

            Assert.AreEqual(3, bits.Length);
            Assert.AreEqual("eyJhbGciOiJFUzI1NiJ9", bits[0]);  // HEADER
            Assert.AreEqual("eyJpZCI6MSwib3JnIjoxfQ", bits[1]); // DATA
        }
        public void SurvivesExportImport()
        {
            var options = new ECCertificateBuilderOptions
            {
                FullSubjectName = "CN=Test",
                ECKeyName = "KeyTestTemp",
                HashingMethod = HashingMethods.Sha512
            };

            var cert = ECCertificateBuilder.CreateNewSigningCertificate(options);
            var data = cert.Export(X509ContentType.Pkcs12, "password");

            if (CngKey.Exists("KeyTestTemp"))
            {
                var objCngKey = CngKey.Open("KeyTestTemp");
                objCngKey.Delete();
            }

            var reloaded = new X509Certificate2(data, "password");
            ECDSACertificateParser.ParsePrivateCertificate(reloaded);
        }
        /// <summary>
        /// Create a ECDSA based certificate with the given options
        /// </summary>
        /// <param name="buildOptions">Allows for more advanced configuration</param>
        /// <returns>An exportable X509Certificate2 object (with private key)</returns>
        public static X509Certificate2 CreateNewSigningCertificate(ECCertificateBuilderOptions buildOptions)
        {
            if (buildOptions == null)
            {
                throw new ArgumentNullException("buildOptions");
            }

            string keyName = buildOptions.ECKeyName ?? "ECDSAKey";

            CngKey objCngKey = null;

            if (CngKey.Exists(keyName))
            {
                objCngKey = CngKey.Open(keyName);
                objCngKey.Delete();
            }

            var creationParameters = new CngKeyCreationParameters();

            creationParameters.ExportPolicy = CngExportPolicies.AllowExport;
            creationParameters.KeyUsage     = CngKeyUsages.Signing;

            CngAlgorithm keyAlg;

            switch (buildOptions.ECCurve ?? ECNamedCurves.P521)
            {
            case ECNamedCurves.P521:
                keyAlg = CngAlgorithm.ECDsaP521;
                break;

            case ECNamedCurves.P384:
                keyAlg = CngAlgorithm.ECDsaP384;
                break;

            case ECNamedCurves.P256:
                keyAlg = CngAlgorithm.ECDsaP256;
                break;

            default:
                throw new InvalidOperationException("Selected curve is not supported");
            }

            objCngKey = CngKey.Create(keyAlg, keyName, creationParameters);

            var name = new X500DistinguishedName(buildOptions.FullSubjectName);

            X509CertificateSignatureAlgorithm certAlg;

            switch (buildOptions.HashingMethod ?? HashingMethods.Sha256)
            {
            case HashingMethods.Sha1:
                certAlg = X509CertificateSignatureAlgorithm.ECDsaSha1;
                break;

            case HashingMethods.Sha256:
                certAlg = X509CertificateSignatureAlgorithm.ECDsaSha256;
                break;

            case HashingMethods.Sha384:
                certAlg = X509CertificateSignatureAlgorithm.ECDsaSha384;
                break;

            case HashingMethods.Sha512:
                certAlg = X509CertificateSignatureAlgorithm.ECDsaSha512;
                break;

            default:
                throw new InvalidOperationException("Selected hashing method is not supported");
            }

            var options = new X509CertificateCreationParameters(name)
            {
                SignatureAlgorithm = certAlg,
                TakeOwnershipOfKey = true
            };

            return(objCngKey.CreateSelfSignedCertificate(options));
        }
        public void ECDSAKeySizeDoesNotMatchThrowsError()
        {
	        var options = new ECCertificateBuilderOptions
	        {
		        FullSubjectName = "CN=Test",
		        ECCurve = ECNamedCurves.P521,
		        HashingMethod = HashingMethods.Sha256,
		        ECKeyName = "ECDSA_Test" 
	        };
			var cert = ECCertificateBuilder.CreateNewSigningCertificate(options);
			string headerJson;
	        var token = JsonWebToken.EncodeUsingECDSA(new {id = 1, org = 2}, cert, out headerJson);

            cert = ECCertificateBuilder.CreateNewSigningCertificate(new ECCertificateBuilderOptions { ECCurve = ECNamedCurves.P256, FullSubjectName = "CN=Test" });

            try
            {
	            string payloadJson;
	            JsonWebToken.DecodeUsingECDSA<object>(token, cert, out headerJson, out payloadJson);
            }
            catch (SignatureVerificationException ex)
            {
                Assert.AreEqual("Key size does not match: ES256 vs ES521", ex.Message);
                return;
            }

            Assert.Fail();
        }
        public void UnknownJWTAlgorithmThrowsError()
        {
			var options = new ECCertificateBuilderOptions
			{
				ECCurve = ECNamedCurves.P256,

				FullSubjectName = "CN=Test"
			};
			var cert = ECCertificateBuilder.CreateNewSigningCertificate(options);
			string headerJson;
	        var token = JsonWebToken.EncodeUsingECDSA(new {id = 1, org = 2}, cert, out headerJson);
            var split = token.Split('.');
            split[0] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSU0EifQ";  // switch header
            token = string.Join(".", split);

            try
            {
	            string payloadJson;
	            JsonWebToken.DecodeUsingECDSA<object>(token, cert, out headerJson, out payloadJson);
            }
            catch (SignatureVerificationException ex)
            {
                Assert.AreEqual("Unsupported signing algorithm: RSA", ex.Message);
                return;
            }

            Assert.Fail();
        }
        /// <summary>
        /// Create a ECDSA based certificate with the given options
        /// </summary>
        /// <param name="buildOptions">Allows for more advanced configuration</param>
        /// <returns>An exportable X509Certificate2 object (with private key)</returns>
        public static X509Certificate2 CreateNewSigningCertificate(ECCertificateBuilderOptions buildOptions)
        {
            if(buildOptions == null)
            {
                throw new ArgumentNullException("buildOptions");
            }

            string keyName = buildOptions.ECKeyName ?? "ECDSAKey";

            CngKey objCngKey = null;
            if (CngKey.Exists(keyName))
            {
                objCngKey = CngKey.Open(keyName);
                objCngKey.Delete();
            }

            var creationParameters = new CngKeyCreationParameters();
            creationParameters.ExportPolicy = CngExportPolicies.AllowExport;
            creationParameters.KeyUsage = CngKeyUsages.Signing;

            CngAlgorithm keyAlg;
            switch(buildOptions.ECCurve ?? ECNamedCurves.P521)
            {
                case ECNamedCurves.P521:
                    keyAlg = CngAlgorithm.ECDsaP521;
                    break;
                case ECNamedCurves.P384:
                    keyAlg = CngAlgorithm.ECDsaP384;
                    break;
                case ECNamedCurves.P256:
                    keyAlg = CngAlgorithm.ECDsaP256;
                    break;
                default:
                    throw new InvalidOperationException("Selected curve is not supported");
            }

            objCngKey = CngKey.Create(keyAlg, keyName, creationParameters);

            var name = new X500DistinguishedName(buildOptions.FullSubjectName);

            X509CertificateSignatureAlgorithm certAlg;
            switch(buildOptions.HashingMethod ?? HashingMethods.Sha256)
            {
                case HashingMethods.Sha1:
                    certAlg = X509CertificateSignatureAlgorithm.ECDsaSha1;
                    break;
                case HashingMethods.Sha256:
                    certAlg = X509CertificateSignatureAlgorithm.ECDsaSha256;
                    break;
                case HashingMethods.Sha384:
                    certAlg = X509CertificateSignatureAlgorithm.ECDsaSha384;
                    break;
                case HashingMethods.Sha512:
                    certAlg = X509CertificateSignatureAlgorithm.ECDsaSha512;
                    break;
                default:
                    throw new InvalidOperationException("Selected hashing method is not supported");
            }

            var options = new X509CertificateCreationParameters(name)
            {
                SignatureAlgorithm = certAlg,
                TakeOwnershipOfKey = true
            };

            return objCngKey.CreateSelfSignedCertificate(options);
        }