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()); } }
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()); } }
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); }