コード例 #1
0
        /// <summary>
        /// Returns true, if there is a WWW-Authenticate header containing ts and tsm but mac
        /// computed for ts does not match tsm, indicating possible tampering. Otherwise, returns false.
        /// This method also sets the compensation field so that the timestamp in the subsequent requests
        /// are adjusted to reduce the clock skew.
        /// </summary>
        private bool IsTimestampResponseTampered(ArtifactsContainer artifacts, IResponseMessage response)
        {
            var wwwHeader = response.WwwAuthenticate;

            if (wwwHeader != null)
            {
                string parameter = wwwHeader.Parameter;

                ArtifactsContainer timestampArtifacts;
                if (!String.IsNullOrWhiteSpace(parameter) &&
                    ArtifactsContainer.TryParse(parameter, out timestampArtifacts))
                {
                    var ts = new NormalizedTimestamp(timestampArtifacts.Timestamp, options.CredentialsCallback(), options.LocalTimeOffsetMillis);

                    if (!ts.IsValid(timestampArtifacts.TimestampMac))
                    {
                        return(true);
                    }

                    lock (myPrecious)
                        HawkClient.CompensatorySeconds = (int)(timestampArtifacts.Timestamp - DateTime.UtcNow.ToUnixTime());

                    Tracing.Information("HawkClient.CompensatorySeconds set to " + HawkClient.CompensatorySeconds);
                }
            }

            return(false);
        }
コード例 #2
0
        /// <summary>
        /// Creates the HTTP Authorization header in hawk scheme.
        /// </summary>
        internal async Task CreateClientAuthorizationInternalAsync(IRequestMessage request, DateTime utcNow)
        {
            var credential = options.CredentialsCallback();

            this.artifacts = new ArtifactsContainer()
            {
                Id        = credential.Id,
                Timestamp = utcNow.AddSeconds(HawkClient.CompensatorySeconds).ToUnixTime(),
                Nonce     = NonceGenerator.Generate()
            };

            if (options.NormalizationCallback != null)
            {
                this.artifacts.ApplicationSpecificData = options.NormalizationCallback(request);
            }

            var normalizedRequest = new NormalizedRequest(request, this.artifacts, options.HostNameSource);

            this.crypto = new Cryptographer(normalizedRequest, this.artifacts, credential);

            // Sign the request
            bool includePayloadHash = options.RequestPayloadHashabilityCallback != null &&
                                      options.RequestPayloadHashabilityCallback(request);

            string payload = includePayloadHash ? await request.ReadBodyAsStringAsync() : null;

            crypto.Sign(payload, request.ContentType);

            request.Authorization = new AuthenticationHeaderValue(HawkConstants.Scheme,
                                                                  this.artifacts.ToAuthorizationHeaderParameter());
        }
コード例 #3
0
        /// <summary>
        /// Returns true if the server response HMAC cannot be validated, indicating possible tampering.
        /// </summary>
        private async Task <bool> IsResponseTamperedAsync(ArtifactsContainer artifacts, Cryptographer crypto,
                                                          HttpResponseMessage response)
        {
            if (response.Headers.Contains(HawkConstants.ServerAuthorizationHeaderName))
            {
                string header = response.Headers.GetValues(HawkConstants.ServerAuthorizationHeaderName).FirstOrDefault();

                if (!String.IsNullOrWhiteSpace(header) &&
                    header.Substring(0, HawkConstants.Scheme.Length).ToLower() == HawkConstants.Scheme)
                {
                    ArtifactsContainer serverAuthorizationArtifacts;
                    if (ArtifactsContainer.TryParse(header.Substring(HawkConstants.Scheme.Length + " ".Length),
                                                    out serverAuthorizationArtifacts))
                    {
                        // To validate response, ext, hash, and mac in the request artifacts must be
                        // replaced with the ones from the server.
                        artifacts.ApplicationSpecificData = serverAuthorizationArtifacts.ApplicationSpecificData;
                        artifacts.PayloadHash             = serverAuthorizationArtifacts.PayloadHash;
                        artifacts.Mac = serverAuthorizationArtifacts.Mac;

                        bool isValid = await crypto.IsSignatureValidAsync(response.Content);

                        if (isValid)
                        {
                            this.WebApiSpecificData = serverAuthorizationArtifacts.ApplicationSpecificData;
                        }

                        return(!isValid);
                    }
                }
            }

            return(true); // Missing header means possible tampered response (to err on the side of caution).
        }
