private static async Task <X509Certificate2> GetCertificate(Uri signatureCertChainUrl)
        {
            if (signatureCertChainUrl == null)
            {
                return(null);
            }

            if (certificateCache.Key == null || certificateCache.Key.ToString().ToLowerInvariant() != signatureCertChainUrl.ToString().ToLowerInvariant())
            {
                try
                {
                    X509Certificate2 certificate = await RequestVerification.GetCertificate(signatureCertChainUrl);

                    if (certificate != null)
                    {
                        certificateCache = new KeyValuePair <Uri, X509Certificate2>(signatureCertChainUrl, certificate);
                    }

                    return(certificate);
                }
                catch
                {
                    return(null);
                }
            }
            else
            {
                return(certificateCache.Value);
            }
        }
        private async Task <bool> ValidateRequest(HttpRequest request, SkillRequest skillRequest)
        {
            try
            {
                request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl);
                if (string.IsNullOrWhiteSpace(signatureChainUrl))
                {
                    return(false);
                }

                Uri certUrl;
                try
                {
                    certUrl = new Uri(signatureChainUrl);
                }
                catch
                {
                    return(false);
                }

                request.Headers.TryGetValue("Signature", out var signature);
                if (string.IsNullOrWhiteSpace(signature))
                {
                    return(false);
                }
                var body = "";
                request.EnableRewind();
                using (var stream = new StreamReader(request.Body))
                {
                    stream.BaseStream.Position = 0;
                    body = stream.ReadToEnd();
                    stream.BaseStream.Position = 0;
                }

                if (string.IsNullOrWhiteSpace(body))
                {
                    return(false);
                }

                bool isTimestampValid = RequestVerification.RequestTimestampWithinTolerance(skillRequest);
                bool valid            = await RequestVerification.Verify(signature, certUrl, body);

                if (!valid || !isTimestampValid)
                {
                    return(false);
                }
                else
                {
                    return(true);
                }
            }
            catch
            {
                return(false);
            }
        }
Exemple #3
0
        public void Replay_Attack_Timestamp_Invalidated_By_RequestVerification()
        {
            var request = new SkillRequest
            {
                Request = new LaunchRequest {
                    Timestamp = DateTime.Now.AddMinutes(3)
                }
            };

            Assert.False(RequestVerification.RequestTimestampWithinTolerance(request));
        }
Exemple #4
0
        private static async Task <bool> ValidateRequest(HttpRequest request, ILogger log, SkillRequest skillRequest)
        {
            request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl);
            if (string.IsNullOrWhiteSpace(signatureChainUrl))
            {
                log.LogError("Validation failed. Empty SignatureCertChainUrl header");
                return(false);
            }

            Uri certUrl;

            try
            {
                certUrl = new Uri(signatureChainUrl);
            }
            catch
            {
                log.LogError($"Validation failed. SignatureChainUrl not valid: {signatureChainUrl}");
                return(false);
            }

            request.Headers.TryGetValue("Signature", out var signature);
            if (string.IsNullOrWhiteSpace(signature))
            {
                log.LogError("Validation failed - Empty Signature header");
                return(false);
            }

            request.Body.Position = 0;
            var body = await request.ReadAsStringAsync();

            request.Body.Position = 0;

            if (string.IsNullOrWhiteSpace(body))
            {
                log.LogError("Validation failed - the JSON is empty");
                return(false);
            }

            bool isTimestampValid = RequestVerification.RequestTimestampWithinTolerance(skillRequest);
            bool valid            = await RequestVerification.Verify(signature, certUrl, body, GetCertificate);

            // bool valid = await RequestVerification.Verify(signature, certUrl, body);

            if (!valid || !isTimestampValid)
            {
                log.LogError("Validation failed - RequestVerification failed");
                return(false);
            }
            else
            {
                return(true);
            }
        }
Exemple #5
0
        public void New_Request_Timestamp_validated_By_RequestVerification()
        {
            var request = new SkillRequest
            {
                Request = new LaunchRequest {
                    Timestamp = DateTime.Now.AddMinutes(1)
                }
            };

            Assert.True(RequestVerification.RequestTimestampWithinTolerance(request));
        }
