Change SRP functions to use EVP_EncodeUpdate/EVP_DecodeUpdate functions
authorMatt Caswell <matt@openssl.org>
Mon, 9 Apr 2018 14:06:50 +0000 (15:06 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 13 Apr 2018 08:37:38 +0000 (09:37 +0100)
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 <appro@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/5925)

crypto/evp/encode.c
crypto/evp/evp_locl.h
crypto/include/internal/evp_int.h
crypto/srp/srp_vfy.c

index 17198ff6bebeb74a3f882f0f1c0f972f5c2d7cdc..a43755ab171845318c405d4c6984b02f7e5e0562 100644 (file)
@@ -12,6 +12,7 @@
 #include "internal/cryptlib.h"
 #include <openssl/evp.h>
 #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;
 }
 
 /*-
index 209577b7c2234200390ec5b44a506796ac427ca9..d5dbbeb0da00774593e6f7aecdd87e621eeb452b 100644 (file)
@@ -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;
index 77c87313557ee2f81358994e76fc045533d5f17c..a766a2c9940f655ef2ec21196d8e5419b21179f3 100644 (file)
@@ -7,6 +7,7 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <openssl/evp.h>
 #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
index 38d1a0f36a5007ce66b4f97b8cb9fa3e56fac320..1eba5a7cb1e39ea238437bdede1fbbaa9e5eb1e1 100644 (file)
@@ -13,6 +13,7 @@
 
 #ifndef OPENSSL_NO_SRP
 # include "internal/cryptlib.h"
+# include "internal/evp_int.h"
 # include <openssl/sha.h>
 # include <openssl/srp.h>
 # include <openssl/evp.h>
 
 /*
  * 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)