/// <summary> /// Computes and returns the canonical request /// </summary> /// <param name="headersToSign">Request headers that are to be included in the signature</param> /// <param name="serviceEndPoint">The endpoint to the service being called</param> /// <param name="queryString">The query parameters for the request</param> /// <param name="headers">The full request headers</param> /// <param name="requestBody">The body of the request</param> /// <param name="binaryRequestBodyHash">The hash of the binary request body if present.</param> /// <param name="httpMethod">The http method used for the request</param> /// <returns>Canonicalised request as a string</returns> private static string GetCanonicalRequest(List <string> headersToSign, Uri serviceEndPoint, string queryString, IDictionary <string, string> headers, string requestBody, string binaryRequestBodyHash, string httpMethod) { StringBuilder canonicalRequest = new StringBuilder(); canonicalRequest.AppendFormat("{0}\n", httpMethod); canonicalRequest.AppendFormat("{0}\n", GetCanonicalizedResourcePath(serviceEndPoint)); canonicalRequest.AppendFormat("{0}\n", queryString); canonicalRequest.AppendFormat("{0}\n", GetCanonicalizedHeaders(headersToSign, headers)); canonicalRequest.AppendFormat("{0}\n", GetSignedHeaders(headersToSign)); if (binaryRequestBodyHash != null) { canonicalRequest.Append(binaryRequestBodyHash); } else { byte[] payloadHashBytes = CanonicalizationHash.ComputeHash(Encoding.UTF8.GetBytes(requestBody)); canonicalRequest.Append(AWSSDKUtils.ToHex(payloadHashBytes, true)); } return(canonicalRequest.ToString()); }
/// <summary> /// Calculates and signs the specified request using the AWS4 signing protocol by using the /// AWS account credentials given in the method parameters. /// </summary> /// <param name="awsAccessKeyId">The AWS public key</param> /// <param name="awsSecretAccessKey">The AWS secret key used to sign the request in clear text</param> /// <param name="clientConfig">The configuration that specifies which hashing algorithm to use</param> /// <param name="request">The request to have the signature compute for</param> /// <param name="secureKey">The AWS secret key stored in a secure string</param> /// <exception cref="Amazon.Runtime.SignatureException">If any problems are encountered while signing the request</exception> public override void Sign(IRequest request, ClientConfig clientConfig, string awsAccessKeyId, string awsSecretAccessKey, SecureString secureKey) { // clean up request from previous execution request.Headers.Remove("Authorization"); string signingAlgorithm = SigningAlgorithm.HmacSHA256.ToString().ToUpper(); DateTime dt = DateTime.UtcNow; string dateTime = dt.ToString(AWSSDKUtils.ISO8601BasicDateTimeFormat, CultureInfo.InvariantCulture); string dateStamp = dt.ToString("yyyyMMdd", CultureInfo.InvariantCulture); string region = DetermineRegion(clientConfig); string service = DetermineService(clientConfig); if (!request.Headers.ContainsKey("Host")) { string hostHeader = request.Endpoint.Host; if (!request.Endpoint.IsDefaultPort) { hostHeader += ":" + request.Endpoint.Port; } request.Headers.Add("Host", hostHeader); } request.Headers["X-Amz-Date"] = dateTime; string scope = string.Format("{0}/{1}/{2}/{3}", dateStamp, region, service, TERMINATOR); List <string> headersToSign = GetHeadersForSigning(request.Headers); var queryString = request.UseQueryString ? AWSSDKUtils.GetParametersAsString(request.Parameters) : ""; string canonicalRequest = GetCanonicalRequest(headersToSign, new Uri(request.Endpoint, request.ResourcePath), queryString, request.Headers, request.UseQueryString ? "" : GetRequestPayload(request), request.ContentStreamHash, request.HttpMethod); StringBuilder stringToSign = new StringBuilder(); stringToSign.AppendFormat("{0}-{1}\n{2}\n{3}\n", SCHEME, ALGORITHM, dateTime, scope); byte[] canonicalRequestHashBytes = CanonicalizationHash.ComputeHash(Encoding.UTF8.GetBytes(canonicalRequest)); stringToSign.Append(AWSSDKUtils.ToHex(canonicalRequestHashBytes, true)); KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(signingAlgorithm); kha.Key = ComposeSigningKey(signingAlgorithm, awsSecretAccessKey, secureKey, region, dateStamp, service); byte[] signature = kha.ComputeHash(Encoding.UTF8.GetBytes(stringToSign.ToString())); StringBuilder authorizationHeader = new StringBuilder(); authorizationHeader.AppendFormat("{0}-{1} ", SCHEME, ALGORITHM); authorizationHeader.AppendFormat("Credential={0}/{1}, ", awsAccessKeyId, scope); authorizationHeader.AppendFormat("SignedHeaders={0}, ", GetSignedHeaders(headersToSign)); authorizationHeader.AppendFormat("Signature={0}", AWSSDKUtils.ToHex(signature, true)); request.Headers["Authorization"] = authorizationHeader.ToString(); }
/// <summary> /// Calculates the AWS4 signature using the supplied request parameters and AWS account credentials. /// </summary> /// <param name="headers">Request headers</param> /// <param name="parameters">Request AWS Query parameters to be included in the signature</param> /// <param name="serviceURL">Service endpoint URL</param> /// <param name="authenticationServiceName"> /// The short-form name of the target service for inclusion in the signature; only needed if this /// cannot be determined by parsing the endpoint. /// </param> /// <param name="authenticationRegion"> /// Region name for inclusion in the signature; only needed if this cannot be determined by parsing /// the endpoint. /// </param> /// <param name="httpMethod">The HTTP method used to make the request.</param> /// <param name="credentials">User credentials</param> /// <returns>The signature string to be added as header 'Authorization' on the eventual request</returns> /// <exception cref="Amazon.Runtime.SignatureException">If any problems are encountered while signing the request</exception> public static string CalculateSignature(IDictionary <string, string> headers, IDictionary <string, string> parameters, string serviceURL, string httpMethod, string authenticationServiceName, string authenticationRegion, ImmutableCredentials credentials) { string signingAlgorithm = SigningAlgorithm.HmacSHA256.ToString().ToUpper(); DateTime dt = DateTime.UtcNow; string dateTime = dt.ToString(AWSSDKUtils.ISO8601BasicDateTimeFormat, CultureInfo.InvariantCulture); string dateStamp = dt.ToString("yyyyMMdd", CultureInfo.InvariantCulture); string region; if (!string.IsNullOrEmpty(authenticationRegion)) { region = authenticationRegion; } else { region = AWSSDKUtils.DetermineRegion(serviceURL).ToLower(); } string service = authenticationServiceName.Trim().ToLower(); headers.Add("Host", new Uri(serviceURL).Host); headers.Add("X-Amz-Date", dateTime); string scope = string.Format("{0}/{1}/{2}/{3}", dateStamp, region, service, TERMINATOR); List <string> headersToSign = GetHeadersForSigning(headers); string canonicalRequest = GetCanonicalRequest(headersToSign, new Uri(serviceURL), "", headers, AWSSDKUtils.GetParametersAsString(parameters), null, // No support for binary request body yet here. httpMethod); StringBuilder stringToSign = new StringBuilder(); stringToSign.AppendFormat("{0}-{1}\n{2}\n{3}\n", SCHEME, ALGORITHM, dateTime, scope); byte[] canonicalRequestHashBytes = CanonicalizationHash.ComputeHash(Encoding.UTF8.GetBytes(canonicalRequest)); stringToSign.Append(AWSSDKUtils.ToHex(canonicalRequestHashBytes, true)); KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(signingAlgorithm); kha.Key = ComposeSigningKey(signingAlgorithm, credentials.ClearSecretKey, credentials.SecureSecretKey, region, dateStamp, service); byte[] signature = kha.ComputeHash(Encoding.UTF8.GetBytes(stringToSign.ToString())); StringBuilder authorizationHeader = new StringBuilder(); authorizationHeader.AppendFormat("{0}-{1} ", SCHEME, ALGORITHM); authorizationHeader.AppendFormat("Credential={0}/{1}, ", credentials.AccessKey, scope); authorizationHeader.AppendFormat("SignedHeaders={0}, ", GetSignedHeaders(headersToSign)); authorizationHeader.AppendFormat("Signature={0}", AWSSDKUtils.ToHex(signature, true)); return(authorizationHeader.ToString()); }
private void SignHttp(IRequest request, ClientConfig clientConfig, string awsAccessKeyId, string awsSecretAccessKey, SecureString secureKey) { SigningAlgorithm algorithm = SigningAlgorithm.HmacSHA256; string nonce = Guid.NewGuid().ToString(); string date = AWSSDKUtils.FormattedCurrentTimestampRFC822; bool isHttps = IsHttpsRequest(request); // Temporarily disabling the AWS3 HTTPS signing scheme and only using AWS3 HTTP isHttps = false; request.Headers["Date"] = date; request.Headers["X-Amz-Date"] = date; // AWS3 HTTP requires that we sign the Host header // so we have to have it in the request by the time we sign. string hostHeader = request.Endpoint.Host; if (!request.Endpoint.IsDefaultPort) { hostHeader += ":" + request.Endpoint.Port; } request.Headers["Host"] = hostHeader; byte[] bytesToSign; string stringToSign; if (isHttps) { request.Headers[NONCE_HEADER] = nonce; stringToSign = date + nonce; bytesToSign = Encoding.UTF8.GetBytes(stringToSign); } else { Uri url = request.Endpoint; if (!string.IsNullOrEmpty(request.ResourcePath)) { url = new Uri(request.Endpoint, request.ResourcePath); } stringToSign = request.HttpMethod + "\n" + GetCanonicalizedResourcePath(url) + "\n" + GetCanonicalizedQueryString(request.Parameters) + "\n" + GetCanonicalizedHeadersForStringToSign(request) + "\n" + GetRequestPayload(request); bytesToSign = CanonicalizationHash.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)); } string signature = ComputeHash(bytesToSign, awsSecretAccessKey, secureKey, algorithm); StringBuilder builder = new StringBuilder(); builder.Append(isHttps ? HTTPS_SCHEME : HTTP_SCHEME); builder.Append(" "); builder.Append("AWSAccessKeyId=" + awsAccessKeyId + ","); builder.Append("Algorithm=" + algorithm.ToString() + ","); if (!isHttps) { builder.Append(GetSignedHeadersComponent(request) + ","); } builder.Append("Signature=" + signature); string authorizationHeader = builder.ToString(); request.Headers[AUTHORIZATION_HEADER] = authorizationHeader; }