コード例 #4
0
        /// <summary>
        /// Returns true, if there is a WWW-Authenticate header containing ts and tsm but mac
        /// computed for ts does not match tsm, indicating possible tampering. Otherwise, returns false.
        /// This method also sets the compensation field so that the timestamp in the subsequent requests
        /// are adjusted to reduce the clock skew.
        /// </summary>
        private bool IsTimestampResponseTampered(ArtifactsContainer artifacts, HttpResponseMessage response)
        {
            if (response.Headers.WwwAuthenticate != null)
            {
                var wwwHeader = response.Headers.WwwAuthenticate.FirstOrDefault();

                if (wwwHeader != null && wwwHeader.Scheme.ToLower() == HawkConstants.Scheme)
                {
                    string parameter = wwwHeader.Parameter;

                    ArtifactsContainer timestampArtifacts;
                    if (!String.IsNullOrWhiteSpace(parameter) &&
                        ArtifactsContainer.TryParse(parameter, out timestampArtifacts))
                    {
                        var ts = new NormalizedTimestamp(timestampArtifacts.Timestamp, credentialFunc());

                        if (!ts.IsValid(timestampArtifacts.TimestampMac))
                        {
                            return(true);
                        }

                        lock (myPrecious)
                            HawkClient.CompensatorySeconds = (int)(timestampArtifacts.Timestamp - DateTime.UtcNow.ToUnixTime());

                        Tracing.Information("HawkClient.CompensatorySeconds set to " + HawkClient.CompensatorySeconds);
                    }
                }
            }

            return(false);
        }
コード例 #5
0
        /// <summary>
        /// Creates the HTTP Authorization header in hawk scheme.
        /// </summary>
        internal async Task CreateClientAuthorizationInternalAsync(HttpRequestMessage request, DateTime utcNow)
        {
            var credential = credentialFunc();

            this.artifacts = new ArtifactsContainer()
            {
                Id        = credential.Id,
                Timestamp = utcNow.AddSeconds(HawkClient.CompensatorySeconds).ToUnixTime(),
                Nonce     = NonceGenerator.Generate()
            };

            if (!String.IsNullOrWhiteSpace(this.ApplicationSpecificData))
            {
                this.artifacts.ApplicationSpecificData = this.ApplicationSpecificData;
            }

            var normalizedRequest = new NormalizedRequest(request, this.artifacts);

            this.crypto = new Cryptographer(normalizedRequest, this.artifacts, credential);

            // Sign the request
            await crypto.SignAsync(request.Content);

            request.Headers.Authorization = new AuthenticationHeaderValue(
                HawkConstants.Scheme,
                this.artifacts.ToAuthorizationHeaderParameter());
        }
コード例 #6
0
        internal static bool IsPayloadHashPresent(this IOwinRequest request)
        {
            string authorization = request.Headers.Get(HawkConstants.AuthorizationHeaderName);

            if (!String.IsNullOrWhiteSpace(authorization))
            {
                string parameter = AuthenticationHeaderValue.Parse(authorization).Parameter;
                return(ArtifactsContainer.IsPayloadHashPresent(parameter));
            }

            return(false);
        }
