Example #1
0
        /// <summary>
        /// Constructs the signed trailing headers, optionally including
        /// the selected checksum for this stream's data. For example:
        /// trailing-header-A:value CRLF
        /// trailing-header-B:value CRLF
        /// x-amz-trailer-signature:signature_value CRLF
        /// CRLF
        /// </summary>
        /// <returns>Stream chunk containing the trailing headers and their signature</returns>
        private string ConstructSignedTrailersChunk()
        {
            // If the trailing headers included a trailing checksum, set the hash value
            if (_hashAlgorithm != null)
            {
                _hashAlgorithm.TransformFinalBlock(new byte[0], 0, 0);
                _trailingHeaders[ChecksumUtils.GetChecksumHeaderKey(_trailingChecksum)] = Convert.ToBase64String(_hashAlgorithm.Hash);
            }

            string chunkSignature;

            if (HeaderSigningResult is AWS4SigningResult)
            {
                var sortedTrailingHeaders        = AWS4Signer.SortAndPruneHeaders(_trailingHeaders);
                var canonicalizedTrailingHeaders = AWS4Signer.CanonicalizeHeaders(sortedTrailingHeaders);

                var chunkStringToSign =
                    TRAILING_HEADER_STRING_TO_SIGN_PREFIX + "\n" +
                    HeaderSigningResult.ISO8601DateTime + "\n" +
                    HeaderSigningResult.Scope + "\n" +
                    PreviousChunkSignature + "\n" +
                    AWSSDKUtils.ToHex(AWS4Signer.ComputeHash(canonicalizedTrailingHeaders), true);

                chunkSignature = AWSSDKUtils.ToHex(AWS4Signer.SignBlob(((AWS4SigningResult)HeaderSigningResult).GetSigningKey(), chunkStringToSign), true);
            }
            else // SigV4a
            {
                chunkSignature = Sigv4aSigner.SignTrailingHeaderChunk(_trailingHeaders, PreviousChunkSignature, (AWS4aSigningResult)HeaderSigningResult).PadRight(V4A_SIGNATURE_LENGTH, '*');
            }

            var chunk = new StringBuilder();

            // The order here must match the order of keys sent already in the X-Amz-Trailer header.
            foreach (var kvp in _trailingHeaders.OrderBy(kvp => kvp.Key))
            {
                chunk.Append($"{kvp.Key}:{kvp.Value}{STREAM_NEWLINE}");
            }
            chunk.Append($"{TRAILING_HEADER_SIGNATURE_KEY}:{chunkSignature}{STREAM_NEWLINE}");
            chunk.Append(STREAM_NEWLINE);
            return(chunk.ToString());
        }
Example #2
0
        /// <summary>
        /// Computes the derived signature for a chunk of data of given length in the input buffer,
        /// placing a formatted chunk with headers, signature and data into the output buffer
        /// ready for streaming back to the consumer.
        /// </summary>
        /// <param name="dataLen"></param>
        private void ConstructOutputBufferChunk(int dataLen)
        {
            // if the input wasn't sufficient to fill the buffer, size it
            // down to make the subseqent hashing/computations easier since
            // they don't take any length arguments
            if (dataLen > 0 && dataLen < _inputBuffer.Length)
            {
                var temp = new byte[dataLen];
                Buffer.BlockCopy(_inputBuffer, 0, temp, 0, dataLen);
                _inputBuffer = temp;
            }

            var chunkHeader = new StringBuilder();

            // variable-length size of the embedded chunk data in hex
            chunkHeader.Append(dataLen.ToString("X", CultureInfo.InvariantCulture));

            string chunkSignature = "";

            if (HeaderSigningResult is AWS4aSigningResult v4aHeaderSigningResult)
            {
                if (dataLen == 0)   // _inputBuffer still contains previous chunk, but this is the final 0 content chunk so sign null
                {
                    chunkSignature = Sigv4aSigner.SignChunk(null, PreviousChunkSignature, v4aHeaderSigningResult);
                }
                else
                {
                    chunkSignature = Sigv4aSigner.SignChunk(new MemoryStream(_inputBuffer), PreviousChunkSignature, v4aHeaderSigningResult);
                }
            }
            else if (HeaderSigningResult is AWS4SigningResult v4HeaderSingingResult) // SigV4
            {
                var chunkStringToSign = BuildChunkedStringToSign(CHUNK_STRING_TO_SIGN_PREFIX, v4HeaderSingingResult.ISO8601DateTime,
                                                                 v4HeaderSingingResult.Scope, PreviousChunkSignature, dataLen, _inputBuffer);

                chunkSignature = AWSSDKUtils.ToHex(AWS4Signer.SignBlob(v4HeaderSingingResult.GetSigningKey(), chunkStringToSign), true);
            }

            // For Sigv4a the chunk signature must be padded when being appended to the chunk metadata,
            // but not when being used as the input for the next chunk
            PreviousChunkSignature = chunkSignature;
            if (HeaderSigningResult is AWS4aSigningResult)
            {
                chunkHeader.Append(CHUNK_SIGNATURE_HEADER + chunkSignature.PadRight(V4A_SIGNATURE_LENGTH, '*'));
            }
            else // SigV4
            {
                chunkHeader.Append(CHUNK_SIGNATURE_HEADER + chunkSignature);
            }
            chunkHeader.Append(CLRF);

            try
            {
                var header  = Encoding.UTF8.GetBytes(chunkHeader.ToString());
                var trailer = Encoding.UTF8.GetBytes(CLRF);

                var writePos = 0;
                Buffer.BlockCopy(header, 0, _outputBuffer, writePos, header.Length);
                writePos += header.Length;
                if (dataLen > 0)
                {
                    Buffer.BlockCopy(_inputBuffer, 0, _outputBuffer, writePos, dataLen);
                    writePos += dataLen;
                }
                Buffer.BlockCopy(trailer, 0, _outputBuffer, writePos, trailer.Length);

                _outputBufferPos     = 0;
                _outputBufferDataLen = header.Length + dataLen + trailer.Length;
            }
            catch (Exception e)
            {
                throw new AmazonClientException("Unable to sign the chunked data. " + e.Message, e);
            }
        }