public async Task WhenSignatureCreationIsInTheFuture_ButInsideClockSkew_IsValid()
        {
            var request = new HttpRequestMessage {
                RequestUri = new Uri("https://httpbin.org/post"),
                Method     = HttpMethod.Post,
                Content    = new StringContent("{'id':42}", Encoding.UTF8, MediaTypeNames.Application.Json),
                Headers    =
                {
                    { "Dalion-App-Id", "ringor" }
                }
            };

            var requestSigner = _requestSignerFactory.Create(
                "e0e8dcd638334c409e1b88daf821d135",
                new SigningSettings {
                SignatureAlgorithm  = SignatureAlgorithm.CreateForSigning("yumACY64r%hm"),
                DigestHashAlgorithm = HashAlgorithmName.SHA256,
                Expires             = TimeSpan.FromMinutes(1),
                Headers             = new[] {
                    (HeaderName)"Dalion-App-Id"
                }
            });
            await requestSigner.Sign(request);

            var receivedRequest = await request.ToServerSideHttpRequest();

            _options.OnSignatureParsed = (httpRequest, signature) => {
                signature.Created = signature.Created.Value.AddSeconds(55);
                signature.Expires = signature.Created.Value.AddMinutes(1);
                return(Task.CompletedTask);
            };

            var verificationResult = await _verifier.VerifySignature(receivedRequest, _options);

            if (verificationResult is RequestSignatureVerificationResultSuccess successResult)
            {
                var simpleClaims = successResult.Principal.Claims.Select(c => new { c.Type, c.Value }).ToList();
                var claimsString = string.Join(", ", simpleClaims.Select(c => $"{{type:{c.Type},value:{c.Value}}}"));
                _output.WriteLine("Request signature verification succeeded: {0}", claimsString);
            }
            else if (verificationResult is RequestSignatureVerificationResultFailure failureResult)
            {
                _output.WriteLine("Request signature verification failed: {0}", failureResult.Failure);
                throw new SignatureVerificationException(failureResult.Failure.ToString());
            }
        }
예제 #2
0
        public async Task ExpiresIsOptional()
        {
            var request = new HttpRequestMessage {
                RequestUri = new Uri("https://httpbin.org/post"),
                Method     = HttpMethod.Post,
                Content    = new StringContent("{'id':42}", Encoding.UTF8, MediaTypeNames.Application.Json),
                Headers    =
                {
                    { "Dalion-App-Id", "ringor" }
                }
            };

            var requestSigner = _requestSignerFactory.Create(
                new KeyId("e0e8dcd638334c409e1b88daf821d135"),
                new SigningSettings {
                SignatureAlgorithm  = SignatureAlgorithm.CreateForSigning("yumACY64r%hm"),
                DigestHashAlgorithm = HashAlgorithmName.SHA256,
                Expires             = TimeSpan.FromMinutes(1),
                Headers             = new[] {
                    (HeaderName)"Dalion-App-Id",
                    HeaderName.PredefinedHeaderNames.Date,
                    HeaderName.PredefinedHeaderNames.Created,
                    HeaderName.PredefinedHeaderNames.Expires
                },
                Events =
                {
                    OnSigningStringComposed    = (HttpRequestMessage requestToSign,        ref string signingString) => {
                        var signingStringRegEx = new Regex(@"\(expires\): ([0-9]+)\n",     RegexOptions.Compiled);
                        signingString          = signingStringRegEx.Replace(signingString, string.Empty); // Remove (expires) from signing string
                        return(Task.CompletedTask);
                    },
                    OnSignatureCreated         = (requestToSign,                           signature, settings) =>      {
                        // Exclude expires header and value
                        signature.Expires = null;
                        signature.Headers = signature.Headers.Where(_ => _ != HeaderName.PredefinedHeaderNames.Expires).ToArray();
                        return(Task.CompletedTask);
                    }
                }
            });
            await requestSigner.Sign(request);

            var receivedRequest = await request.ToServerSideHttpRequest();

            var verificationResult = await _verifier.VerifySignature(receivedRequest, _options);

            if (verificationResult is RequestSignatureVerificationResultSuccess successResult)
            {
                var simpleClaims = successResult.Principal.Claims.Select(c => new { c.Type, c.Value }).ToList();
                var claimsString = string.Join(", ", simpleClaims.Select(c => $"{{type:{c.Type},value:{c.Value}}}"));
                _output.WriteLine("Request signature verification succeeded: {0}", claimsString);
            }
            else if (verificationResult is RequestSignatureVerificationResultFailure failureResult)
            {
                _output.WriteLine("Request signature verification failed: {0}", failureResult.Failure);
                throw new SignatureVerificationException(failureResult.Failure.ToString());
            }
        }