コード例 #7
0
        public async Task TimestampInSubsequentRequestMustBeAdjustedBasedOnTimestampInWwwAuthenticateHeaderOfPrevious()
        {
            using (var invoker = new HttpMessageInvoker(server))
            {
                using (var request = new HttpRequestMessage(HttpMethod.Get, URI))
                {
                    var client = ClientFactory.Create();
                    await client.CreateClientAuthorizationAsync(new WebApiRequestMessage(request));

                    using (var response = await invoker.SendAsync(request, CancellationToken.None))
                    {
                        // Simulate server clock running 5 minutes slower than client and
                        // produce the parameter with ts and tsm
                        var    timestamp       = new NormalizedTimestamp(DateTime.UtcNow.AddMinutes(-5), ServerFactory.DefaultCredential);
                        string timestampHeader = timestamp.ToWwwAuthenticateHeaderParameter();

                        // Add that to the WWW-Authenticate before authenticating with the
                        // client, to simulate clock skew
                        response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue("hawk", timestampHeader));

                        // Client must have now calculated an offset of -300 seconds approx
                        Assert.IsTrue(await client.AuthenticateAsync(new WebApiResponseMessage(response)));
                        Assert.IsTrue(HawkClient.CompensatorySeconds <= -299 && HawkClient.CompensatorySeconds >= -301);

                        // Create a fresh request and see if this offset is applied to the timestamp
                        using (var subsequentRequest = new HttpRequestMessage(HttpMethod.Get, URI))
                        {
                            await client.CreateClientAuthorizationAsync(new WebApiRequestMessage(subsequentRequest));

                            string header = subsequentRequest.Headers.Authorization.Parameter;

                            ArtifactsContainer artifacts = null;
                            Assert.IsTrue(ArtifactsContainer.TryParse(header, out artifacts));

                            var timestampInSubsequentRequest = artifacts.Timestamp;
                            var now = DateTime.UtcNow.ToUnixTime();

                            // Since server clock is slow, the timestamp going out must be offset by the same 5 minutes
                            // or 300 seconds. Give leeway of a second while asserting.
                            ulong difference = now - timestampInSubsequentRequest;
                            Assert.IsTrue(difference >= 299 && difference <= 301);
                        }
                    }
                }
            }
        }
コード例 #8
0
        /// <summary>
        /// Returns true if the server response HMAC cannot be validated, indicating possible tampering.
        /// </summary>
        private async Task <bool> IsResponseTamperedAsync(ArtifactsContainer artifacts, Cryptographer crypto,
                                                          IResponseMessage response)
        {
            if (response.Headers.ContainsKey(HawkConstants.ServerAuthorizationHeaderName))
            {
                string header = response.Headers[HawkConstants.ServerAuthorizationHeaderName].FirstOrDefault();

                if (!String.IsNullOrWhiteSpace(header) &&
                    header.Substring(0, HawkConstants.Scheme.Length).ToLower() == HawkConstants.Scheme)
                {
                    ArtifactsContainer serverAuthorizationArtifacts;
                    if (ArtifactsContainer.TryParse(header.Substring(HawkConstants.Scheme.Length + " ".Length),
                                                    out serverAuthorizationArtifacts))
                    {
                        // To validate response, ext, hash, and mac in the request artifacts must be
                        // replaced with the ones from the server.
                        artifacts.ApplicationSpecificData = serverAuthorizationArtifacts.ApplicationSpecificData;
                        artifacts.PayloadHash             = serverAuthorizationArtifacts.PayloadHash;
                        artifacts.Mac = serverAuthorizationArtifacts.Mac;

                        // Response body is needed only if payload hash is present in the server response.
                        string body = null;
                        if (artifacts.PayloadHash != null && artifacts.PayloadHash.Length > 0)
                        {
                            body = await response.ReadBodyAsStringAsync();
                        }

                        bool isValid = crypto.IsSignatureValid(body, response.ContentType, isServerAuthorization: true);

                        if (isValid)
                        {
                            string appSpecificData = serverAuthorizationArtifacts.ApplicationSpecificData;

                            isValid = options.VerificationCallback == null ||
                                      options.VerificationCallback(response, appSpecificData);
                        }

                        return(!isValid);
                    }
                }
            }

            return(true); // Missing header means possible tampered response (to err on the side of caution).
        }
