summaryrefslogtreecommitdiffstats
path: root/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c
diff options
context:
space:
mode:
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.c1347
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;
-}