Exemple #6
0
        /// <summary>
        /// Validate if all necessary parts for a valid request are available
        /// and pass them to the RequestsVerification tool
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task Invoke(HttpContext context)
        {
            // EnableBuffering so the body can be read without causing issues to the request pipeline
            context.Request.EnableBuffering();

            // Verify SignatureCertChainUrl is present
            context.Request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl);
            if (string.IsNullOrWhiteSpace(signatureChainUrl))
            {
                context.Response.StatusCode = StatusCodes.Status400BadRequest;
                return;
            }

            Uri certUrl;

            try
            {
                certUrl = new Uri(signatureChainUrl);
            }
            catch
            {
                context.Response.StatusCode = StatusCodes.Status400BadRequest;
                return;
            }

            // Verify SignatureCertChainUrl is Signature
            context.Request.Headers.TryGetValue("Signature", out var signature);
            if (string.IsNullOrWhiteSpace(signature))
            {
                context.Response.StatusCode = StatusCodes.Status400BadRequest;
                return;
            }

            var body = await new StreamReader(context.Request.Body).ReadToEndAsync();

            context.Request.Body.Position = 0;

            if (string.IsNullOrWhiteSpace(body))
            {
                context.Response.StatusCode = StatusCodes.Status400BadRequest;
                return;
            }

            var valid = await RequestVerification.Verify(signature, certUrl, body);

            if (!valid)
            {
                context.Response.StatusCode = StatusCodes.Status400BadRequest;
                return;
            }

            await _next(context);
        }
        public static async Task <bool> ValidateRequestAsync(this SkillRequest skillRequest, HttpRequest request, ILogger log)
        {
            // Verifies that the request is indeed coming from Alexa.

            request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl);
            if (string.IsNullOrWhiteSpace(signatureChainUrl))
            {
                log.LogError("Validation failed. Empty SignatureCertChainUrl header");
                return(false);
            }

            Uri certUrl;

            try
            {
                certUrl = new Uri(signatureChainUrl);
            }
            catch
            {
                log.LogError($"Validation failed. SignatureChainUrl not valid: {signatureChainUrl}");
                return(false);
            }

            request.Headers.TryGetValue("Signature", out var signature);
            if (string.IsNullOrWhiteSpace(signature))
            {
                log.LogError("Validation failed - Empty Signature header");
                return(false);
            }

            request.Body.Position = 0;
            var body = request.Body.ToString();

            request.Body.Position = 0;

            if (string.IsNullOrWhiteSpace(body))
            {
                log.LogError("Validation failed - the JSON is empty");
                return(false);
            }

            var isTimestampValid = RequestVerification.RequestTimestampWithinTolerance(skillRequest);
            var isValid          = await RequestVerification.Verify(signature, certUrl, body);

            if (!isValid || !isTimestampValid)
            {
                log.LogError("Validation failed - RequestVerification failed");
                return(false);
            }

            return(true);
        }
Exemple #8
0
        private async Task <bool> ValidateRequest(HttpRequest request, SkillRequest skillRequest)
        {
            try {
                var header    = request.Headers;
                var signature = header["Signature"];
                var certUrl   = new Uri(header["SignatureCertChainUrl"]);
                var body      = await request.ReadAsStringAsync();

                return
                    (RequestVerification.RequestTimestampWithinTolerance(skillRequest) &&
                     await RequestVerification.Verify(signature, certUrl, body));
            } catch {
                m_logger.LogError("Validation exception");
                return(false);
            }
        }
Exemple #9
0
        public static async Task EnsureValidAlexaSignatureAsync(this HttpRequest request)
        {
            request.EnableRewind();

            // Verify SignatureCertChainUrl is present
            request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl);

            if (string.IsNullOrWhiteSpace(signatureChainUrl))
            {
                throw new InvalidSignatureException();
            }

            Uri certUrl;

            try
            {
                certUrl = new Uri(signatureChainUrl);
            }
            catch
            {
                throw new InvalidSignatureException();
            }

            // Verify SignatureCertChainUrl is Signature
            request.Headers.TryGetValue("Signature", out var signature);

            if (string.IsNullOrWhiteSpace(signature))
            {
                throw new InvalidSignatureException();
            }

            var body = new StreamReader(request.Body).ReadToEnd();

            request.Body.Position = 0;

            if (string.IsNullOrWhiteSpace(body))
            {
                throw new InvalidSignatureException();
            }

            var valid = await RequestVerification.Verify(signature, certUrl, body);

            if (!valid)
            {
                throw new InvalidSignatureException();
            }
        }
