diff --git a/tests/api.c b/tests/api.c index e218f77b3..4ab15cb31 100644 --- a/tests/api.c +++ b/tests/api.c @@ -2600,6 +2600,508 @@ static void test_ED448(void) | EVP *----------------------------------------------------------------------------*/ +/* Test functions for base64 encode/decode */ +static void test_wolfSSL_EVP_ENCODE_CTX_new(void) +{ +#if defined(OPENSSL_EXTRA) && \ +( defined(WOLFSSL_BASE64_ENCODE) || defined(WOLFSSL_BASE64_DECODE)) + printf(testingFmt, "EVP_ENCODE_CTX_new()"); + + EVP_ENCODE_CTX* ctx = NULL; + + AssertNotNull( ctx = EVP_ENCODE_CTX_new()); + AssertIntEQ( ctx->remaining,0); + AssertIntEQ( ctx->data[0],0); + AssertIntEQ( ctx->data[sizeof(ctx->data) -1],0); + EVP_ENCODE_CTX_free(ctx); + + printf(resultFmt, passed); +#endif /* OPENSSL_EXTRA && (WOLFSSL_BASE64_ENCODE || WOLFSSL_BASE64_DECODE)*/ +} +static void test_wolfSSL_EVP_ENCODE_CTX_free(void) +{ +#if defined(OPENSSL_EXTRA) && \ +( defined(WOLFSSL_BASE64_ENCODE) || defined(WOLFSSL_BASE64_DECODE)) + printf(testingFmt, "EVP_ENCODE_CTX_free()"); + EVP_ENCODE_CTX* ctx = NULL; + + AssertNotNull( ctx = EVP_ENCODE_CTX_new()); + EVP_ENCODE_CTX_free(ctx); + printf(resultFmt, passed); +#endif /*OPENSSL_EXTRA && (WOLFSSL_BASE64_ENCODE || WOLFSSL_BASE64_DECODE)*/ +} + +static void test_wolfSSL_EVP_EncodeInit(void) +{ +#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_BASE64_ENCODE) + printf(testingFmt, "EVP_EncodeInit()"); + EVP_ENCODE_CTX* ctx = NULL; + + AssertNotNull( ctx = EVP_ENCODE_CTX_new()); + AssertIntEQ( ctx->remaining,0); + AssertIntEQ( ctx->data[0],0); + AssertIntEQ( ctx->data[sizeof(ctx->data) -1],0); + + /* make ctx dirty */ + ctx->remaining = 10; + XMEMSET( ctx->data, 0x77, sizeof(ctx->data)); + + EVP_EncodeInit(ctx); + + AssertIntEQ( ctx->remaining,0); + AssertIntEQ( ctx->data[0],0); + AssertIntEQ( ctx->data[sizeof(ctx->data) -1],0); + + EVP_ENCODE_CTX_free(ctx); + printf(resultFmt, passed); +#endif /* OPENSSL_EXTRA && WOLFSSL_BASE64_ENCODE*/ +} +static void test_wolfSSL_EVP_EncodeUpdate(void) +{ +#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_BASE64_ENCODE) + printf(testingFmt, "EVP_EncodeUpdate()"); + int outl; + int total; + + const unsigned char plain0[] = {"Th"}; + const unsigned char plain1[] = {"This is a base64 encodeing test."}; + const unsigned char plain2[] = {"This is additional data."}; + + const unsigned char enc0[] = {"VGg=\n"}; + /* expected encoded result for the first output 64 chars plus trailing LF*/ + const unsigned char enc1[] = {"VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVpbmcgdGVzdC5UaGlzIGlzIGFkZGl0aW9u\n"}; + + const unsigned char enc2[] = + {"VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVpbmcgdGVzdC5UaGlzIGlzIGFkZGl0aW9u\nYWwgZGF0YS4=\n"}; + + unsigned char encOutBuff[300]; + + EVP_ENCODE_CTX* ctx = NULL; + AssertNotNull( ctx = EVP_ENCODE_CTX_new()); + + EVP_EncodeInit(ctx); + + /* illegal parameter test */ + AssertIntEQ( + EVP_EncodeUpdate( + NULL, /* pass NULL as ctx */ + encOutBuff, + &outl, + plain1, + sizeof(plain1)-1), + 0 /* expected result code 0: fail */ + ); + + AssertIntEQ( + EVP_EncodeUpdate( + ctx, + NULL, /* pass NULL as out buff */ + &outl, + plain1, + sizeof(plain1)-1), + 0 /* expected result code 0: fail */ + ); + + AssertIntEQ( + EVP_EncodeUpdate( + ctx, + encOutBuff, + NULL, /* pass NULL as outl */ + plain1, + sizeof(plain1)-1), + 0 /* expected result code 0: fail */ + ); + + AssertIntEQ( + EVP_EncodeUpdate( + ctx, + encOutBuff, + &outl, + NULL, /* pass NULL as in */ + sizeof(plain1)-1), + 0 /* expected result code 0: fail */ + ); + + /* meaningless parameter test */ + + AssertIntEQ( + EVP_EncodeUpdate( + ctx, + encOutBuff, + &outl, + plain1, + 0), /* pass zero input */ + 1 /* expected result code 1: success */ + ); + + /* very small data encoding test */ + + EVP_EncodeInit(ctx); + + AssertIntEQ( + EVP_EncodeUpdate( + ctx, + encOutBuff, + &outl, + plain0, + sizeof(plain0)-1), + 1 /* expected result code 1: success */ + ); + AssertIntEQ(outl,0); + + EVP_EncodeFinal( + ctx, + encOutBuff + outl, + &outl); + + AssertIntEQ( outl, sizeof(enc0)-1); + AssertIntEQ( + XSTRNCMP( + (const char*)encOutBuff, + (const char*)enc0,sizeof(enc0) ), + 0); + + /* pass small size( < 48bytes ) input, then make sure they are not + * encoded and just stored in ctx + */ + + EVP_EncodeInit(ctx); + + total = 0; + outl = 0; + XMEMSET( encOutBuff,0, sizeof(encOutBuff)); + + AssertIntEQ( + EVP_EncodeUpdate( + ctx, + encOutBuff, /* buffer for output */ + &outl, /* size of output */ + plain1, /* input */ + sizeof(plain1)-1), /* size of input */ + 1); /* expected result code 1:success */ + + total += outl; + + AssertIntEQ(outl, 0); /* no output expected */ + AssertIntEQ(ctx->remaining, sizeof(plain1) -1); + AssertTrue( + XSTRNCMP((const char*)(ctx->data), + (const char*)plain1, + ctx->remaining) ==0 ); + AssertTrue(encOutBuff[0] == 0); + + /* call wolfSSL_EVP_EncodeUpdate again to make it encode + * the stored data and the new input together + */ + AssertIntEQ( + EVP_EncodeUpdate( + ctx, + encOutBuff + outl, /* buffer for output */ + &outl, /* size of output */ + plain2, /* additional input */ + sizeof(plain2) -1), /* size of additional input */ + 1); /* expected result code 1:success */ + + total += outl; + + AssertIntNE(outl, 0); /* some output is expected this time*/ + AssertIntEQ(outl, BASE64_ENCODE_RESULT_BLOCK_SIZE +1); /* 64 bytes and LF */ + AssertIntEQ( + XSTRNCMP((const char*)encOutBuff,(const char*)enc1,sizeof(enc1) ),0); + + /* call wolfSSL_EVP_EncodeFinal to flush all the unprocessed input */ + EVP_EncodeFinal( + ctx, + encOutBuff + outl, + &outl); + + total += outl; + + AssertIntNE(total,0); + AssertIntNE(outl,0); + AssertIntEQ(XSTRNCMP( + (const char*)encOutBuff,(const char*)enc2,sizeof(enc2) ),0); + + /* test with illeagal parameters */ + outl = 1; + EVP_EncodeFinal(NULL, encOutBuff + outl, &outl); + AssertIntEQ(outl, 0); + outl = 1; + EVP_EncodeFinal(ctx, NULL, &outl); + AssertIntEQ(outl, 0); + EVP_EncodeFinal(ctx, encOutBuff + outl, NULL); + EVP_EncodeFinal(NULL, NULL, NULL); + + EVP_ENCODE_CTX_free(ctx); + printf(resultFmt, passed); +#endif /* OPENSSL_EXTRA && WOLFSSL_BASE64_ENCODE*/ +} +static void test_wolfSSL_EVP_EncodeFinal(void) +{ +#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_BASE64_ENCODE) + printf(testingFmt, "wolfSSL_EVP_EncodeFinal()"); + + /* tests for wolfSSL_EVP_EncodeFinal are included in + * test_wolfSSL_EVP_EncodeUpdate + */ + printf(resultFmt, passed); +#endif /* OPENSSL_EXTRA && WOLFSSL_BASE64_ENCODE*/ +} + + +static void test_wolfSSL_EVP_DecodeInit(void) +{ +#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_BASE64_DECODE) + printf(testingFmt, "EVP_DecodeInit()"); + + EVP_ENCODE_CTX* ctx = NULL; + + AssertNotNull( ctx = EVP_ENCODE_CTX_new()); + AssertIntEQ( ctx->remaining,0); + AssertIntEQ( ctx->data[0],0); + AssertIntEQ( ctx->data[sizeof(ctx->data) -1],0); + + /* make ctx dirty */ + ctx->remaining = 10; + XMEMSET( ctx->data, 0x77, sizeof(ctx->data)); + + EVP_DecodeInit(ctx); + + AssertIntEQ( ctx->remaining,0); + AssertIntEQ( ctx->data[0],0); + AssertIntEQ( ctx->data[sizeof(ctx->data) -1],0); + + EVP_ENCODE_CTX_free(ctx); + printf(resultFmt, passed); +#endif /* OPENSSL && WOLFSSL_BASE_DECODE */ +} +static void test_wolfSSL_EVP_DecodeUpdate(void) +{ +#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_BASE64_DECODE) + printf(testingFmt, "EVP_DecodeUpdate()"); + + int outl; + unsigned char decOutBuff[300]; + + EVP_ENCODE_CTX* ctx = EVP_ENCODE_CTX_new(); + EVP_DecodeInit(ctx); + + const unsigned char enc1[] = + {"VGhpcyBpcyBhIGJhc2U2NCBkZWNvZGluZyB0ZXN0Lg==\n"}; +/* const unsigned char plain1[] = + {"This is a base64 decoding test."} */ + + /* illegal parameter tests */ + + /* pass NULL as ctx */ + AssertIntEQ( + EVP_DecodeUpdate( + NULL, /* pass NULL as ctx */ + decOutBuff, + &outl, + enc1, + sizeof(enc1)-1), + -1 /* expected result code -1: fail */ + ); + AssertIntEQ( outl, 0); + + /* pass NULL as output */ + AssertIntEQ( + EVP_DecodeUpdate( + ctx, + NULL, /* pass NULL as out buff */ + &outl, + enc1, + sizeof(enc1)-1), + -1 /* expected result code -1: fail */ + ); + AssertIntEQ( outl, 0); + + /* pass NULL as outl */ + AssertIntEQ( + EVP_DecodeUpdate( + ctx, + decOutBuff, + NULL, /* pass NULL as outl */ + enc1, + sizeof(enc1)-1), + -1 /* expected result code -1: fail */ + ); + + /* pass NULL as input */ + AssertIntEQ( + EVP_DecodeUpdate( + ctx, + decOutBuff, + &outl, + NULL, /* pass NULL as in */ + sizeof(enc1)-1), + -1 /* expected result code -1: fail */ + ); + AssertIntEQ( outl, 0); + + /* pass zero length input */ + + AssertIntEQ( + EVP_DecodeUpdate( + ctx, + decOutBuff, + &outl, + enc1, + 0), /* pass zero as input len */ + 1 /* expected result code 1: success */ + ); + + /* decode correct base64 string */ + + const unsigned char enc2[] = + {"VGhpcyBpcyBhIGJhc2U2NCBkZWNvZGluZyB0ZXN0Lg==\n"}; + const unsigned char plain2[] = + {"This is a base64 decoding test."}; + + EVP_EncodeInit(ctx); + + AssertIntEQ( + EVP_DecodeUpdate( + ctx, + decOutBuff, + &outl, + enc2, + sizeof(enc2)-1), + 0 /* expected result code 0: success */ + ); + + AssertIntEQ(outl,sizeof(plain2) -1); + + AssertIntEQ( + EVP_DecodeFinal( + ctx, + decOutBuff + outl, + &outl), + 1 /* expected result code 1: success */ + ); + AssertIntEQ(outl, 0); /* expected DecodeFinal outout no data */ + + AssertIntEQ(XSTRNCMP( (const char*)plain2,(const char*)decOutBuff, + sizeof(plain2) -1 ),0); + + /* decode correct base64 string which does not have '\n' in its last*/ + + const unsigned char enc3[] = + {"VGhpcyBpcyBhIGJhc2U2NCBkZWNvZGluZyB0ZXN0Lg=="}; /* 44 chars */ + const unsigned char plain3[] = + {"This is a base64 decoding test."}; /* 31 chars */ + + EVP_EncodeInit(ctx); + + AssertIntEQ( + EVP_DecodeUpdate( + ctx, + decOutBuff, + &outl, + enc3, + sizeof(enc3)-1), + 0 /* expected result code 0: success */ + ); + + AssertIntEQ(outl,sizeof(plain3)-1); /* 31 chars should be output */ + + AssertIntEQ(XSTRNCMP( (const char*)plain3,(const char*)decOutBuff, + sizeof(plain3) -1 ),0); + + AssertIntEQ( + EVP_DecodeFinal( + ctx, + decOutBuff + outl, + &outl), + 1 /* expected result code 1: success */ + ); + + AssertIntEQ(outl,0 ); + + /* decode string which has a padding char ('=') in the illegal position*/ + + const unsigned char enc4[] = + {"VGhpcyBpcyBhIGJhc2U2N=CBkZWNvZGluZyB0ZXN0Lg==\n"}; + + + EVP_EncodeInit(ctx); + + AssertIntEQ( + EVP_DecodeUpdate( + ctx, + decOutBuff, + &outl, + enc4, + sizeof(enc4)-1), + -1 /* expected result code -1: error */ + ); + AssertIntEQ(outl,0); + + /* small data decode test */ + + const unsigned char enc00[] = {"VG"}; + const unsigned char enc01[] = {"g=\n"}; + const unsigned char plain4[] = {"Th"}; + + EVP_EncodeInit(ctx); + + AssertIntEQ( + EVP_DecodeUpdate( + ctx, + decOutBuff, + &outl, + enc00, + sizeof(enc00)-1), + 1 /* expected result code 1: success */ + ); + AssertIntEQ(outl,0); + + AssertIntEQ( + EVP_DecodeUpdate( + ctx, + decOutBuff + outl, + &outl, + enc01, + sizeof(enc01)-1), + 0 /* expected result code 0: success */ + ); + + AssertIntEQ(outl,sizeof(plain4)-1); + + /* test with illegal parameters */ + AssertIntEQ(EVP_DecodeFinal(NULL,decOutBuff + outl,&outl), -1); + AssertIntEQ(EVP_DecodeFinal(ctx,NULL,&outl), -1); + AssertIntEQ(EVP_DecodeFinal(ctx,decOutBuff + outl, NULL), -1); + AssertIntEQ(EVP_DecodeFinal(NULL,NULL, NULL), -1); + + EVP_DecodeFinal( + ctx, + decOutBuff + outl, + &outl); + + AssertIntEQ( outl, 0); + AssertIntEQ( + XSTRNCMP( + (const char*)decOutBuff, + (const char*)plain4,sizeof(plain4)-1 ), + 0); + + EVP_ENCODE_CTX_free(ctx); + + printf(resultFmt, passed); +#endif /* OPENSSL && WOLFSSL_BASE_DECODE */ +} +static void test_wolfSSL_EVP_DecodeFinal(void) +{ +#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_BASE64_DECODE) + printf(testingFmt, "EVP_DecodeFinal()"); + /* tests for wolfSSL_EVP_DecodeFinal are included in + * test_wolfSSL_EVP_DecodeUpdate + */ + printf(resultFmt, passed); +#endif /* OPENSSL && WOLFSSL_BASE_DECODE */ +} static void test_wolfSSL_EVP_PKEY_print_public(void) { #if defined(OPENSSL_EXTRA) @@ -44424,6 +44926,14 @@ void ApiTest(void) test_wolfSSL_EVP_MD_hmac_signing(); test_wolfSSL_EVP_MD_rsa_signing(); test_wolfSSL_EVP_MD_ecc_signing(); + test_wolfSSL_EVP_ENCODE_CTX_new(); + test_wolfSSL_EVP_ENCODE_CTX_free(); + test_wolfSSL_EVP_EncodeInit(); + test_wolfSSL_EVP_EncodeUpdate(); + test_wolfSSL_EVP_EncodeFinal(); + test_wolfSSL_EVP_DecodeInit(); + test_wolfSSL_EVP_DecodeUpdate(); + test_wolfSSL_EVP_DecodeFinal(); test_wolfSSL_EVP_PKEY_print_public(); test_wolfSSL_CTX_add_extra_chain_cert(); #if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) diff --git a/wolfcrypt/src/coding.c b/wolfcrypt/src/coding.c index 18ef90752..30ce6ea10 100644 --- a/wolfcrypt/src/coding.c +++ b/wolfcrypt/src/coding.c @@ -113,7 +113,8 @@ static WC_INLINE byte Base64_Char2Val(byte c) } #endif -static WC_INLINE int Base64_SkipNewline(const byte* in, word32 *inLen, word32 *outJ) +int Base64_SkipNewline(const byte* in, word32 *inLen, + word32 *outJ) { word32 len = *inLen; word32 j = *outJ; diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 9338a2448..f1b2705f4 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -8104,6 +8104,431 @@ int wolfSSL_EVP_get_hashinfo(const WOLFSSL_EVP_MD* evp, } #endif /* !defined(NO_PWDBASED) */ +/* Base64 encoding APIs */ +#if defined(WOLFSSL_BASE64_ENCODE) || defined(WOLFSSL_BASE64_DECODE) + +/* wolfSSL_EVP_ENCODE_CTX_new allocates WOLFSSL_EVP_ENCODE_CTX + * Returns WOLFSSL_EVP_ENCODE_CTX structure on success, NULL on failure. + */ +struct WOLFSSL_EVP_ENCODE_CTX* wolfSSL_EVP_ENCODE_CTX_new(void) +{ + WOLFSSL_EVP_ENCODE_CTX* ctx = NULL; + WOLFSSL_ENTER("wolfSSL_EVP_ENCODE_CTX_new"); + ctx = (WOLFSSL_EVP_ENCODE_CTX*)XMALLOC( sizeof(WOLFSSL_EVP_ENCODE_CTX), + NULL, DYNAMIC_TYPE_OPENSSL ); + + if (ctx != NULL) { + XMEMSET(ctx, 0, sizeof(WOLFSSL_EVP_ENCODE_CTX) ); + ctx->heap = NULL; + return ctx; + } + return NULL; +} +/* wolfSSL_EVP_ENCODE_CTX_free frees specified WOLFSSL_EVP_ENCODE_CTX struc. + */ +void wolfSSL_EVP_ENCODE_CTX_free(WOLFSSL_EVP_ENCODE_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_EVP_ENCODE_CTX_free"); + if (ctx != NULL) { + XFREE(ctx, ctx->heap, DYNAMIC_TYPE_OPENSSL); + } +} +#endif /* WOLFSSL_BASE64_ENCODE || WOLFSSL_BASE64_DECODE */ +#if defined(WOLFSSL_BASE64_ENCODE) +/* wolfSSL_EVP_EncodeInit initializes specified WOLFSSL_EVP_ENCODE_CTX object + * for the subsequent wolfSSL_EVP_EncodeUpdate. + */ +void wolfSSL_EVP_EncodeInit(WOLFSSL_EVP_ENCODE_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_EVP_EncodeInit"); + + /* clean up ctx */ + if (ctx != NULL) { + ctx->remaining = 0; + XMEMSET(ctx->data, 0, sizeof(ctx->data)); + } +} +/* wolfSSL_EVP_EncodeUpdate encodes the input data in 48-byte units + * and outputs it to out. If less than 48 bytes of data remain, save it in + * ctx. The data given in the subsequent wolfSSL_EVP_EncodeUpdate + * is combined with the data stored in CTX and used for encoding. + * Returns 1 on success, 0 on error. + */ +int wolfSSL_EVP_EncodeUpdate(WOLFSSL_EVP_ENCODE_CTX* ctx, + unsigned char* out, int* outl, const unsigned char* in, int inl) +{ + int cpysz; + int res; + word32 outsz = 0; + + WOLFSSL_ENTER("wolfSSL_EVP_EncodeUpdate"); + + if (ctx == NULL || out == NULL || in == NULL || outl == NULL) + return 0; + + *outl = 0; + + /* if the remaining data exists in the ctx, add input data to them + * to create a block(48bytes) for encoding + */ + if (ctx->remaining > 0 && inl > 0) { + cpysz = min((BASE64_ENCODE_BLOCK_SIZE - ctx->remaining), inl); + XMEMCPY(ctx->data + ctx->remaining, in, cpysz); + ctx->remaining += cpysz; + in += cpysz; + inl -= cpysz; + + /* check if a block for encoding exists in ctx.data, if so encode it */ + if (ctx->remaining >= BASE64_ENCODE_BLOCK_SIZE) { + /* Base64_Encode asks the out buff size via the 4th param*/ + outsz = BASE64_ENCODE_RESULT_BLOCK_SIZE + 1; + res = Base64_Encode(ctx->data, BASE64_ENCODE_BLOCK_SIZE, out, + &outsz); + if (res == 0) { + ctx->remaining = 0; + *outl = outsz; + } + else + return 0; /* return with error */ + } + else { + /* could not create a block */ + *outl = 0; + return 1; + } + } + /* Here, there is no data left in ctx, so try processing the data of + * the specified input data. + */ + + while (inl >= BASE64_ENCODE_BLOCK_SIZE) { + outsz = BASE64_ENCODE_RESULT_BLOCK_SIZE + 1;/* 64 byte and one for LF*/ + res = Base64_Encode(in, BASE64_ENCODE_BLOCK_SIZE,out,&outsz); + if (res == 0) { + in += BASE64_ENCODE_BLOCK_SIZE; + inl -= BASE64_ENCODE_BLOCK_SIZE; + out += outsz; + *outl += outsz; + } + else { + *outl = 0; + return 0; + } + } + + /* if remaining data exists, copy them into ctx for the next call*/ + if (inl > 0) { + XMEMSET(ctx->data, 0, sizeof(ctx->data)); + XMEMCPY(ctx->data, in, inl); + ctx->remaining = inl; + } + + return 1; /* returns 1 on success, 0 on error */ +} +/* wolfSSL_EVP_EncodeFinal encodes data in ctx and outputs to out. + */ +void wolfSSL_EVP_EncodeFinal(WOLFSSL_EVP_ENCODE_CTX* ctx, + unsigned char* out, int* outl) +{ + word32 outsz = 0; + int res; + + WOLFSSL_ENTER("wolfSSL_EVP_EncodeFinal"); + + if (outl == NULL) + return; + + if (ctx == NULL || out == NULL) { + *outl = 0; + return; + } + if (ctx->remaining >= BASE64_ENCODE_RESULT_BLOCK_SIZE) { + *outl = 0; + return; + } + /* process remaining data in ctx */ + outsz = BASE64_ENCODE_RESULT_BLOCK_SIZE + 1; /* 64 byte and one for LF*/ + res = Base64_Encode(ctx->data, ctx->remaining ,out, &outsz); + if (res == 0) + *outl = outsz; + else + *outl = 0; + + ctx->remaining = 0; + XMEMSET(ctx->data, 0, sizeof(ctx->data)); + + return; +} +#endif /* WOLFSSL_BASE64_ENCODE */ +#if defined(WOLFSSL_BASE64_DECODE) + +/* wolfSSL_EVP_DecodeInit initializes specified WOLFSSL_EVP_ENCODE_CTX struct + * for subsequent wolfSSL_EVP_DecodeUpdate. + */ +void wolfSSL_EVP_DecodeInit(WOLFSSL_EVP_ENCODE_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_EVP_DecodeInit"); + /* clean up ctx */ + if (ctx != NULL) { + ctx->remaining = 0; + XMEMSET(ctx->data, 0, sizeof(ctx->data)); + } +} +/* wolfSSL_EVP_DecodeUpdate encodes the input data in 4-byte units + * and outputs it to out. If less than 4 bytes of data remain, save it in + * ctx. The data given in the subsequent wolfSSL_EVP_DecodeUpdate + * is combined with the data stored in CTX and used for decoding. + * Returns 1 or 0 on success, -1 on error. Return value 0 indicates that + * clients should call wolfSSL_EVP_DecodeFinal as next call. + */ +int wolfSSL_EVP_DecodeUpdate(WOLFSSL_EVP_ENCODE_CTX* ctx, + unsigned char* out, int* outl, const unsigned char* in, int inl) +{ + word32 outsz = 0; + word32 j = 0; + word32 inLen; + int res; + int pad = 0; + int i; + int cpySz; + unsigned char c; + int pad3 = 0; + int pad4 = 0; + byte e[4]; + + WOLFSSL_ENTER("wolfSSL_EVP_DecodeUpdate"); + + if (outl == NULL) + return -1; + + if (ctx == NULL || out == NULL || in == NULL) { + *outl = 0; + return -1; + } + + if (inl == 0) { + *outl = 0; + return 1; + } + + inLen = inl; + *outl = 0; + + /* if the remaining data exist in the ctx, add input data to them to create + a block(4bytes) for decoding*/ + if ( ctx->remaining > 0 && inl > 0) { + + cpySz = min((BASE64_DECODE_BLOCK_SIZE - ctx->remaining), inl); + + for ( i = 0; cpySz > 0 && inLen > 0; i++) { + if ((res = Base64_SkipNewline(in, &inLen, &j)) + == ASN_INPUT_E) { + return -1; /* detected an illegal char in input */ + } + c = in[j++]; + + if (c == '=') + pad = 1; + + *(ctx->data + ctx->remaining + i) = c; + inLen--; + cpySz--; + } + + outsz = sizeof(ctx->data); + res = Base64_Decode( ctx->data, BASE64_DECODE_BLOCK_SIZE, out, &outsz); + if (res == 0) { + *outl += outsz; + out += outsz; + + ctx->remaining = 0; + XMEMSET(ctx->data, 0, sizeof(ctx->data)); + } + else { + *outl = 0; + return -1; /* return with error */ + } + } + + /* Base64_Decode is not a streaming process, so it processes + * the input data and exits. If a line break or whitespace + * character is found in the input data, it will be skipped, + * but if the end point of the input data is reached as a result, + * Base64_Decode will stop processing there. The data cleansing is + * required before Base64_Decode so that the processing does not + * stop within 4 bytes, which is the unit of Base64 decoding processing. + * The logic that exists before calling Base64_Decode in a While Loop is + * a data cleansing process that removes line breaks and whitespace. + */ + while (inLen > 3) { + if ((res = Base64_SkipNewline(in, &inLen, &j)) != 0) { + if (res == BUFFER_E) { + break; + } + else { + *outl = 0; + return -1; + } + } + e[0] = in[j++]; + if (e[0] == '\0') { + break; + } + inLen--; + if ((res = Base64_SkipNewline(in, &inLen, &j)) != 0) { + if (res == BUFFER_E) { + break; + } + else { + *outl = 0; + return -1; + } + } + e[1] = in[j++]; + inLen--; + if ((res = Base64_SkipNewline(in, &inLen, &j)) != 0) { + if (res == BUFFER_E) { + break; + } + else { + *outl = 0; + return -1; + } + } + e[2] = in[j++]; + inLen--; + if ((res = Base64_SkipNewline(in, &inLen, &j)) != 0) { + if (res == BUFFER_E) { + break; + } + else { + *outl = 0; + return -1; + } + } + e[3] = in[j++]; + inLen--; + + if (e[0] == '=') + pad = 1; + if (e[1] == '=') + pad = 1; + if (e[2] == '=') { + pad = 1; + pad3 = 1; + } + if (e[3] == '=') { + pad = 1; + pad4 = 1; + } + if (pad3 && !pad4) { + *outl = 0; + return -1; + } + + /* decode four bytes */ + outsz = sizeof(ctx->data); + res = Base64_Decode( e, BASE64_DECODE_BLOCK_SIZE, out, &outsz); + if (res < 0) { + *outl = 0; + return -1; + } + + *outl += outsz; + out += outsz; + } + /* copy left data to ctx */ + if (inLen > 0) { + + XMEMSET(ctx->data, 0, sizeof(ctx->data)); + + i = 0; + while (inLen > 0) { + c = in[j++]; + if (c== '\n' || c == '\r' || c == ' ') { + inLen--; + continue; + } + if (c == '=') { + pad = 1; + } + ctx->data[i++] = c; + ctx->remaining++; + inLen--; + } + + if (pad) + return 0; /* indicates that clients should call DecodeFinal */ + else + return 1; + + } + /* if the last data is '\n', remove it */ + c = in[j - 1]; + if (c == '\n') { + c = (in[j - 2]); + if (c == '=') + return 0; + else + return 1; + } + if (c == '=') + return 0; + else + return 1; + +} +/* wolfSSL_EVP_DecodeFinal decode remaining data in ctx + * to outputs to out. + * Returns 1 on success, -1 on failure. + */ +int wolfSSL_EVP_DecodeFinal(WOLFSSL_EVP_ENCODE_CTX* ctx, + unsigned char* out, int* outl) +{ + word32 outsz = 0; + word32 inLen; + word32 j = 0; + int res; + + WOLFSSL_ENTER("wolfSSL_EVP_DecodeFinal"); + + if (outl == NULL) + return -1; + + if (ctx == NULL || out == NULL ) { + *outl = 0; + return -1; + } + + if (ctx->remaining > 0) { + inLen = ctx->remaining; + if ((res = Base64_SkipNewline(ctx->data, &inLen, &j)) != 0) { + *outl = 0; + if (res == BUFFER_E) /* means no valid data to decode in buffer */ + return 1; /* returns as success with no output */ + else + return -1; + } + + + outsz = ctx->remaining; + res = Base64_Decode(ctx->data, ctx->remaining, out, &outsz); + if (res == 0) { + *outl = outsz; + return 1; + } + else { + *outl = 0; + return -1; + } + } + else { + *outl = 0; + return 1; + } +} +#endif /* WOLFSSL_BASE64_DECODE */ + #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #endif /* WOLFSSL_EVP_INCLUDED */ diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index 1376de168..fc92977b7 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -59,6 +59,10 @@ #endif #include +#if defined(WOLFSSL_BASE64_ENCODE) || defined(WOLFSSL_BASE64_DECODE) +#include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -373,6 +377,38 @@ struct WOLFSSL_EVP_PKEY_CTX { int nbits; }; +#if defined(WOLFSSL_BASE64_ENCODE) || defined(WOLFSSL_BASE64_DECODE) + +#define BASE64_ENCODE_BLOCK_SIZE 48 +#define BASE64_ENCODE_RESULT_BLOCK_SIZE 64 +#define BASE64_DECODE_BLOCK_SIZE 4 + +struct WOLFSSL_EVP_ENCODE_CTX { + void* heap; + int remaining; /* num of bytes in data[] */ + byte data[BASE64_ENCODE_BLOCK_SIZE];/* storage for unprocessed raw data */ +}; +typedef struct WOLFSSL_EVP_ENCODE_CTX WOLFSSL_EVP_ENCODE_CTX; + +WOLFSSL_API struct WOLFSSL_EVP_ENCODE_CTX* wolfSSL_EVP_ENCODE_CTX_new(void); +WOLFSSL_API void wolfSSL_EVP_ENCODE_CTX_free(WOLFSSL_EVP_ENCODE_CTX* ctx); +#endif /* WOLFSSL_BASE64_ENCODE || WOLFSSL_BASE64_DECODE */ + +#if defined(WOLFSSL_BASE64_ENCODE) +WOLFSSL_API void wolfSSL_EVP_EncodeInit(WOLFSSL_EVP_ENCODE_CTX* ctx); +WOLFSSL_API int wolfSSL_EVP_EncodeUpdate(WOLFSSL_EVP_ENCODE_CTX* ctx, + unsigned char*out, int *outl, const unsigned char*in, int inl); +WOLFSSL_API void wolfSSL_EVP_EncodeFinal(WOLFSSL_EVP_ENCODE_CTX* ctx, + unsigned char*out, int *outl); +#endif /* WOLFSSL_BASE64_ENCODE */ + +#if defined(WOLFSSL_BASE64_DECODE) +WOLFSSL_API void wolfSSL_EVP_DecodeInit(WOLFSSL_EVP_ENCODE_CTX* ctx); +WOLFSSL_API int wolfSSL_EVP_DecodeUpdate(WOLFSSL_EVP_ENCODE_CTX* ctx, + unsigned char*out, int *outl, const unsigned char*in, int inl); +WOLFSSL_API int wolfSSL_EVP_DecodeFinal(WOLFSSL_EVP_ENCODE_CTX* ctx, + unsigned char*out, int *outl); +#endif /* WOLFSSL_BASE64_DECODE */ typedef struct WOLFSSL_ASN1_PCTX { int dummy; @@ -955,6 +991,22 @@ typedef WOLFSSL_ASN1_PCTX ASN1_PCTX; #define EVP_MD_name(x) x #define EVP_CIPHER_nid wolfSSL_EVP_CIPHER_nid +/* Base64 encoding/decoding APIs */ +#if defined(WOLFSSL_BASE64_ENCODE) || defined(WOLFSSL_BASE64_DECODE) +#define EVP_ENCODE_CTX WOLFSSL_EVP_ENCODE_CTX +#define EVP_ENCODE_CTX_new wolfSSL_EVP_ENCODE_CTX_new +#define EVP_ENCODE_CTX_free wolfSSL_EVP_ENCODE_CTX_free +#endif /* WOLFSSL_BASE64_ENCODE || WOLFSSL_BASE64_DECODE*/ +#if defined(WOLFSSL_BASE64_ENCODE) +#define EVP_EncodeInit wolfSSL_EVP_EncodeInit +#define EVP_EncodeUpdate wolfSSL_EVP_EncodeUpdate +#define EVP_EncodeFinal wolfSSL_EVP_EncodeFinal +#endif /* WOLFSSL_BASE64_ENCODE */ +#if defined(WOLFSSL_BASE64_DECODE) +#define EVP_DecodeInit wolfSSL_EVP_DecodeInit +#define EVP_DecodeUpdate wolfSSL_EVP_DecodeUpdate +#define EVP_DecodeFinal wolfSSL_EVP_DecodeFinal +#endif /* WOLFSSL_BASE64_DECODE */ WOLFSSL_API void printPKEY(WOLFSSL_EVP_PKEY *k); diff --git a/wolfssl/wolfcrypt/coding.h b/wolfssl/wolfcrypt/coding.h index fd5562183..bcc4c5b95 100644 --- a/wolfssl/wolfcrypt/coding.h +++ b/wolfssl/wolfcrypt/coding.h @@ -79,6 +79,8 @@ WOLFSSL_API int Base64_Decode(const byte* in, word32 inLen, byte* out, int Base16_Encode(const byte* in, word32 inLen, byte* out, word32* outLen); #endif + WOLFSSL_LOCAL int Base64_SkipNewline(const byte* in, word32* inLen, + word32* outJ); #ifdef __cplusplus } /* extern "C" */