コード例 #9
0
        /// <summary>
        /// Returns true, if there is a WWW-Authenticate header containing ts and tsm but mac
        /// computed for ts does not match tsm, indicating possible tampering. Otherwise, returns false.
        /// This method also sets the compensation field so that the timestamp in the subsequent requests
        /// are adjusted to reduce the clock skew.
        /// </summary>
        private bool IsTimestampResponseTampered(ArtifactsContainer artifacts, HttpResponseMessage response)
        {
            if (response.Headers.WwwAuthenticate != null)
            {
                var wwwHeader = response.Headers.WwwAuthenticate.FirstOrDefault();

                if (wwwHeader != null && wwwHeader.Scheme.ToLower() == HawkConstants.Scheme)
                {
                    string parameter = wwwHeader.Parameter;

                    ArtifactsContainer timestampArtifacts;
                    if (!String.IsNullOrWhiteSpace(parameter) &&
                                    ArtifactsContainer.TryParse(parameter, out timestampArtifacts))
                    {
                        var ts = new NormalizedTimestamp(timestampArtifacts.Timestamp, credentialFunc());

                        if (!ts.IsValid(timestampArtifacts.TimestampMac))
                            return true;

                        lock (myPrecious)
                            HawkClient.CompensatorySeconds = (int)(timestampArtifacts.Timestamp - DateTime.UtcNow.ToUnixTime());
                    }
                }
            }

            return false;
        }
コード例 #10
0
        /// <summary>
        /// Returns true if the server response HMAC cannot be validated, indicating possible tampering.
        /// </summary>
        private async Task<bool> IsResponseTamperedAsync(ArtifactsContainer artifacts, Cryptographer crypto,
                                                        HttpResponseMessage response)
        {
            if (response.Headers.Contains(HawkConstants.ServerAuthorizationHeaderName))
            {
                string header = response.Headers.GetValues(HawkConstants.ServerAuthorizationHeaderName).FirstOrDefault();

                if (!String.IsNullOrWhiteSpace(header) &&
                                    header.Substring(0, HawkConstants.Scheme.Length).ToLower() == HawkConstants.Scheme)
                {
                    ArtifactsContainer serverAuthorizationArtifacts;
                    if (ArtifactsContainer.TryParse(header.Substring(HawkConstants.Scheme.Length + " ".Length),
                                                                                    out serverAuthorizationArtifacts))
                    {
                        // To validate response, ext, hash, and mac in the request artifacts must be
                        // replaced with the ones from the server.
                        artifacts.ApplicationSpecificData = serverAuthorizationArtifacts.ApplicationSpecificData;
                        artifacts.PayloadHash = serverAuthorizationArtifacts.PayloadHash;
                        artifacts.Mac = serverAuthorizationArtifacts.Mac;

                        bool isValid = await crypto.IsSignatureValidAsync(response.Content);

                        if(isValid)
                            this.WebApiSpecificData = serverAuthorizationArtifacts.ApplicationSpecificData;

                        return !isValid;
                    }
                }
            }

            return true; // Missing header means possible tampered response (to err on the side of caution).
        }
コード例 #11
0
        /// <summary>
        /// Creates the HTTP Authorization header in hawk scheme.
        /// </summary>
        internal async Task CreateClientAuthorizationInternalAsync(HttpRequestMessage request, DateTime utcNow)
        {
            var credential = credentialFunc();
            this.artifacts = new ArtifactsContainer()
            {
                Id = credential.Id,
                Timestamp = utcNow.AddSeconds(HawkClient.CompensatorySeconds).ToUnixTime(),
                Nonce = NonceGenerator.Generate()
            };

            if (!String.IsNullOrWhiteSpace(this.ApplicationSpecificData))
                this.artifacts.ApplicationSpecificData = this.ApplicationSpecificData;

            var normalizedRequest = new NormalizedRequest(request, this.artifacts);
            this.crypto = new Cryptographer(normalizedRequest, this.artifacts, credential);

            // Sign the request
            await crypto.SignAsync(request.Content);

            request.Headers.Authorization = new AuthenticationHeaderValue(
                                                HawkConstants.Scheme,
                                                this.artifacts.ToAuthorizationHeaderParameter());
        }