diff options
Diffstat (limited to 'drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c')
-rw-r--r-- | drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c | 1347 |
1 files changed, 0 insertions, 1347 deletions
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c deleted file mode 100644 index 299116d..0000000 --- a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c +++ /dev/null @@ -1,1347 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <assert.h> -#include <ctype.h> -#include <fcntl.h> -#include <limits.h> -#include <pthread.h> -#include <string.h> -#include <sys/stat.h> -#include <unistd.h> -#include <openssl/aes.h> -#include <openssl/hmac.h> - -#include "FwdLockConv.h" -#include "FwdLockGlue.h" - -#define TRUE 1 -#define FALSE 0 - -#define INVALID_OFFSET ((off64_t)-1) - -#define MAX_NUM_SESSIONS 32 - -#define OUTPUT_BUFFER_SIZE_INCREMENT 1024 -#define READ_BUFFER_SIZE 1024 - -#define MAX_BOUNDARY_LENGTH 70 -#define MAX_DELIMITER_LENGTH (MAX_BOUNDARY_LENGTH + 4) - -#define STRING_LENGTH_INCREMENT 25 - -#define KEY_SIZE AES_BLOCK_SIZE -#define KEY_SIZE_IN_BITS (KEY_SIZE * 8) - -#define SHA1_HASH_SIZE 20 - -#define FWD_LOCK_VERSION 0 -#define FWD_LOCK_SUBFORMAT 0 -#define USAGE_RESTRICTION_FLAGS 0 -#define CONTENT_TYPE_LENGTH_POS 7 -#define TOP_HEADER_SIZE 8 - -/** - * Data type for the parser states of the converter. - */ -typedef enum FwdLockConv_ParserState { - FwdLockConv_ParserState_WantsOpenDelimiter, - FwdLockConv_ParserState_WantsMimeHeaders, - FwdLockConv_ParserState_WantsBinaryEncodedData, - FwdLockConv_ParserState_WantsBase64EncodedData, - FwdLockConv_ParserState_Done -} FwdLockConv_ParserState_t; - -/** - * Data type for the scanner states of the converter. - */ -typedef enum FwdLockConv_ScannerState { - FwdLockConv_ScannerState_WantsFirstDash, - FwdLockConv_ScannerState_WantsSecondDash, - FwdLockConv_ScannerState_WantsCR, - FwdLockConv_ScannerState_WantsLF, - FwdLockConv_ScannerState_WantsBoundary, - FwdLockConv_ScannerState_WantsBoundaryEnd, - FwdLockConv_ScannerState_WantsMimeHeaderNameStart, - FwdLockConv_ScannerState_WantsMimeHeaderName, - FwdLockConv_ScannerState_WantsMimeHeaderNameEnd, - FwdLockConv_ScannerState_WantsContentTypeStart, - FwdLockConv_ScannerState_WantsContentType, - FwdLockConv_ScannerState_WantsContentTransferEncodingStart, - FwdLockConv_ScannerState_Wants_A_OR_I, - FwdLockConv_ScannerState_Wants_N, - FwdLockConv_ScannerState_Wants_A, - FwdLockConv_ScannerState_Wants_R, - FwdLockConv_ScannerState_Wants_Y, - FwdLockConv_ScannerState_Wants_S, - FwdLockConv_ScannerState_Wants_E, - FwdLockConv_ScannerState_Wants_6, - FwdLockConv_ScannerState_Wants_4, - FwdLockConv_ScannerState_Wants_B, - FwdLockConv_ScannerState_Wants_I, - FwdLockConv_ScannerState_Wants_T, - FwdLockConv_ScannerState_WantsContentTransferEncodingEnd, - FwdLockConv_ScannerState_WantsMimeHeaderValueEnd, - FwdLockConv_ScannerState_WantsMimeHeadersEnd, - FwdLockConv_ScannerState_WantsByte1, - FwdLockConv_ScannerState_WantsByte1_AfterCRLF, - FwdLockConv_ScannerState_WantsByte2, - FwdLockConv_ScannerState_WantsByte3, - FwdLockConv_ScannerState_WantsByte4, - FwdLockConv_ScannerState_WantsPadding, - FwdLockConv_ScannerState_WantsWhitespace, - FwdLockConv_ScannerState_WantsWhitespace_AfterCRLF, - FwdLockConv_ScannerState_WantsDelimiter -} FwdLockConv_ScannerState_t; - -/** - * Data type for the content transfer encoding. - */ -typedef enum FwdLockConv_ContentTransferEncoding { - FwdLockConv_ContentTransferEncoding_Undefined, - FwdLockConv_ContentTransferEncoding_Binary, - FwdLockConv_ContentTransferEncoding_Base64 -} FwdLockConv_ContentTransferEncoding_t; - -/** - * Data type for a dynamically growing string. - */ -typedef struct FwdLockConv_String { - char *ptr; - size_t length; - size_t maxLength; - size_t lengthIncrement; -} FwdLockConv_String_t; - -/** - * Data type for the per-file state information needed by the converter. - */ -typedef struct FwdLockConv_Session { - FwdLockConv_ParserState_t parserState; - FwdLockConv_ScannerState_t scannerState; - FwdLockConv_ScannerState_t savedScannerState; - off64_t numCharsConsumed; - char delimiter[MAX_DELIMITER_LENGTH]; - size_t delimiterLength; - size_t delimiterMatchPos; - FwdLockConv_String_t mimeHeaderName; - FwdLockConv_String_t contentType; - FwdLockConv_ContentTransferEncoding_t contentTransferEncoding; - unsigned char sessionKey[KEY_SIZE]; - void *pEncryptedSessionKey; - size_t encryptedSessionKeyLength; - AES_KEY encryptionRoundKeys; - HMAC_CTX signingContext; - unsigned char topHeader[TOP_HEADER_SIZE]; - unsigned char counter[AES_BLOCK_SIZE]; - unsigned char keyStream[AES_BLOCK_SIZE]; - int keyStreamIndex; - unsigned char ch; - size_t outputBufferSize; - size_t dataOffset; - size_t numDataBytes; -} FwdLockConv_Session_t; - -static FwdLockConv_Session_t *sessionPtrs[MAX_NUM_SESSIONS] = { NULL }; - -static pthread_mutex_t sessionAcquisitionMutex = PTHREAD_MUTEX_INITIALIZER; - -static const FwdLockConv_String_t nullString = { NULL, 0, 0, STRING_LENGTH_INCREMENT }; - -static const unsigned char topHeaderTemplate[] = - { 'F', 'W', 'L', 'K', FWD_LOCK_VERSION, FWD_LOCK_SUBFORMAT, USAGE_RESTRICTION_FLAGS }; - -static const char strContent[] = "content-"; -static const char strType[] = "type"; -static const char strTransferEncoding[] = "transfer-encoding"; -static const char strTextPlain[] = "text/plain"; -static const char strApplicationVndOmaDrmRightsXml[] = "application/vnd.oma.drm.rights+xml"; -static const char strApplicationVndOmaDrmContent[] = "application/vnd.oma.drm.content"; - -static const size_t strlenContent = sizeof strContent - 1; -static const size_t strlenTextPlain = sizeof strTextPlain - 1; - -static const signed char base64Values[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 -}; - -/** - * Acquires an unused converter session. - * - * @return A session ID. - */ -static int FwdLockConv_AcquireSession() { - int sessionId = -1; - int i; - pthread_mutex_lock(&sessionAcquisitionMutex); - for (i = 0; i < MAX_NUM_SESSIONS; ++i) { - if (sessionPtrs[i] == NULL) { - sessionPtrs[i] = malloc(sizeof *sessionPtrs[i]); - if (sessionPtrs[i] != NULL) { - sessionId = i; - } - break; - } - } - pthread_mutex_unlock(&sessionAcquisitionMutex); - return sessionId; -} - -/** - * Checks whether a session ID is in range and currently in use. - * - * @param[in] sessionID A session ID. - * - * @return A Boolean value indicating whether the session ID is in range and currently in use. - */ -static int FwdLockConv_IsValidSession(int sessionId) { - return 0 <= sessionId && sessionId < MAX_NUM_SESSIONS && sessionPtrs[sessionId] != NULL; -} - -/** - * Releases a converter session. - * - * @param[in] sessionID A session ID. - */ -static void FwdLockConv_ReleaseSession(int sessionId) { - pthread_mutex_lock(&sessionAcquisitionMutex); - assert(FwdLockConv_IsValidSession(sessionId)); - memset(sessionPtrs[sessionId], 0, sizeof *sessionPtrs[sessionId]); // Zero out key data. - free(sessionPtrs[sessionId]); - sessionPtrs[sessionId] = NULL; - pthread_mutex_unlock(&sessionAcquisitionMutex); -} - -/** - * Derives cryptographically independent keys for encryption and signing from the session key. - * - * @param[in,out] pSession A reference to a converter session. - * - * @return A status code. - */ -static int FwdLockConv_DeriveKeys(FwdLockConv_Session_t *pSession) { - FwdLockConv_Status_t status; - struct FwdLockConv_DeriveKeys_Data { - AES_KEY sessionRoundKeys; - unsigned char value[KEY_SIZE]; - unsigned char key[KEY_SIZE]; - } *pData = malloc(sizeof *pData); - if (pData == NULL) { - status = FwdLockConv_Status_OutOfMemory; - } else { - if (AES_set_encrypt_key(pSession->sessionKey, KEY_SIZE_IN_BITS, - &pData->sessionRoundKeys) != 0) { - status = FwdLockConv_Status_ProgramError; - } else { - // Encrypt the 16-byte value {0, 0, ..., 0} to produce the encryption key. - memset(pData->value, 0, KEY_SIZE); - AES_encrypt(pData->value, pData->key, &pData->sessionRoundKeys); - if (AES_set_encrypt_key(pData->key, KEY_SIZE_IN_BITS, - &pSession->encryptionRoundKeys) != 0) { - status = FwdLockConv_Status_ProgramError; - } else { - // Encrypt the 16-byte value {1, 0, ..., 0} to produce the signing key. - ++pData->value[0]; - AES_encrypt(pData->value, pData->key, &pData->sessionRoundKeys); - HMAC_CTX_init(&pSession->signingContext); - HMAC_Init_ex(&pSession->signingContext, pData->key, KEY_SIZE, EVP_sha1(), NULL); - status = FwdLockConv_Status_OK; - } - } - memset(pData, 0, sizeof pData); // Zero out key data. - free(pData); - } - return status; -} - -/** - * Checks whether a given character is valid in a boundary. Allows some non-standard characters that - * are invalid according to RFC 2046 but nevertheless used by one vendor's DRM packager. Note that - * the boundary may contain leading and internal spaces. - * - * @param[in] ch The character to check. - * - * @return A Boolean value indicating whether the given character is valid in a boundary. - */ -static int FwdLockConv_IsBoundaryChar(int ch) { - return isalnum(ch) || ch == '\'' || ch == '(' || ch == ')' || ch == '+' || ch == '_' || - ch == ',' || ch == '-' || ch == '.' || ch == '/' || ch == ':' || ch == '=' || - ch == '?' || ch == ' ' || ch == '%' || ch == '[' || ch == '&' || ch == '*' || ch == '^'; -} - -/** - * Checks whether a given character should be considered whitespace, using a narrower definition - * than the standard-library isspace() function. - * - * @param[in] ch The character to check. - * - * @return A Boolean value indicating whether the given character should be considered whitespace. - */ -static int FwdLockConv_IsWhitespace(int ch) { - return ch == ' ' || ch == '\t'; -} - -/** - * Removes trailing spaces from the delimiter. - * - * @param[in,out] pSession A reference to a converter session. - * - * @return A status code. - */ -static FwdLockConv_Status_t FwdLockConv_RightTrimDelimiter(FwdLockConv_Session_t *pSession) { - while (pSession->delimiterLength > 4 && - pSession->delimiter[pSession->delimiterLength - 1] == ' ') { - --pSession->delimiterLength; - } - if (pSession->delimiterLength > 4) { - return FwdLockConv_Status_OK; - } - return FwdLockConv_Status_SyntaxError; -} - -/** - * Matches the open delimiter. - * - * @param[in,out] pSession A reference to a converter session. - * @param[in] ch A character. - * - * @return A status code. - */ -static FwdLockConv_Status_t FwdLockConv_MatchOpenDelimiter(FwdLockConv_Session_t *pSession, - int ch) { - FwdLockConv_Status_t status = FwdLockConv_Status_OK; - switch (pSession->scannerState) { - case FwdLockConv_ScannerState_WantsFirstDash: - if (ch == '-') { - pSession->scannerState = FwdLockConv_ScannerState_WantsSecondDash; - } else if (ch == '\r') { - pSession->scannerState = FwdLockConv_ScannerState_WantsLF; - } else { - pSession->scannerState = FwdLockConv_ScannerState_WantsCR; - } - break; - case FwdLockConv_ScannerState_WantsSecondDash: - if (ch == '-') { - // The delimiter starts with "\r\n--" (the open delimiter may omit the initial "\r\n"). - // The rest is the user-defined boundary that should come next. - pSession->delimiter[0] = '\r'; - pSession->delimiter[1] = '\n'; - pSession->delimiter[2] = '-'; - pSession->delimiter[3] = '-'; - pSession->delimiterLength = 4; - pSession->scannerState = FwdLockConv_ScannerState_WantsBoundary; - } else if (ch == '\r') { - pSession->scannerState = FwdLockConv_ScannerState_WantsLF; - } else { - pSession->scannerState = FwdLockConv_ScannerState_WantsCR; - } - break; - case FwdLockConv_ScannerState_WantsCR: - if (ch == '\r') { - pSession->scannerState = FwdLockConv_ScannerState_WantsLF; - } - break; - case FwdLockConv_ScannerState_WantsLF: - if (ch == '\n') { - pSession->scannerState = FwdLockConv_ScannerState_WantsFirstDash; - } else if (ch != '\r') { - pSession->scannerState = FwdLockConv_ScannerState_WantsCR; - } - break; - case FwdLockConv_ScannerState_WantsBoundary: - if (FwdLockConv_IsBoundaryChar(ch)) { - // The boundary may contain leading and internal spaces, so trailing spaces will also be - // matched here. These will be removed later. - if (pSession->delimiterLength < MAX_DELIMITER_LENGTH) { - pSession->delimiter[pSession->delimiterLength++] = ch; - } else if (ch != ' ') { - status = FwdLockConv_Status_SyntaxError; - } - } else if (ch == '\r') { - status = FwdLockConv_RightTrimDelimiter(pSession); - if (status == FwdLockConv_Status_OK) { - pSession->scannerState = FwdLockConv_ScannerState_WantsBoundaryEnd; - } - } else if (ch == '\t') { - status = FwdLockConv_RightTrimDelimiter(pSession); - if (status == FwdLockConv_Status_OK) { - pSession->scannerState = FwdLockConv_ScannerState_WantsWhitespace; - } - } else { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsWhitespace: - if (ch == '\r') { - pSession->scannerState = FwdLockConv_ScannerState_WantsBoundaryEnd; - } else if (!FwdLockConv_IsWhitespace(ch)) { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsBoundaryEnd: - if (ch == '\n') { - pSession->parserState = FwdLockConv_ParserState_WantsMimeHeaders; - pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderNameStart; - } else { - status = FwdLockConv_Status_SyntaxError; - } - break; - default: - status = FwdLockConv_Status_ProgramError; - break; - } - return status; -} - -/** - * Checks whether a given character is valid in a MIME header name. - * - * @param[in] ch The character to check. - * - * @return A Boolean value indicating whether the given character is valid in a MIME header name. - */ -static int FwdLockConv_IsMimeHeaderNameChar(int ch) { - return isgraph(ch) && ch != ':'; -} - -/** - * Checks whether a given character is valid in a MIME header value. - * - * @param[in] ch The character to check. - * - * @return A Boolean value indicating whether the given character is valid in a MIME header value. - */ -static int FwdLockConv_IsMimeHeaderValueChar(int ch) { - return isgraph(ch) && ch != ';'; -} - -/** - * Appends a character to the specified dynamically growing string. - * - * @param[in,out] pString A reference to a dynamically growing string. - * @param[in] ch The character to append. - * - * @return A status code. - */ -static FwdLockConv_Status_t FwdLockConv_StringAppend(FwdLockConv_String_t *pString, int ch) { - if (pString->length == pString->maxLength) { - size_t newMaxLength = pString->maxLength + pString->lengthIncrement; - char *newPtr = realloc(pString->ptr, newMaxLength + 1); - if (newPtr == NULL) { - return FwdLockConv_Status_OutOfMemory; - } - pString->ptr = newPtr; - pString->maxLength = newMaxLength; - } - pString->ptr[pString->length++] = ch; - pString->ptr[pString->length] = '\0'; - return FwdLockConv_Status_OK; -} - -/** - * Attempts to recognize the MIME header name and changes the scanner state accordingly. - * - * @param[in,out] pSession A reference to a converter session. - * - * @return A status code. - */ -static FwdLockConv_Status_t FwdLockConv_RecognizeMimeHeaderName(FwdLockConv_Session_t *pSession) { - FwdLockConv_Status_t status = FwdLockConv_Status_OK; - if (strncmp(pSession->mimeHeaderName.ptr, strContent, strlenContent) == 0) { - if (strcmp(pSession->mimeHeaderName.ptr + strlenContent, strType) == 0) { - if (pSession->contentType.ptr == NULL) { - pSession->scannerState = FwdLockConv_ScannerState_WantsContentTypeStart; - } else { - status = FwdLockConv_Status_SyntaxError; - } - } else if (strcmp(pSession->mimeHeaderName.ptr + strlenContent, strTransferEncoding) == 0) { - if (pSession->contentTransferEncoding == - FwdLockConv_ContentTransferEncoding_Undefined) { - pSession->scannerState = FwdLockConv_ScannerState_WantsContentTransferEncodingStart; - } else { - status = FwdLockConv_Status_SyntaxError; - } - } else { - pSession->scannerState = FwdLockConv_ScannerState_WantsCR; - } - } else { - pSession->scannerState = FwdLockConv_ScannerState_WantsCR; - } - return status; -} - -/** - * Applies defaults to missing MIME header values. - * - * @param[in,out] pSession A reference to a converter session. - * - * @return A status code. - */ -static FwdLockConv_Status_t FwdLockConv_ApplyDefaults(FwdLockConv_Session_t *pSession) { - if (pSession->contentType.ptr == NULL) { - // Content type is missing: default to "text/plain". - pSession->contentType.ptr = malloc(sizeof strTextPlain); - if (pSession->contentType.ptr == NULL) { - return FwdLockConv_Status_OutOfMemory; - } - memcpy(pSession->contentType.ptr, strTextPlain, sizeof strTextPlain); - pSession->contentType.length = strlenTextPlain; - pSession->contentType.maxLength = strlenTextPlain; - } - if (pSession->contentTransferEncoding == FwdLockConv_ContentTransferEncoding_Undefined) { - // Content transfer encoding is missing: default to binary. - pSession->contentTransferEncoding = FwdLockConv_ContentTransferEncoding_Binary; - } - return FwdLockConv_Status_OK; -} - -/** - * Verifies that the content type is supported. - * - * @param[in,out] pSession A reference to a converter session. - * - * @return A status code. - */ -static FwdLockConv_Status_t FwdLockConv_VerifyContentType(FwdLockConv_Session_t *pSession) { - FwdLockConv_Status_t status; - if (pSession->contentType.ptr == NULL) { - status = FwdLockConv_Status_ProgramError; - } else if (strcmp(pSession->contentType.ptr, strApplicationVndOmaDrmRightsXml) == 0 || - strcmp(pSession->contentType.ptr, strApplicationVndOmaDrmContent) == 0) { - status = FwdLockConv_Status_UnsupportedFileFormat; - } else { - status = FwdLockConv_Status_OK; - } - return status; -} - -/** - * Writes the header of the output file. - * - * @param[in,out] pSession A reference to a converter session. - * @param[out] pOutput The output from the conversion process. - * - * @return A status code. - */ -static FwdLockConv_Status_t FwdLockConv_WriteHeader(FwdLockConv_Session_t *pSession, - FwdLockConv_Output_t *pOutput) { - FwdLockConv_Status_t status; - if (pSession->contentType.length > UCHAR_MAX) { - status = FwdLockConv_Status_SyntaxError; - } else { - pSession->outputBufferSize = OUTPUT_BUFFER_SIZE_INCREMENT; - pOutput->fromConvertData.pBuffer = malloc(pSession->outputBufferSize); - if (pOutput->fromConvertData.pBuffer == NULL) { - status = FwdLockConv_Status_OutOfMemory; - } else { - size_t encryptedSessionKeyPos = TOP_HEADER_SIZE + pSession->contentType.length; - size_t dataSignaturePos = encryptedSessionKeyPos + pSession->encryptedSessionKeyLength; - size_t headerSignaturePos = dataSignaturePos + SHA1_HASH_SIZE; - pSession->dataOffset = headerSignaturePos + SHA1_HASH_SIZE; - memcpy(pSession->topHeader, topHeaderTemplate, sizeof topHeaderTemplate); - pSession->topHeader[CONTENT_TYPE_LENGTH_POS] = - (unsigned char)pSession->contentType.length; - memcpy(pOutput->fromConvertData.pBuffer, pSession->topHeader, TOP_HEADER_SIZE); - memcpy((char *)pOutput->fromConvertData.pBuffer + TOP_HEADER_SIZE, - pSession->contentType.ptr, pSession->contentType.length); - memcpy((char *)pOutput->fromConvertData.pBuffer + encryptedSessionKeyPos, - pSession->pEncryptedSessionKey, pSession->encryptedSessionKeyLength); - - // Set the signatures to all zeros for now; they will have to be updated later. - memset((char *)pOutput->fromConvertData.pBuffer + dataSignaturePos, 0, - SHA1_HASH_SIZE); - memset((char *)pOutput->fromConvertData.pBuffer + headerSignaturePos, 0, - SHA1_HASH_SIZE); - - pOutput->fromConvertData.numBytes = pSession->dataOffset; - status = FwdLockConv_Status_OK; - } - } - return status; -} - -/** - * Matches the MIME headers. - * - * @param[in,out] pSession A reference to a converter session. - * @param[in] ch A character. - * @param[out] pOutput The output from the conversion process. - * - * @return A status code. - */ -static FwdLockConv_Status_t FwdLockConv_MatchMimeHeaders(FwdLockConv_Session_t *pSession, - int ch, - FwdLockConv_Output_t *pOutput) { - FwdLockConv_Status_t status = FwdLockConv_Status_OK; - switch (pSession->scannerState) { - case FwdLockConv_ScannerState_WantsMimeHeaderNameStart: - if (FwdLockConv_IsMimeHeaderNameChar(ch)) { - pSession->mimeHeaderName.length = 0; - status = FwdLockConv_StringAppend(&pSession->mimeHeaderName, tolower(ch)); - if (status == FwdLockConv_Status_OK) { - pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderName; - } - } else if (ch == '\r') { - pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeadersEnd; - } else if (!FwdLockConv_IsWhitespace(ch)) { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsMimeHeaderName: - if (FwdLockConv_IsMimeHeaderNameChar(ch)) { - status = FwdLockConv_StringAppend(&pSession->mimeHeaderName, tolower(ch)); - } else if (ch == ':') { - status = FwdLockConv_RecognizeMimeHeaderName(pSession); - } else if (FwdLockConv_IsWhitespace(ch)) { - pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderNameEnd; - } else { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsMimeHeaderNameEnd: - if (ch == ':') { - status = FwdLockConv_RecognizeMimeHeaderName(pSession); - } else if (!FwdLockConv_IsWhitespace(ch)) { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsContentTypeStart: - if (FwdLockConv_IsMimeHeaderValueChar(ch)) { - status = FwdLockConv_StringAppend(&pSession->contentType, tolower(ch)); - if (status == FwdLockConv_Status_OK) { - pSession->scannerState = FwdLockConv_ScannerState_WantsContentType; - } - } else if (!FwdLockConv_IsWhitespace(ch)) { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsContentType: - if (FwdLockConv_IsMimeHeaderValueChar(ch)) { - status = FwdLockConv_StringAppend(&pSession->contentType, tolower(ch)); - } else if (ch == ';') { - pSession->scannerState = FwdLockConv_ScannerState_WantsCR; - } else if (ch == '\r') { - pSession->scannerState = FwdLockConv_ScannerState_WantsLF; - } else if (FwdLockConv_IsWhitespace(ch)) { - pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderValueEnd; - } else { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsContentTransferEncodingStart: - if (ch == 'b' || ch == 'B') { - pSession->scannerState = FwdLockConv_ScannerState_Wants_A_OR_I; - } else if (ch == '7' || ch == '8') { - pSession->scannerState = FwdLockConv_ScannerState_Wants_B; - } else if (!FwdLockConv_IsWhitespace(ch)) { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_Wants_A_OR_I: - if (ch == 'i' || ch == 'I') { - pSession->scannerState = FwdLockConv_ScannerState_Wants_N; - } else if (ch == 'a' || ch == 'A') { - pSession->scannerState = FwdLockConv_ScannerState_Wants_S; - } else { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_Wants_N: - if (ch == 'n' || ch == 'N') { - pSession->scannerState = FwdLockConv_ScannerState_Wants_A; - } else { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_Wants_A: - if (ch == 'a' || ch == 'A') { - pSession->scannerState = FwdLockConv_ScannerState_Wants_R; - } else { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_Wants_R: - if (ch == 'r' || ch == 'R') { - pSession->scannerState = FwdLockConv_ScannerState_Wants_Y; - } else { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_Wants_Y: - if (ch == 'y' || ch == 'Y') { - pSession->contentTransferEncoding = FwdLockConv_ContentTransferEncoding_Binary; - pSession->scannerState = FwdLockConv_ScannerState_WantsContentTransferEncodingEnd; - } else { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_Wants_S: - if (ch == 's' || ch == 'S') { - pSession->scannerState = FwdLockConv_ScannerState_Wants_E; - } else { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_Wants_E: - if (ch == 'e' || ch == 'E') { - pSession->scannerState = FwdLockConv_ScannerState_Wants_6; - } else { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_Wants_6: - if (ch == '6') { - pSession->scannerState = FwdLockConv_ScannerState_Wants_4; - } else { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_Wants_4: - if (ch == '4') { - pSession->contentTransferEncoding = FwdLockConv_ContentTransferEncoding_Base64; - pSession->scannerState = FwdLockConv_ScannerState_WantsContentTransferEncodingEnd; - } else { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_Wants_B: - if (ch == 'b' || ch == 'B') { - pSession->scannerState = FwdLockConv_ScannerState_Wants_I; - } else { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_Wants_I: - if (ch == 'i' || ch == 'I') { - pSession->scannerState = FwdLockConv_ScannerState_Wants_T; - } else { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_Wants_T: - if (ch == 't' || ch == 'T') { - pSession->contentTransferEncoding = FwdLockConv_ContentTransferEncoding_Binary; - pSession->scannerState = FwdLockConv_ScannerState_WantsContentTransferEncodingEnd; - } else { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_WantsContentTransferEncodingEnd: - if (ch == ';') { - pSession->scannerState = FwdLockConv_ScannerState_WantsCR; - } else if (ch == '\r') { - pSession->scannerState = FwdLockConv_ScannerState_WantsLF; - } else if (FwdLockConv_IsWhitespace(ch)) { - pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderValueEnd; - } else { - status = FwdLockConv_Status_UnsupportedContentTransferEncoding; - } - break; - case FwdLockConv_ScannerState_WantsMimeHeaderValueEnd: - if (ch == ';') { - pSession->scannerState = FwdLockConv_ScannerState_WantsCR; - } else if (ch == '\r') { - pSession->scannerState = FwdLockConv_ScannerState_WantsLF; - } else if (!FwdLockConv_IsWhitespace(ch)) { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsCR: - if (ch == '\r') { - pSession->scannerState = FwdLockConv_ScannerState_WantsLF; - } - break; - case FwdLockConv_ScannerState_WantsLF: - if (ch == '\n') { - pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderNameStart; - } else { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsMimeHeadersEnd: - if (ch == '\n') { - status = FwdLockConv_ApplyDefaults(pSession); - if (status == FwdLockConv_Status_OK) { - status = FwdLockConv_VerifyContentType(pSession); - } - if (status == FwdLockConv_Status_OK) { - status = FwdLockConv_WriteHeader(pSession, pOutput); - } - if (status == FwdLockConv_Status_OK) { - if (pSession->contentTransferEncoding == - FwdLockConv_ContentTransferEncoding_Binary) { - pSession->parserState = FwdLockConv_ParserState_WantsBinaryEncodedData; - } else { - pSession->parserState = FwdLockConv_ParserState_WantsBase64EncodedData; - } - pSession->scannerState = FwdLockConv_ScannerState_WantsByte1; - } - } else { - status = FwdLockConv_Status_SyntaxError; - } - break; - default: - status = FwdLockConv_Status_ProgramError; - break; - } - return status; -} - -/** - * Increments the counter, treated as a 16-byte little-endian number, by one. - * - * @param[in,out] pSession A reference to a converter session. - */ -static void FwdLockConv_IncrementCounter(FwdLockConv_Session_t *pSession) { - size_t i = 0; - while ((++pSession->counter[i] == 0) && (++i < AES_BLOCK_SIZE)) - ; -} - -/** - * Encrypts the given character and writes it to the output buffer. - * - * @param[in,out] pSession A reference to a converter session. - * @param[in] ch The character to encrypt and write. - * @param[in,out] pOutput The output from the conversion process. - * - * @return A status code. - */ -static FwdLockConv_Status_t FwdLockConv_WriteEncryptedChar(FwdLockConv_Session_t *pSession, - unsigned char ch, - FwdLockConv_Output_t *pOutput) { - if (pOutput->fromConvertData.numBytes == pSession->outputBufferSize) { - void *pBuffer; - pSession->outputBufferSize += OUTPUT_BUFFER_SIZE_INCREMENT; - pBuffer = realloc(pOutput->fromConvertData.pBuffer, pSession->outputBufferSize); - if (pBuffer == NULL) { - return FwdLockConv_Status_OutOfMemory; - } - pOutput->fromConvertData.pBuffer = pBuffer; - } - if (++pSession->keyStreamIndex == AES_BLOCK_SIZE) { - FwdLockConv_IncrementCounter(pSession); - pSession->keyStreamIndex = 0; - } - if (pSession->keyStreamIndex == 0) { - AES_encrypt(pSession->counter, pSession->keyStream, &pSession->encryptionRoundKeys); - } - ch ^= pSession->keyStream[pSession->keyStreamIndex]; - ((unsigned char *)pOutput->fromConvertData.pBuffer)[pOutput->fromConvertData.numBytes++] = ch; - ++pSession->numDataBytes; - return FwdLockConv_Status_OK; -} - -/** - * Matches binary-encoded content data and encrypts it, while looking out for the close delimiter. - * - * @param[in,out] pSession A reference to a converter session. - * @param[in] ch A character. - * @param[in,out] pOutput The output from the conversion process. - * - * @return A status code. - */ -static FwdLockConv_Status_t FwdLockConv_MatchBinaryEncodedData(FwdLockConv_Session_t *pSession, - int ch, - FwdLockConv_Output_t *pOutput) { - FwdLockConv_Status_t status = FwdLockConv_Status_OK; - switch (pSession->scannerState) { - case FwdLockConv_ScannerState_WantsByte1: - if (ch != pSession->delimiter[pSession->delimiterMatchPos]) { - // The partial match of the delimiter turned out to be spurious. Flush the matched bytes - // to the output buffer and start over. - size_t i; - for (i = 0; i < pSession->delimiterMatchPos; ++i) { - status = FwdLockConv_WriteEncryptedChar(pSession, pSession->delimiter[i], pOutput); - if (status != FwdLockConv_Status_OK) { - return status; - } - } - pSession->delimiterMatchPos = 0; - } - if (ch != pSession->delimiter[pSession->delimiterMatchPos]) { - // The current character isn't part of the delimiter. Write it to the output buffer. - status = FwdLockConv_WriteEncryptedChar(pSession, ch, pOutput); - } else if (++pSession->delimiterMatchPos == pSession->delimiterLength) { - // The entire delimiter has been matched. The only valid characters now are the "--" - // that complete the close delimiter (no more message parts are expected). - pSession->scannerState = FwdLockConv_ScannerState_WantsFirstDash; - } - break; - case FwdLockConv_ScannerState_WantsFirstDash: - if (ch == '-') { - pSession->scannerState = FwdLockConv_ScannerState_WantsSecondDash; - } else { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsSecondDash: - if (ch == '-') { - pSession->parserState = FwdLockConv_ParserState_Done; - } else { - status = FwdLockConv_Status_SyntaxError; - } - break; - default: - status = FwdLockConv_Status_ProgramError; - break; - } - return status; -} - -/** - * Checks whether a given character is valid in base64-encoded data. - * - * @param[in] ch The character to check. - * - * @return A Boolean value indicating whether the given character is valid in base64-encoded data. - */ -static int FwdLockConv_IsBase64Char(int ch) { - return 0 <= ch && ch <= 'z' && base64Values[ch] >= 0; -} - -/** - * Matches base64-encoded content data and encrypts it, while looking out for the close delimiter. - * - * @param[in,out] pSession A reference to a converter session. - * @param[in] ch A character. - * @param[in,out] pOutput The output from the conversion process. - * - * @return A status code. - */ -static FwdLockConv_Status_t FwdLockConv_MatchBase64EncodedData(FwdLockConv_Session_t *pSession, - int ch, - FwdLockConv_Output_t *pOutput) { - FwdLockConv_Status_t status = FwdLockConv_Status_OK; - switch (pSession->scannerState) { - case FwdLockConv_ScannerState_WantsByte1: - case FwdLockConv_ScannerState_WantsByte1_AfterCRLF: - if (FwdLockConv_IsBase64Char(ch)) { - pSession->ch = base64Values[ch] << 2; - pSession->scannerState = FwdLockConv_ScannerState_WantsByte2; - } else if (ch == '\r') { - pSession->savedScannerState = FwdLockConv_ScannerState_WantsByte1_AfterCRLF; - pSession->scannerState = FwdLockConv_ScannerState_WantsLF; - } else if (ch == '-') { - if (pSession->scannerState == FwdLockConv_ScannerState_WantsByte1_AfterCRLF) { - pSession->delimiterMatchPos = 3; - pSession->scannerState = FwdLockConv_ScannerState_WantsDelimiter; - } else { - status = FwdLockConv_Status_SyntaxError; - } - } else if (!FwdLockConv_IsWhitespace(ch)) { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsByte2: - if (FwdLockConv_IsBase64Char(ch)) { - pSession->ch |= base64Values[ch] >> 4; - status = FwdLockConv_WriteEncryptedChar(pSession, pSession->ch, pOutput); - if (status == FwdLockConv_Status_OK) { - pSession->ch = base64Values[ch] << 4; - pSession->scannerState = FwdLockConv_ScannerState_WantsByte3; - } - } else if (ch == '\r') { - pSession->savedScannerState = pSession->scannerState; - pSession->scannerState = FwdLockConv_ScannerState_WantsLF; - } else if (!FwdLockConv_IsWhitespace(ch)) { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsByte3: - if (FwdLockConv_IsBase64Char(ch)) { - pSession->ch |= base64Values[ch] >> 2; - status = FwdLockConv_WriteEncryptedChar(pSession, pSession->ch, pOutput); - if (status == FwdLockConv_Status_OK) { - pSession->ch = base64Values[ch] << 6; - pSession->scannerState = FwdLockConv_ScannerState_WantsByte4; - } - } else if (ch == '\r') { - pSession->savedScannerState = pSession->scannerState; - pSession->scannerState = FwdLockConv_ScannerState_WantsLF; - } else if (ch == '=') { - pSession->scannerState = FwdLockConv_ScannerState_WantsPadding; - } else if (!FwdLockConv_IsWhitespace(ch)) { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsByte4: - if (FwdLockConv_IsBase64Char(ch)) { - pSession->ch |= base64Values[ch]; - status = FwdLockConv_WriteEncryptedChar(pSession, pSession->ch, pOutput); - if (status == FwdLockConv_Status_OK) { - pSession->scannerState = FwdLockConv_ScannerState_WantsByte1; - } - } else if (ch == '\r') { - pSession->savedScannerState = pSession->scannerState; - pSession->scannerState = FwdLockConv_ScannerState_WantsLF; - } else if (ch == '=') { - pSession->scannerState = FwdLockConv_ScannerState_WantsWhitespace; - } else if (!FwdLockConv_IsWhitespace(ch)) { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsLF: - if (ch == '\n') { - pSession->scannerState = pSession->savedScannerState; - } else { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsPadding: - if (ch == '=') { - pSession->scannerState = FwdLockConv_ScannerState_WantsWhitespace; - } else { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsWhitespace: - case FwdLockConv_ScannerState_WantsWhitespace_AfterCRLF: - if (ch == '\r') { - pSession->savedScannerState = FwdLockConv_ScannerState_WantsWhitespace_AfterCRLF; - pSession->scannerState = FwdLockConv_ScannerState_WantsLF; - } else if (ch == '-') { - if (pSession->scannerState == FwdLockConv_ScannerState_WantsWhitespace_AfterCRLF) { - pSession->delimiterMatchPos = 3; - pSession->scannerState = FwdLockConv_ScannerState_WantsDelimiter; - } else { - status = FwdLockConv_Status_SyntaxError; - } - } else if (FwdLockConv_IsWhitespace(ch)) { - pSession->scannerState = FwdLockConv_ScannerState_WantsWhitespace; - } else { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsDelimiter: - if (ch != pSession->delimiter[pSession->delimiterMatchPos]) { - status = FwdLockConv_Status_SyntaxError; - } else if (++pSession->delimiterMatchPos == pSession->delimiterLength) { - pSession->scannerState = FwdLockConv_ScannerState_WantsFirstDash; - } - break; - case FwdLockConv_ScannerState_WantsFirstDash: - if (ch == '-') { - pSession->scannerState = FwdLockConv_ScannerState_WantsSecondDash; - } else { - status = FwdLockConv_Status_SyntaxError; - } - break; - case FwdLockConv_ScannerState_WantsSecondDash: - if (ch == '-') { - pSession->parserState = FwdLockConv_ParserState_Done; - } else { - status = FwdLockConv_Status_SyntaxError; - } - break; - default: - status = FwdLockConv_Status_ProgramError; - break; - } - return status; -} - -/** - * Pushes a single character into the converter's state machine. - * - * @param[in,out] pSession A reference to a converter session. - * @param[in] ch A character. - * @param[in,out] pOutput The output from the conversion process. - * - * @return A status code. - */ -static FwdLockConv_Status_t FwdLockConv_PushChar(FwdLockConv_Session_t *pSession, - int ch, - FwdLockConv_Output_t *pOutput) { - FwdLockConv_Status_t status; - ++pSession->numCharsConsumed; - switch (pSession->parserState) { - case FwdLockConv_ParserState_WantsOpenDelimiter: - status = FwdLockConv_MatchOpenDelimiter(pSession, ch); - break; - case FwdLockConv_ParserState_WantsMimeHeaders: - status = FwdLockConv_MatchMimeHeaders(pSession, ch, pOutput); - break; - case FwdLockConv_ParserState_WantsBinaryEncodedData: - status = FwdLockConv_MatchBinaryEncodedData(pSession, ch, pOutput); - break; - case FwdLockConv_ParserState_WantsBase64EncodedData: - if (ch == '\n' && pSession->scannerState != FwdLockConv_ScannerState_WantsLF) { - // Repair base64-encoded data that doesn't have carriage returns in its line breaks. - status = FwdLockConv_MatchBase64EncodedData(pSession, '\r', pOutput); - if (status != FwdLockConv_Status_OK) { - break; - } - } - status = FwdLockConv_MatchBase64EncodedData(pSession, ch, pOutput); - break; - case FwdLockConv_ParserState_Done: - status = FwdLockConv_Status_OK; - break; - default: - status = FwdLockConv_Status_ProgramError; - break; - } - return status; -} - -FwdLockConv_Status_t FwdLockConv_OpenSession(int *pSessionId, FwdLockConv_Output_t *pOutput) { - FwdLockConv_Status_t status; - if (pSessionId == NULL || pOutput == NULL) { - status = FwdLockConv_Status_InvalidArgument; - } else { - *pSessionId = FwdLockConv_AcquireSession(); - if (*pSessionId < 0) { - status = FwdLockConv_Status_TooManySessions; - } else { - FwdLockConv_Session_t *pSession = sessionPtrs[*pSessionId]; - pSession->encryptedSessionKeyLength = FwdLockGlue_GetEncryptedKeyLength(KEY_SIZE); - if (pSession->encryptedSessionKeyLength < AES_BLOCK_SIZE) { - // The encrypted session key is used as the CTR-mode nonce, so it must be at least - // the size of a single AES block. - status = FwdLockConv_Status_ProgramError; - } else { - pSession->pEncryptedSessionKey = malloc(pSession->encryptedSessionKeyLength); - if (pSession->pEncryptedSessionKey == NULL) { - status = FwdLockConv_Status_OutOfMemory; - } else { - if (!FwdLockGlue_GetRandomNumber(pSession->sessionKey, KEY_SIZE)) { - status = FwdLockConv_Status_RandomNumberGenerationFailed; - } else if (!FwdLockGlue_EncryptKey(pSession->sessionKey, KEY_SIZE, - pSession->pEncryptedSessionKey, - pSession->encryptedSessionKeyLength)) { - status = FwdLockConv_Status_KeyEncryptionFailed; - } else { - status = FwdLockConv_DeriveKeys(pSession); - } - if (status == FwdLockConv_Status_OK) { - memset(pSession->sessionKey, 0, KEY_SIZE); // Zero out key data. - memcpy(pSession->counter, pSession->pEncryptedSessionKey, AES_BLOCK_SIZE); - pSession->parserState = FwdLockConv_ParserState_WantsOpenDelimiter; - pSession->scannerState = FwdLockConv_ScannerState_WantsFirstDash; - pSession->numCharsConsumed = 0; - pSession->delimiterMatchPos = 0; - pSession->mimeHeaderName = nullString; - pSession->contentType = nullString; - pSession->contentTransferEncoding = - FwdLockConv_ContentTransferEncoding_Undefined; - pSession->keyStreamIndex = -1; - pOutput->fromConvertData.pBuffer = NULL; - pOutput->fromConvertData.errorPos = INVALID_OFFSET; - } else { - free(pSession->pEncryptedSessionKey); - } - } - } - if (status != FwdLockConv_Status_OK) { - FwdLockConv_ReleaseSession(*pSessionId); - *pSessionId = -1; - } - } - } - return status; -} - -FwdLockConv_Status_t FwdLockConv_ConvertData(int sessionId, - const void *pBuffer, - size_t numBytes, - FwdLockConv_Output_t *pOutput) { - FwdLockConv_Status_t status; - if (!FwdLockConv_IsValidSession(sessionId) || pBuffer == NULL || pOutput == NULL) { - status = FwdLockConv_Status_InvalidArgument; - } else { - size_t i; - FwdLockConv_Session_t *pSession = sessionPtrs[sessionId]; - pSession->dataOffset = 0; - pSession->numDataBytes = 0; - pOutput->fromConvertData.numBytes = 0; - status = FwdLockConv_Status_OK; - - for (i = 0; i < numBytes; ++i) { - status = FwdLockConv_PushChar(pSession, ((char *)pBuffer)[i], pOutput); - if (status != FwdLockConv_Status_OK) { - break; - } - } - if (status == FwdLockConv_Status_OK) { - // Update the data signature. - HMAC_Update(&pSession->signingContext, - &((unsigned char *)pOutput->fromConvertData.pBuffer)[pSession->dataOffset], - pSession->numDataBytes); - } else if (status == FwdLockConv_Status_SyntaxError) { - pOutput->fromConvertData.errorPos = pSession->numCharsConsumed; - } - } - return status; -} - -FwdLockConv_Status_t FwdLockConv_CloseSession(int sessionId, FwdLockConv_Output_t *pOutput) { - FwdLockConv_Status_t status; - if (!FwdLockConv_IsValidSession(sessionId) || pOutput == NULL) { - status = FwdLockConv_Status_InvalidArgument; - } else { - FwdLockConv_Session_t *pSession = sessionPtrs[sessionId]; - free(pOutput->fromConvertData.pBuffer); - if (pSession->parserState != FwdLockConv_ParserState_Done) { - pOutput->fromCloseSession.errorPos = pSession->numCharsConsumed; - status = FwdLockConv_Status_SyntaxError; - } else { - // Finalize the data signature. - unsigned int signatureSize = SHA1_HASH_SIZE; - HMAC_Final(&pSession->signingContext, pOutput->fromCloseSession.signatures, - &signatureSize); - if (signatureSize != SHA1_HASH_SIZE) { - status = FwdLockConv_Status_ProgramError; - } else { - // Calculate the header signature, which is a signature of the rest of the header - // including the data signature. - HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL); - HMAC_Update(&pSession->signingContext, pSession->topHeader, TOP_HEADER_SIZE); - HMAC_Update(&pSession->signingContext, (unsigned char *)pSession->contentType.ptr, - pSession->contentType.length); - HMAC_Update(&pSession->signingContext, pSession->pEncryptedSessionKey, - pSession->encryptedSessionKeyLength); - HMAC_Update(&pSession->signingContext, pOutput->fromCloseSession.signatures, - SHA1_HASH_SIZE); - HMAC_Final(&pSession->signingContext, - &pOutput->fromCloseSession.signatures[SHA1_HASH_SIZE], &signatureSize); - if (signatureSize != SHA1_HASH_SIZE) { - status = FwdLockConv_Status_ProgramError; - } else { - pOutput->fromCloseSession.fileOffset = TOP_HEADER_SIZE + - pSession->contentType.length + pSession->encryptedSessionKeyLength; - status = FwdLockConv_Status_OK; - } - } - pOutput->fromCloseSession.errorPos = INVALID_OFFSET; - } - free(pSession->mimeHeaderName.ptr); - free(pSession->contentType.ptr); - free(pSession->pEncryptedSessionKey); - HMAC_CTX_cleanup(&pSession->signingContext); - FwdLockConv_ReleaseSession(sessionId); - } - return status; -} - -FwdLockConv_Status_t FwdLockConv_ConvertOpenFile(int inputFileDesc, - FwdLockConv_ReadFunc_t *fpReadFunc, - int outputFileDesc, - FwdLockConv_WriteFunc_t *fpWriteFunc, - FwdLockConv_LSeekFunc_t *fpLSeekFunc, - off64_t *pErrorPos) { - FwdLockConv_Status_t status; - if (pErrorPos != NULL) { - *pErrorPos = INVALID_OFFSET; - } - if (fpReadFunc == NULL || fpWriteFunc == NULL || fpLSeekFunc == NULL || inputFileDesc < 0 || - outputFileDesc < 0) { - status = FwdLockConv_Status_InvalidArgument; - } else { - char *pReadBuffer = malloc(READ_BUFFER_SIZE); - if (pReadBuffer == NULL) { - status = FwdLockConv_Status_OutOfMemory; - } else { - int sessionId; - FwdLockConv_Output_t output; - status = FwdLockConv_OpenSession(&sessionId, &output); - if (status == FwdLockConv_Status_OK) { - ssize_t numBytesRead; - FwdLockConv_Status_t closeStatus; - while ((numBytesRead = - fpReadFunc(inputFileDesc, pReadBuffer, READ_BUFFER_SIZE)) > 0) { - status = FwdLockConv_ConvertData(sessionId, pReadBuffer, (size_t)numBytesRead, - &output); - if (status == FwdLockConv_Status_OK) { - if (output.fromConvertData.pBuffer != NULL && - output.fromConvertData.numBytes > 0) { - ssize_t numBytesWritten = fpWriteFunc(outputFileDesc, - output.fromConvertData.pBuffer, - output.fromConvertData.numBytes); - if (numBytesWritten != (ssize_t)output.fromConvertData.numBytes) { - status = FwdLockConv_Status_FileWriteError; - break; - } - } - } else { - if (status == FwdLockConv_Status_SyntaxError && pErrorPos != NULL) { - *pErrorPos = output.fromConvertData.errorPos; - } - break; - } - } // end while - if (numBytesRead < 0) { - status = FwdLockConv_Status_FileReadError; - } - closeStatus = FwdLockConv_CloseSession(sessionId, &output); - if (status == FwdLockConv_Status_OK) { - if (closeStatus != FwdLockConv_Status_OK) { - if (closeStatus == FwdLockConv_Status_SyntaxError && pErrorPos != NULL) { - *pErrorPos = output.fromCloseSession.errorPos; - } - status = closeStatus; - } else if (fpLSeekFunc(outputFileDesc, output.fromCloseSession.fileOffset, - SEEK_SET) < 0) { - status = FwdLockConv_Status_FileSeekError; - } else if (fpWriteFunc(outputFileDesc, output.fromCloseSession.signatures, - FWD_LOCK_SIGNATURES_SIZE) != FWD_LOCK_SIGNATURES_SIZE) { - status = FwdLockConv_Status_FileWriteError; - } - } - } - free(pReadBuffer); - } - } - return status; -} - -FwdLockConv_Status_t FwdLockConv_ConvertFile(const char *pInputFilename, - const char *pOutputFilename, - off64_t *pErrorPos) { - FwdLockConv_Status_t status; - if (pErrorPos != NULL) { - *pErrorPos = INVALID_OFFSET; - } - if (pInputFilename == NULL || pOutputFilename == NULL) { - status = FwdLockConv_Status_InvalidArgument; - } else { - int inputFileDesc = open(pInputFilename, O_RDONLY); - if (inputFileDesc < 0) { - status = FwdLockConv_Status_FileNotFound; - } else { - int outputFileDesc = open(pOutputFilename, O_CREAT | O_TRUNC | O_WRONLY, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (outputFileDesc < 0) { - status = FwdLockConv_Status_FileCreationFailed; - } else { - status = FwdLockConv_ConvertOpenFile(inputFileDesc, read, outputFileDesc, write, - lseek64, pErrorPos); - if (close(outputFileDesc) == 0 && status != FwdLockConv_Status_OK) { - remove(pOutputFilename); - } - } - (void)close(inputFileDesc); - } - } - return status; -} |