From c080461448815dab809661080ee5e21417478fb4 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Mon, 9 Apr 2018 15:06:50 +0100 Subject: [PATCH] Change SRP functions to use EVP_EncodeUpdate/EVP_DecodeUpdate functions Previously they were using EVP_EncodeBlock/EVP_DecodeBlock. These are low level functions that do not handle padding characters. This was causing the SRP code to fail. One side effect of using EVP_EncodeUpdate is that it inserts newlines which is not what we need in SRP so we add a flag to avoid that. Reviewed-by: Andy Polyakov (Merged from https://github.com/openssl/openssl/pull/5925) --- crypto/evp/encode.c | 28 +++++++++++++++------ crypto/evp/evp_locl.h | 2 +- crypto/include/internal/evp_int.h | 6 +++++ crypto/srp/srp_vfy.c | 42 +++++++++++++++++++++++++++---- 4 files changed, 65 insertions(+), 13 deletions(-) diff --git a/crypto/evp/encode.c b/crypto/evp/encode.c index 17198ff6be..a43755ab17 100644 --- a/crypto/evp/encode.c +++ b/crypto/evp/encode.c @@ -12,6 +12,7 @@ #include "internal/cryptlib.h" #include #include "evp_locl.h" +#include "internal/evp_int.h" static unsigned char conv_ascii2bin(unsigned char a); #ifndef CHARSET_EBCDIC @@ -115,11 +116,17 @@ int EVP_ENCODE_CTX_num(EVP_ENCODE_CTX *ctx) return ctx->num; } +void evp_encode_ctx_set_flags(EVP_ENCODE_CTX *ctx, unsigned int flags) +{ + ctx->flags = flags; +} + void EVP_EncodeInit(EVP_ENCODE_CTX *ctx) { ctx->length = 48; ctx->num = 0; ctx->line_num = 0; + ctx->flags = 0; } int EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, @@ -145,18 +152,24 @@ int EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length); ctx->num = 0; out += j; - *(out++) = '\n'; + total = j; + if ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0) { + *(out++) = '\n'; + total++; + } *out = '\0'; - total = j + 1; } while (inl >= ctx->length && total <= INT_MAX) { j = EVP_EncodeBlock(out, in, ctx->length); in += ctx->length; inl -= ctx->length; out += j; - *(out++) = '\n'; + total += j; + if ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0) { + *(out++) = '\n'; + total++; + } *out = '\0'; - total += j + 1; } if (total > INT_MAX) { /* Too much output data! */ @@ -177,7 +190,8 @@ void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl) if (ctx->num != 0) { ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num); - out[ret++] = '\n'; + if ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0) + out[ret++] = '\n'; out[ret] = '\0'; ctx->num = 0; } @@ -217,11 +231,11 @@ int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen) void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) { - /* Only ctx->num is used during decoding. */ + /* Only ctx->num and ctx->flags are used during decoding. */ ctx->num = 0; ctx->length = 0; ctx->line_num = 0; - ctx->expect_nl = 0; + ctx->flags = 0; } /*- diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h index 209577b7c2..d5dbbeb0da 100644 --- a/crypto/evp/evp_locl.h +++ b/crypto/evp/evp_locl.h @@ -59,7 +59,7 @@ struct evp_Encode_Ctx_st { unsigned char enc_data[80]; /* number read on current line */ int line_num; - int expect_nl; + unsigned int flags; }; typedef struct evp_pbe_st EVP_PBE_CTL; diff --git a/crypto/include/internal/evp_int.h b/crypto/include/internal/evp_int.h index 77c8731355..a766a2c994 100644 --- a/crypto/include/internal/evp_int.h +++ b/crypto/include/internal/evp_int.h @@ -7,6 +7,7 @@ * https://www.openssl.org/source/license.html */ +#include #include "internal/refcount.h" struct evp_pkey_ctx_st { @@ -422,3 +423,8 @@ void evp_app_cleanup_int(void); #ifndef TLS1_1_VERSION # define TLS1_1_VERSION 0x0302 #endif + +void evp_encode_ctx_set_flags(EVP_ENCODE_CTX *ctx, unsigned int flags); + +/* EVP_ENCODE_CTX flags */ +#define EVP_ENCODE_CTX_NO_NEWLINES 1 diff --git a/crypto/srp/srp_vfy.c b/crypto/srp/srp_vfy.c index 38d1a0f36a..1eba5a7cb1 100644 --- a/crypto/srp/srp_vfy.c +++ b/crypto/srp/srp_vfy.c @@ -13,6 +13,7 @@ #ifndef OPENSSL_NO_SRP # include "internal/cryptlib.h" +# include "internal/evp_int.h" # include # include # include @@ -26,24 +27,55 @@ /* * Convert a base64 string into raw byte array representation. + * Returns the length of the decoded data, or -1 on error. */ static int t_fromb64(unsigned char *a, size_t alen, const char *src) { + EVP_ENCODE_CTX *ctx; + int outl = 0, outl2 = 0; size_t size = strlen(src); - /* Four bytes in src become three bytes output. */ - if (size > INT_MAX || (size / 4) * 3 > alen) + if (size > INT_MAX) return -1; - return EVP_DecodeBlock(a, (unsigned char *)src, (int)size); + ctx = EVP_ENCODE_CTX_new(); + if (ctx == NULL) + return -1; + + EVP_DecodeInit(ctx); + if (EVP_DecodeUpdate(ctx, a, &outl, (const unsigned char *)src, size) < 0) { + EVP_ENCODE_CTX_free(ctx); + return -1; + } + EVP_DecodeFinal(ctx, a + outl, &outl2); + + EVP_ENCODE_CTX_free(ctx); + return outl + outl2; } /* * Convert a raw byte string into a null-terminated base64 ASCII string. + * Returns 1 on success or 0 on error. */ -static void t_tob64(char *dst, const unsigned char *src, int size) +static int t_tob64(char *dst, const unsigned char *src, int size) { - EVP_EncodeBlock((unsigned char *)dst, src, size); + EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new(); + int outl = 0, outl2 = 0; + + if (ctx == NULL) + return 0; + + EVP_EncodeInit(ctx); + evp_encode_ctx_set_flags(ctx, EVP_ENCODE_CTX_NO_NEWLINES); + + if (!EVP_EncodeUpdate(ctx, (unsigned char *)dst, &outl, src, size)) { + EVP_ENCODE_CTX_free(ctx); + return 0; + } + EVP_EncodeFinal(ctx, (unsigned char *)dst + outl, &outl2); + + EVP_ENCODE_CTX_free(ctx); + return 1; } void SRP_user_pwd_free(SRP_user_pwd *user_pwd) -- 2.25.1