Exemple #10
0
        private static async Task <bool> ValidateRequestAsync(HttpRequest request, SkillRequest skillRequest)
        {
            request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl);
            if (string.IsNullOrWhiteSpace(signatureChainUrl))
            {
                return(false);
            }

            Uri certUrl;

            try
            {
                certUrl = new Uri(signatureChainUrl);
            }
            catch
            {
                return(false);
            }

            request.Headers.TryGetValue("Signature", out var signature);
            if (string.IsNullOrWhiteSpace(signature))
            {
                return(false);
            }

            request.Body.Position = 0;
            var body = await request.ReadAsStringAsync();

            request.Body.Position = 0;

            if (string.IsNullOrWhiteSpace(body))
            {
                return(false);
            }

            bool isTimestampValid = RequestVerification.RequestTimestampWithinTolerance(skillRequest);
            bool valid            = await RequestVerification.Verify(signature, certUrl, body);

            if (!valid || !isTimestampValid)
            {
                return(false);
            }
            else
            {
                return(true);
            }
        }
        /// <summary>
        /// Authorize the SkillRequest is coming from Alexa.
        /// </summary>
        /// <param name="skillRequest">Incoming SkillRequest from Alexa.</param>
        /// <param name="requestBody">Full request body from Alexa.</param>
        /// <param name="signatureChainUrl">Signature Chain Url. This is the SignatureCertChainUrl header value.</param>
        /// <param name="signature">Signature. This is the Signature header value.</param>
        /// <returns>True if this is a valid SkillRequest otherwise false.</returns>
        public virtual async Task <bool> ValidateSkillRequest(CrunchRequest skillRequest, string requestBody, string signatureChainUrl, string signature)
        {
            if (skillRequest == null)
            {
                _logger.LogError("Validation failed. No incoming skill request.");
                return(false);
            }

            if (string.IsNullOrWhiteSpace(signatureChainUrl))
            {
                _logger.LogError("Validation failed. Empty SignatureCertChainUrl header.");
                return(false);
            }

            Uri certUrl;

            try
            {
                certUrl = new Uri(signatureChainUrl);
            }
            catch
            {
                _logger.LogError($"Validation failed. SignatureChainUrl not valid: {signatureChainUrl}.");
                return(false);
            }

            if (string.IsNullOrWhiteSpace(signature))
            {
                _logger.LogError("Validation failed. Empty Signature header.");
                return(false);
            }

            if (!RequestVerification.RequestTimestampWithinTolerance(skillRequest))
            {
                _logger.LogError("Validation failed. Request timestamp outside of tolerance.");
                return(false);
            }
            if (!await RequestVerification.Verify(signature, certUrl, requestBody))
            {
                _logger.LogError("Validation failed. Alexa certificate validation failed.");
                return(false);
            }

            return(true);
        }
 /// <summary>
 /// Validates the request.
 /// </summary>
 /// <param name="signature">The Signature value.</param>
 /// <param name="signatureCertChainUrl">The SignatureCertChainUrl value.</param>
 /// <param name="body">The body value.</param>
 /// <returns></returns>
 private static async Task <bool> IsRequestValid(string signature, Uri signatureCertChainUrl, string body)
 {
     return(await RequestVerification.Verify(signature, signatureCertChainUrl, body));
 }
        public async Task InvokeAsync(HttpContext context)
        {
            string bodyStr;

            using (var reader = new StreamReader(context.Request.Body))
            {
                bodyStr = reader.ReadToEnd();
            }

            if (environment.IsProduction())
            {
                // Verify SignatureCertChainUrl is present
                context.Request.Headers.TryGetValue("SignatureCertChainUrl", out var signatureChainUrl);
                if (String.IsNullOrWhiteSpace(signatureChainUrl))
                {
                    context.Response.StatusCode = StatusCodes.Status400BadRequest;
                    return;
                }

                Uri certUrl;
                try
                {
                    certUrl = new Uri(signatureChainUrl);
                }
                catch
                {
                    context.Response.StatusCode = StatusCodes.Status400BadRequest;
                    return;
                }

                // Verify SignatureCertChainUrl is Signature
                context.Request.Headers.TryGetValue("Signature", out var signature);
                if (String.IsNullOrWhiteSpace(signature))
                {
                    context.Response.StatusCode = StatusCodes.Status400BadRequest;
                    return;
                }

                if (String.IsNullOrWhiteSpace(bodyStr))
                {
                    context.Response.StatusCode = StatusCodes.Status400BadRequest;
                    return;
                }
                var valid = await RequestVerification.Verify(signature, certUrl, bodyStr);

                if (!valid)
                {
                    context.Response.StatusCode = StatusCodes.Status400BadRequest;
                    return;
                }
            }

            var skillRequest = JsonConvert.DeserializeObject <SkillRequest>(bodyStr);

            if (skillRequest == null)
            {
                context.Response.StatusCode = StatusCodes.Status400BadRequest;
                return;
            }
            var skillResponse = await skillRequestHandler.HandleRequestAsync(skillRequest);

            await context.Response.WriteAsync(JsonConvert.SerializeObject(skillResponse));
        }
