/// <summary> /// Constructs the token for validating an incoming request. /// </summary> public HttpSignatureSecurityToken(string rawDigest, string rawSignature) { RawDigest = rawDigest; RawSignature = rawSignature; Digest = HttpDigest.Parse(rawDigest); Signature = HttpSignature.Parse(rawSignature); }
/// <summary> /// constructs the token for sending a request with http signature. /// </summary> /// <param name="signingCredentials"></param> /// <param name="requestBody"></param> /// <param name="includedHeaders"></param> /// <param name="createdDate"></param> /// <param name="expirationDate"></param> public HttpSignatureSecurityToken(SigningCredentials signingCredentials, byte[] requestBody, IDictionary <string, string> includedHeaders, DateTime?createdDate = null, DateTime?expirationDate = null) { Digest = new HttpDigest(signingCredentials.Algorithm, requestBody); includedHeaders.Add(HttpDigest.HTTPHeaderName, Digest.ToString()); Signature = new HttpSignature(signingCredentials, includedHeaders, createdDate, expirationDate); RequestId = includedHeaders["X-Request-Id"]; }
/// <summary> /// Parses the header value string into an <see cref="HttpDigest"/> instance. /// </summary> /// <param name="headerValue"></param> /// <returns></returns> public static HttpDigest Parse(string headerValue) { var equalsSignPosition = headerValue.IndexOf('='); // do not use split because base64 uses the equals sign. if (equalsSignPosition < 0) { throw new FormatException($"Cannot parse HttpDigest from raw value {headerValue}"); } var digest = new HttpDigest { Algorithm = headerValue.Substring(0, equalsSignPosition), Output = headerValue.Substring(equalsSignPosition + 1), }; return(digest); }
private async Task ValidateResponse(HttpRequestMessage request, HttpResponseMessage response) { if (IgnoreResponseValidation) { return; } if (StringExtensions.IsIgnoredPath(IgnoredPaths, request.RequestUri.AbsolutePath, request.Method.Method)) { return; } if (!response.Headers.TryGetValues(HttpSignature.HTTPHeaderName, out var signatureValues) || signatureValues.Count() == 0) { return; } if (!response.Headers.TryGetValues(ResponseSignatureCertificateHeaderName, out var certValues) || certValues.Count() == 0) { var error = $"Missing certificate in HTTP header '{ResponseSignatureCertificateHeaderName}'. Cannot validate signature."; throw new Exception(error); } var rawSignature = signatureValues.First(); var rawCertificate = certValues.First(); Debug.WriteLine($"{nameof(HttpSignatureDelegatingHandler)}: Raw Signature: {rawSignature}"); Debug.WriteLine($"{nameof(HttpSignatureDelegatingHandler)}: Raw Certificate: {rawCertificate}"); X509Certificate2 certificate; try { certificate = new X509Certificate2(Convert.FromBase64String(rawCertificate)); } catch (Exception inner) { var error = $"Signature Certificate not in a valid format. Expected a base64 encoded x509."; throw new Exception(error, inner); } var validationKey = new X509SecurityKey(certificate); Debug.WriteLine($"{nameof(HttpSignatureDelegatingHandler)}: Validation Key: {validationKey.KeyId}"); var httpSignature = HttpSignature.Parse(rawSignature); if (response.Headers.TryGetValues(HttpDigest.HTTPHeaderName, out var digestValues) && digestValues.Count() > 0) { var rawDigest = digestValues.First(); Debug.WriteLine($"{nameof(HttpSignatureDelegatingHandler)}: Raw Digest: {rawDigest}"); var httpDigest = HttpDigest.Parse(rawDigest); Debug.WriteLine($"{nameof(HttpSignatureDelegatingHandler)}: Validated Token Digest: {httpDigest}"); var responseBody = await response.Content.ReadAsByteArrayAsync(); // Validate the request. var disgestIsValid = httpDigest.Validate(responseBody); if (!disgestIsValid) { var error = $"Response digest validation failed."; throw new Exception(error); } } response.Headers.TryGetValues(ResponseCreatedHeaderName, out var createdFieldValue); var signatureIsValid = httpSignature.Validate(validationKey, request.RequestUri, request.Method.Method, createdFieldValue.First(), response.Headers); if (!signatureIsValid) { var error = $"Response signature validation failed."; throw new Exception(error); } }