예제 #3
0
        public async Task <int> Run(SignOptions options, string httpMessage)
        {
            ISignatureAlgorithm signatureAlgorithm;

            if (string.IsNullOrEmpty(options.KeyType) || options.KeyType.Equals("RSA", StringComparison.OrdinalIgnoreCase))
            {
                RSAParameters rsaPrivateKey;
                using (var stream = File.OpenRead(options.PrivateKey)) {
                    using (var reader = new PemReader(stream)) {
                        rsaPrivateKey = reader.ReadRsaKey();
                    }
                }

                signatureAlgorithm = RSASignatureAlgorithm.CreateForSigning(HashAlgorithmName.SHA512, rsaPrivateKey);
            }
            else if (options.KeyType.Equals("P256", StringComparison.OrdinalIgnoreCase) || options.KeyType.Equals("ECDSA", StringComparison.OrdinalIgnoreCase))
            {
                ECParameters ecPrivateKey;
                using (var stream = File.OpenRead(options.PrivateKey)) {
                    using (var reader = new StreamReader(stream)) {
                        var fileContents = reader.ReadToEnd();
                        var lines        = fileContents.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
                        lines = lines.Skip(1).Take(lines.Length - 2).ToArray();
                        var pem      = string.Join("", lines);
                        var ecdsa    = ECDsa.Create();
                        var derArray = Convert.FromBase64String(pem);
                        ecdsa.ImportPkcs8PrivateKey(derArray, out _);
                        ecPrivateKey = ecdsa.ExportParameters(true);
                    }
                }

                signatureAlgorithm = ECDsaSignatureAlgorithm.CreateForSigning(HashAlgorithmName.SHA512, ecPrivateKey);
            }
            else if (options.KeyType.Equals("HMAC", StringComparison.OrdinalIgnoreCase))
            {
                signatureAlgorithm = SignatureAlgorithm.CreateForSigning(options.PrivateKey, HashAlgorithmName.SHA512);
            }
            else
            {
                throw new NotSupportedException("The specified key type is not supported.");
            }

            if (!string.IsNullOrEmpty(options.Algorithm) &&
                !options.Algorithm.StartsWith("rsa", StringComparison.OrdinalIgnoreCase) &&
                !options.Algorithm.StartsWith("hmac", StringComparison.OrdinalIgnoreCase) &&
                !options.Algorithm.StartsWith("ecdsa", StringComparison.OrdinalIgnoreCase))
            {
                signatureAlgorithm = new CustomSignatureAlgorithm(options.Algorithm);
            }

            var signingSettings = new SigningSettings {
                SignatureAlgorithm  = signatureAlgorithm,
                EnableNonce         = false,
                DigestHashAlgorithm = HashAlgorithmName.SHA256,
                AutomaticallyAddRecommendedHeaders = false,
                Headers = options.Headers
                          ?.Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries)
                          .Select(h => new HeaderName(h))
                          .ToArray()
            };
            var signer = _requestSignerFactory.Create(
                new KeyId("test"),
                signingSettings);

            var request = HttpRequestMessageParser.Parse(httpMessage);

            var created = DateTimeOffset.UtcNow;

            if (!string.IsNullOrEmpty(options.Created))
            {
                var createdUnix = int.Parse(options.Created);
                created = DateTimeOffset.FromUnixTimeSeconds(createdUnix);
            }

            var expires = signingSettings.Expires;

            if (!string.IsNullOrEmpty(options.Expires))
            {
                var expiresUnix     = int.Parse(options.Expires);
                var expiresAbsolute = DateTimeOffset.FromUnixTimeSeconds(expiresUnix);
                expires = expiresAbsolute - created;
            }

            await signer.Sign(request, created, expires);

            var httpMessageLines = new List <string>(httpMessage.Split('\n').Select(l => l.Trim()));

            httpMessageLines.Insert(1, "Authorization: " + request.Headers.Authorization.Scheme + " " + request.Headers.Authorization.Parameter);
            var fullMessage = string.Join('\n', httpMessageLines);

            Log.Information(fullMessage);

            Console.Out.Flush();

            return(0);
        }