Exemple #14
0
        public IActionResult HandleSkillRequest()
        {
            string body;

            using (var reader = new StreamReader(Request.Body, Encoding.UTF8))
            {
                body = reader.ReadToEnd();
                m_Logger.LogDebug("body: " + body);
            }

            SkillRequest input = JsonConvert.DeserializeObject <SkillRequest>(body);

            string signatureCertChainUrl = Request.Headers["SignatureCertChainUrl"];
            string signature             = Request.Headers["Signature"];

            m_Logger.LogDebug("signatureCertChainUrl: " + signatureCertChainUrl);
            m_Logger.LogDebug("signature: " + signature);

            if (string.IsNullOrEmpty(signatureCertChainUrl) || string.IsNullOrEmpty(signature))
            {
                return(BadRequest());
            }

            m_Logger.LogDebug("HandleSkillRequest: " + input.Session.Application.ApplicationId);

            if (input.Session.Application.ApplicationId != _appid)
            {
                m_Logger.LogDebug("ApplicationId wrong");
                return(BadRequest());
            }

            if (!RequestVerification.VerifyCertificateUrl(new Uri(signatureCertChainUrl)))
            {
                m_Logger.LogDebug("VerifyCertificateUrl: false");
                return(BadRequest());
            }

            var certificate = RequestVerification.GetCertificate(new Uri(signatureCertChainUrl)).Result;

            if (!RequestVerification.VerifyChain(certificate))
            {
                m_Logger.LogDebug("VerifyChain: false");
                return(BadRequest());
            }

            if (!RequestVerification.AssertHashMatch(certificate, signature, body))
            {
                m_Logger.LogDebug("AssertHashMatch: false");
                return(BadRequest());
            }

            if (!RequestVerification.RequestTimestampWithinTolerance(input))
            {
                m_Logger.LogDebug("RequestTimestampWithinTolerance: false");
                return(BadRequest());
            }

            var requestType = input.GetRequestType();

            if (requestType == typeof(IntentRequest))
            {
                m_Logger.LogInformation("requestType IntentRequest");
                var response = HandleIntents(input);
                return(Ok(response));
            }

            if (requestType == typeof(LaunchRequest))
            {
                m_Logger.LogInformation("requestType LaunchRequest");
                return(Ok(BuildResponse(Statics.WelcomeMessage, false)));
            }

            m_Logger.LogWarning("ErrorResponse");
            return(Ok(BuildResponse(Statics.ErrorMessage, true)));
        }
 public async ValueTask <bool> IsRequestValidAsync(string encodedSignature, Uri signatureCertChainUrl,
                                                   string request)
 {
     return(await RequestVerification.Verify(encodedSignature, signatureCertChainUrl, request));
 }
Exemple #16
0
        protected async Task <ActionResult> CheckBadRequest(SkillRequest skillRequest)
        {
            try
            {
                if (!RequestVerification.RequestTimestampWithinTolerance(skillRequest))
                {
                    LogMessage("Request failed due to TimestampTolerance", SeverityLevel.Error, null);
                    return(BadRequest());
                }

                var sigCertChainUrl = Request.Headers["SignatureCertChainUrl"];
                if (String.IsNullOrWhiteSpace(sigCertChainUrl))
                {
                    LogMessage("Request failed due to no SignatureCertChainUrl", SeverityLevel.Error, null);
                    return(BadRequest());
                }

                var signature = Request.Headers["Signature"];
                if (String.IsNullOrWhiteSpace(signature))
                {
                    LogMessage("Request failed due to no Signature", SeverityLevel.Error, null);
                    return(BadRequest());
                }

                var sigCertChainPath = new Uri(sigCertChainUrl);
                if (!RequestVerification.VerifyCertificateUrl(sigCertChainPath))
                {
                    LogMessage($"Request failed due to an invalid Certificate Url ({sigCertChainPath})", SeverityLevel.Error, null);
                    return(BadRequest());
                }

                //var cert = await RequestVerification.GetCertificate(sigCertChainPath);
                //if (!RequestVerification.VerifyChain(cert))
                //{
                //    LogMessage("Request failed due to invalid Certificate Chain", SeverityLevel.Error, null);
                //    return BadRequest();
                //}

                //Request.Body.Position = 0;
                var body = await new StreamReader(Request.Body, Encoding.UTF8).ReadToEndAsync();
                //Request.Body.Position = 0;

                if (!await RequestVerification.Verify(signature, sigCertChainPath, body))
                {
                    LogMessage($"Request verification failed! (sig: {signature}, sig cert chain: {sigCertChainPath}, request details: {await GetRequestDetails()})", SeverityLevel.Error, null);
                    return(BadRequest());
                }
            }
            catch (Exception exc)
            {
                LogMessage($"Request failed because of unknown error. Request: {await GetRequestDetails()}", SeverityLevel.Error, new Dictionary <string, string>()
                {
                    { "StackTrace", exc.StackTrace }
                });
                return(BadRequest());
            }

            //Success, let's log the request info temporarily
            LogMessage($"Successful request: {await GetRequestDetails()}", SeverityLevel.Verbose, "AlexaBaseController", "CheckBadRequest");
            return(null);
        }
 /// <summary>
 /// Validates the timestamp.
 /// </summary>
 /// <param name="skillRequest">The current skill request.</param>
 private static bool IsTimestampValid(SkillRequest skillRequest)
 {
     return(RequestVerification.RequestTimestampWithinTolerance(skillRequest));
 }