Browse Source

Merge branch 'srp'

toddouska 9 years ago
parent
commit
50fd2538ff

+ 61 - 45
configure.ac

@@ -85,7 +85,7 @@ AC_CHECK_TYPES(__uint128_t)
 AC_C_BIGENDIAN
 # mktime check takes forever on some systems, if time supported it would be
 # highly unusual for mktime to be missing
-#AC_FUNC_MKTIME 
+#AC_FUNC_MKTIME
 
 AC_PROG_CC
 AC_PROG_CC_C_O
@@ -199,7 +199,7 @@ fi
 AM_CONDITIONAL([BUILD_IPV6], [test "x$ENABLED_IPV6" = "xyes"])
 
 
-# Fortress build 
+# Fortress build
 AC_ARG_ENABLE([fortress],
     [  --enable-fortress       Enable SSL fortress build (default: disabled)],
     [ ENABLED_FORTRESS=$enableval ],
@@ -217,7 +217,7 @@ then
 fi
 
 
-# ssl bump build 
+# ssl bump build
 AC_ARG_ENABLE([bump],
     [  --enable-bump           Enable SSL Bump build (default: disabled)],
     [ ENABLED_BUMP=$enableval ],
@@ -231,7 +231,7 @@ fi
 
 ENABLED_SLOWMATH="yes"
 
-# lean psk build 
+# lean psk build
 AC_ARG_ENABLE([leanpsk],
     [  --enable-leanpsk        Enable Lean PSK build (default: disabled)],
     [ ENABLED_LEANPSK=$enableval ],
@@ -287,7 +287,7 @@ then
 fi
 
 
-# Persistent session cache 
+# Persistent session cache
 AC_ARG_ENABLE([savesession],
     [  --enable-savesession    Enable persistent session cache (default: disabled)],
     [ ENABLED_SAVESESSION=$enableval ],
@@ -300,7 +300,7 @@ then
 fi
 
 
-# Persistent cert cache 
+# Persistent cert cache
 AC_ARG_ENABLE([savecert],
     [  --enable-savecert       Enable persistent cert cache (default: disabled)],
     [ ENABLED_SAVECERT=$enableval ],
@@ -313,7 +313,7 @@ then
 fi
 
 
-# Atomic User Record Layer  
+# Atomic User Record Layer
 AC_ARG_ENABLE([atomicuser],
     [  --enable-atomicuser     Enable Atomic User Record Layer (default: disabled)],
     [ ENABLED_ATOMICUSER=$enableval ],
@@ -326,7 +326,7 @@ then
 fi
 
 
-# Public Key Callbacks  
+# Public Key Callbacks
 AC_ARG_ENABLE([pkcallbacks],
     [  --enable-pkcallbacks    Enable Public Key Callbacks (default: disabled)],
     [ ENABLED_PKCALLBACKS=$enableval ],
@@ -491,7 +491,7 @@ fi
 AM_CONDITIONAL([BUILD_MD2], [test "x$ENABLED_MD2" = "xyes"])
 
 
-# NULL CIPHER 
+# NULL CIPHER
 AC_ARG_ENABLE([nullcipher],
     [  --enable-nullcipher     Enable wolfSSL NULL cipher support (default: disabled)],
     [ ENABLED_NULL_CIPHER=$enableval ],
@@ -650,7 +650,7 @@ then
 fi
 
 
-# HKDF 
+# HKDF
 AC_ARG_ENABLE([hkdf],
     [  --enable-hkdf           Enable HKDF (HMAC-KDF) support (default: disabled)],
     [ ENABLED_HKDF=$enableval ],
@@ -792,7 +792,7 @@ if test "$ENABLED_FPECC" = "yes"
 then
     if test "$ENABLED_ECC" = "no"
     then
-        AC_MSG_ERROR([cannot enable fpecc without enabling ecc.]) 
+        AC_MSG_ERROR([cannot enable fpecc without enabling ecc.])
     fi
     AM_CFLAGS="$AM_CFLAGS -DFP_ECC"
 fi
@@ -809,17 +809,17 @@ if test "$ENABLED_ECC_ENCRYPT" = "yes"
 then
     if test "$ENABLED_ECC" = "no"
     then
-        AC_MSG_ERROR([cannot enable eccencrypt without enabling ecc.]) 
+        AC_MSG_ERROR([cannot enable eccencrypt without enabling ecc.])
     fi
     if test "$ENABLED_HKDF" = "no"
     then
-        AC_MSG_ERROR([cannot enable eccencrypt without enabling hkdf.]) 
+        AC_MSG_ERROR([cannot enable eccencrypt without enabling hkdf.])
     fi
     AM_CFLAGS="$AM_CFLAGS -DHAVE_ECC_ENCRYPT"
 fi
 
 
-# PSK 
+# PSK
 AC_ARG_ENABLE([psk],
     [  --enable-psk            Enable PSK (default: disabled)],
     [ ENABLED_PSK=$enableval ],
@@ -857,7 +857,7 @@ else
 fi
 
 
-# OLD TLS 
+# OLD TLS
 AC_ARG_ENABLE([oldtls],
     [  --enable-oldtls         Enable old TLS versions < 1.2 (default: enabled)],
     [ ENABLED_OLD_TLS=$enableval ],
@@ -877,7 +877,7 @@ else
 fi
 
 
-# STACK SIZE info for examples 
+# STACK SIZE info for examples
 AC_ARG_ENABLE([stacksize],
     [  --enable-stacksize      Enable stack size info on examples (default: disabled)],
     [ ENABLED_STACKSIZE=$enableval ],
@@ -892,7 +892,7 @@ then
 fi
 
 
-# MEMORY 
+# MEMORY
 AC_ARG_ENABLE([memory],
     [  --enable-memory         Enable memory callbacks (default: enabled)],
     [ ENABLED_MEMORY=$enableval ],
@@ -914,7 +914,7 @@ fi
 AM_CONDITIONAL([BUILD_MEMORY], [test "x$ENABLED_MEMORY" = "xyes"])
 
 
-# RSA 
+# RSA
 AC_ARG_ENABLE([rsa],
     [  --enable-rsa            Enable RSA (default: enabled)],
     [ ENABLED_RSA=$enableval ],
@@ -1119,7 +1119,7 @@ fi
 AM_CONDITIONAL([BUILD_DES3], [test "x$ENABLED_DES3" = "xyes"])
 
 
-# ARC4 
+# ARC4
 AC_ARG_ENABLE([arc4],
     [  --enable-arc4           Enable ARC4 (default: disabled)],
     [ ENABLED_ARC4=$enableval ],
@@ -1146,7 +1146,7 @@ fi
 AM_CONDITIONAL([BUILD_RC4], [test "x$ENABLED_ARC4" = "xyes"])
 
 
-# MD5 
+# MD5
 AC_ARG_ENABLE([md5],
     [  --enable-md5            Enable MD5 (default: enabled)],
     [ ENABLED_MD5=$enableval ],
@@ -1168,7 +1168,7 @@ fi
 AM_CONDITIONAL([BUILD_MD5], [test "x$ENABLED_MD5" = "xyes"])
 
 
-# SHA 
+# SHA
 AC_ARG_ENABLE([sha],
     [  --enable-sha            Enable SHA (default: enabled)],
     [ ENABLED_SHA=$enableval ],
@@ -1190,7 +1190,7 @@ fi
 AM_CONDITIONAL([BUILD_SHA], [test "x$ENABLED_SHA" = "xyes"])
 
 
-# Web Server Build 
+# Web Server Build
 AC_ARG_ENABLE([webserver],
     [  --enable-webserver      Enable Web Server (default: disabled)],
     [ ENABLED_WEBSERVER=$enableval ],
@@ -1204,7 +1204,7 @@ fi
 
 
 
-# HC128 
+# HC128
 AC_ARG_ENABLE([hc128],
     [  --enable-hc128          Enable HC-128 (default: disabled)],
     [ ENABLED_HC128=$enableval ],
@@ -1350,7 +1350,7 @@ else
 fi
 
 
-# Filesystem Build 
+# Filesystem Build
 AC_ARG_ENABLE([filesystem],
     [  --enable-filesystem     Enable Filesystem support (default: enabled)],
     [ ENABLED_FILESYSTEM=$enableval ],
@@ -1370,7 +1370,7 @@ else
 fi
 
 
-# inline Build 
+# inline Build
 AC_ARG_ENABLE([inline],
     [  --enable-inline         Enable inline functions (default: enabled)],
     [ ENABLED_INLINE=$enableval ],
@@ -1492,7 +1492,7 @@ AM_CONDITIONAL([BUILD_NTRU], [test "x$ENABLED_NTRU" = "xyes"])
 
 if test "$ENABLED_NTRU" = "yes" && test "$ENABLED_SMALL" = "yes"
 then
-    AC_MSG_ERROR([cannot enable ntru and small, ntru requires TLS which small turns off.]) 
+    AC_MSG_ERROR([cannot enable ntru and small, ntru requires TLS which small turns off.])
 fi
 
 # SNI
@@ -1648,6 +1648,22 @@ then
 fi
 
 
+# Secure Remote Password
+AC_ARG_ENABLE([srp],
+    [  --enable-srp            Enable Secure Remote Password (default: disabled)],
+    [ ENABLED_SRP=$enableval ],
+    [ ENABLED_SRP=no ]
+    )
+
+if test "x$ENABLED_SRP" = "xyes"
+then
+    AM_CFLAGS="$AM_CFLAGS -DWOLFCRYPT_HAVE_SRP"
+fi
+
+AM_CONDITIONAL([BUILD_SRP], [test "x$ENABLED_SRP" = "xyes"])
+
+
+
 # Small Stack
 AC_ARG_ENABLE([smallstack],
     [  --enable-smallstack     Enable Small Stack Usage (default: disabled)],
@@ -1684,7 +1700,7 @@ fi
 AM_CONDITIONAL([USE_VALGRIND], [test "x$ENABLED_VALGRIND" = "xyes"])
 
 
-# Test certs, use internal cert functions for extra testing 
+# Test certs, use internal cert functions for extra testing
 AC_ARG_ENABLE([testcert],
     [  --enable-testcert       Enable Test Cert (default: disabled)],
     [ ENABLED_TESTCERT=$enableval ],
@@ -1715,7 +1731,7 @@ then
 fi
 
 
-# Certificate Service Support 
+# Certificate Service Support
 AC_ARG_ENABLE([certservice],
     [  --enable-certservice    Enable cert service (default: disabled)],
     [ ENABLED_CERT_SERVICE=$enableval ],
@@ -1957,7 +1973,7 @@ AC_ARG_WITH([libz],
 AM_CONDITIONAL([BUILD_LIBZ], [test "x$ENABLED_LIBZ" = "xyes"])
 
 
-# cavium 
+# cavium
 trycaviumdir=""
 AC_ARG_WITH([cavium],
     [  --with-cavium=PATH      PATH to cavium/software dir ],
@@ -2183,7 +2199,7 @@ touch ctaocrypt/src/fips.c
 touch ctaocrypt/src/fips_test.c
 echo
 
-# generate user options header 
+# generate user options header
 echo "---"
 echo "Generating user options header..."
 
@@ -2193,7 +2209,7 @@ OPTION_FILE="wolfssl/options.h"
 #fi
 rm -f $OPTION_FILE
 
-echo "/* wolfssl options.h" > $OPTION_FILE 
+echo "/* wolfssl options.h" > $OPTION_FILE
 echo " * generated from configure options" >> $OPTION_FILE
 echo " *" >> $OPTION_FILE
 echo " * Copyright (C) 2006-2015 wolfSSL Inc." >> $OPTION_FILE
@@ -2202,13 +2218,13 @@ echo " * This file is part of wolfSSL. (formerly known as CyaSSL)" >> $OPTION_FI
 echo " *" >> $OPTION_FILE
 echo " */" >> $OPTION_FILE
 
-echo "" >> $OPTION_FILE 
-echo "#pragma once" >> $OPTION_FILE 
-echo "" >> $OPTION_FILE 
-echo "#ifdef __cplusplus" >> $OPTION_FILE 
-echo "extern \"C\" {" >> $OPTION_FILE 
-echo "#endif" >> $OPTION_FILE 
-echo "" >> $OPTION_FILE 
+echo "" >> $OPTION_FILE
+echo "#pragma once" >> $OPTION_FILE
+echo "" >> $OPTION_FILE
+echo "#ifdef __cplusplus" >> $OPTION_FILE
+echo "extern \"C\" {" >> $OPTION_FILE
+echo "#endif" >> $OPTION_FILE
+echo "" >> $OPTION_FILE
 
 for option in $OPTION_FLAGS; do
     defonly=`echo $option | sed 's/-D//'`
@@ -2244,11 +2260,11 @@ for option in $OPTION_FLAGS; do
     fi
 done
 
-echo "" >> $OPTION_FILE 
-echo "#ifdef __cplusplus" >> $OPTION_FILE 
-echo "}" >> $OPTION_FILE 
-echo "#endif" >> $OPTION_FILE 
-echo "" >> $OPTION_FILE 
+echo "" >> $OPTION_FILE
+echo "#ifdef __cplusplus" >> $OPTION_FILE
+echo "}" >> $OPTION_FILE
+echo "#endif" >> $OPTION_FILE
+echo "" >> $OPTION_FILE
 echo
 
 #backwards compatability for those who have included options or version
@@ -2279,7 +2295,7 @@ echo "   * Debug enabled:             $ax_enable_debug"
 echo "   * Warnings as failure:       $ac_cv_warnings_as_errors"
 echo "   * make -j:                   $enable_jobserver"
 echo "   * VCS checkout:              $ac_cv_vcs_checkout"
-echo 
+echo
 echo "   Features "
 echo "   * Single threaded:           $ENABLED_SINGLETHREADED"
 echo "   * Filesystem:                $ENABLED_FILESYSTEM"
@@ -2351,10 +2367,10 @@ echo "   * Session Ticket:            $ENABLED_SESSION_TICKET"
 echo "   * All TLS Extensions:        $ENABLED_TLSX"
 echo "   * PKCS#7                     $ENABLED_PKCS7"
 echo "   * wolfSCEP                   $ENABLED_WOLFSCEP"
+echo "   * Secure Remote Password     $ENABLED_SRP"
 echo "   * Small Stack:               $ENABLED_SMALL_STACK"
 echo "   * valgrind unit tests:       $ENABLED_VALGRIND"
 echo "   * LIBZ:                      $ENABLED_LIBZ"
 echo "   * Examples:                  $ENABLED_EXAMPLES"
 echo ""
 echo "---"
-

+ 4 - 1
src/include.am

@@ -201,6 +201,10 @@ if BUILD_PKCS7
 src_libwolfssl_la_SOURCES += wolfcrypt/src/pkcs7.c
 endif
 
+if BUILD_SRP
+src_libwolfssl_la_SOURCES += wolfcrypt/src/srp.c
+endif
+
 # ssl files
 src_libwolfssl_la_SOURCES += \
                src/internal.c \
@@ -220,4 +224,3 @@ endif
 if BUILD_SNIFFER
 src_libwolfssl_la_SOURCES += src/sniffer.c
 endif
-

+ 1 - 0
tests/include.am

@@ -11,6 +11,7 @@ tests_unit_test_SOURCES = \
                   tests/api.c \
                   tests/suites.c \
                   tests/hash.c \
+                  tests/srp.c \
                   examples/client/client.c \
                   examples/server/server.c
 tests_unit_test_CFLAGS       = -DNO_MAIN_DRIVER $(AM_CFLAGS)

+ 696 - 0
tests/srp.c

@@ -0,0 +1,696 @@
+/* srp.c SRP unit tests
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Geteral Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Geteral Public License for more details.
+ *
+ * You should have received a copy of the GNU Geteral Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#include <tests/unit.h>
+#include <wolfssl/wolfcrypt/sha512.h>
+#include <wolfssl/wolfcrypt/srp.h>
+
+#ifdef WOLFCRYPT_HAVE_SRP
+
+static byte username[] = "user";
+static word32 usernameSz = 4;
+
+static byte password[] = "password";
+static word32 passwordSz = 8;
+
+static byte N[] = {
+    0xD4, 0xC7, 0xF8, 0xA2, 0xB3, 0x2C, 0x11, 0xB8, 0xFB, 0xA9, 0x58, 0x1E,
+    0xC4, 0xBA, 0x4F, 0x1B, 0x04, 0x21, 0x56, 0x42, 0xEF, 0x73, 0x55, 0xE3,
+    0x7C, 0x0F, 0xC0, 0x44, 0x3E, 0xF7, 0x56, 0xEA, 0x2C, 0x6B, 0x8E, 0xEB,
+    0x75, 0x5A, 0x1C, 0x72, 0x30, 0x27, 0x66, 0x3C, 0xAA, 0x26, 0x5E, 0xF7,
+    0x85, 0xB8, 0xFF, 0x6A, 0x9B, 0x35, 0x22, 0x7A, 0x52, 0xD8, 0x66, 0x33,
+    0xDB, 0xDF, 0xCA, 0x43
+};
+
+static byte g[] = {
+    0x02
+};
+
+static byte salt[] = {
+    0x80, 0x66, 0x61, 0x5B, 0x7D, 0x33, 0xA2, 0x2E, 0x79, 0x18
+};
+
+static byte verifier[] = {
+    0x24, 0x5F, 0xA5, 0x1B, 0x2A, 0x28, 0xF8, 0xFF, 0xE2, 0xA0, 0xF8, 0x61,
+    0x7B, 0x0F, 0x3C, 0x05, 0xD6, 0x4A, 0x55, 0xDF, 0x74, 0x31, 0x54, 0x47,
+    0xA1, 0xFA, 0x9D, 0x25, 0x7B, 0x02, 0x88, 0x0A, 0xE8, 0x5A, 0xBA, 0x8B,
+    0xA2, 0xD3, 0x8A, 0x62, 0x46, 0x8C, 0xEC, 0x52, 0xBE, 0xDE, 0xFC, 0x75,
+    0xF5, 0xDB, 0x9C, 0x8C, 0x9B, 0x34, 0x7A, 0xE7, 0x4A, 0x5F, 0xBB, 0x96,
+    0x38, 0x19, 0xAB, 0x24
+};
+
+static byte a[] = {
+    0x37, 0x95, 0xF2, 0xA6, 0xF1, 0x6F, 0x0D, 0x58, 0xBF, 0xED, 0x44, 0x87,
+    0xE0, 0xB6, 0xCC, 0x1C, 0xA0, 0x50, 0xC6, 0x61, 0xBB, 0x36, 0xE0, 0x9A,
+    0xF3, 0xF7, 0x1E, 0x7A, 0x61, 0x86, 0x5A, 0xF5
+};
+
+static byte A[] = {
+    0x8D, 0x28, 0xC5, 0x6A, 0x46, 0x5C, 0x82, 0xDB, 0xC7, 0xF6, 0x8B, 0x62,
+    0x1A, 0xAD, 0xA1, 0x76, 0x1B, 0x55, 0xFF, 0xAB, 0x10, 0x2F, 0xFF, 0x4A,
+    0xAA, 0x46, 0xAD, 0x33, 0x64, 0xDE, 0x28, 0x2E, 0x82, 0x7A, 0xBE, 0xEA,
+    0x32, 0xFC, 0xD6, 0x14, 0x01, 0x71, 0xE6, 0xC8, 0xC9, 0x53, 0x69, 0x55,
+    0xE1, 0xF8, 0x3D, 0xDD, 0xC7, 0xD5, 0x21, 0xCE, 0xFF, 0x17, 0xFC, 0x23,
+    0xBF, 0xCF, 0x2D, 0xB0
+};
+
+static byte b[] = {
+    0x2B, 0xDD, 0x30, 0x30, 0x53, 0xAF, 0xD8, 0x3A, 0xE7, 0xE0, 0x17, 0x82,
+    0x39, 0x44, 0x2C, 0xDB, 0x30, 0x88, 0x0F, 0xC8, 0x88, 0xC2, 0xB2, 0xC1,
+    0x78, 0x43, 0x2F, 0xD5, 0x60, 0xD4, 0xDA, 0x43
+};
+
+static byte B[] = {
+    0xB5, 0x80, 0x36, 0x7F, 0x50, 0x89, 0xC1, 0x04, 0x42, 0x98, 0xD7, 0x6A,
+    0x37, 0x8E, 0xF1, 0x81, 0x52, 0xC5, 0x7A, 0xA1, 0xD5, 0xB7, 0x66, 0x84,
+    0xA1, 0x3E, 0x32, 0x82, 0x2B, 0x3A, 0xB5, 0xD7, 0x3D, 0x50, 0xF1, 0x58,
+    0xBD, 0x89, 0x75, 0xC7, 0x51, 0xCF, 0x6C, 0x03, 0xD4, 0xCA, 0xD5, 0x6E,
+    0x97, 0x4D, 0xA3, 0x1E, 0x19, 0x0B, 0xF0, 0xAA, 0x7D, 0x14, 0x90, 0x80,
+    0x0E, 0xC7, 0x92, 0xAD
+};
+
+static byte key[] = {
+    0x66, 0x00, 0x9D, 0x58, 0xB3, 0xD2, 0x0D, 0x4B, 0x69, 0x7F, 0xCF, 0x48,
+    0xFF, 0x8F, 0x15, 0x81, 0x4C, 0x4B, 0xFE, 0x9D, 0x85, 0x77, 0x88, 0x60,
+    0x1D, 0x1E, 0x51, 0xCF, 0x75, 0xCC, 0x58, 0x00, 0xE7, 0x8D, 0x22, 0x87,
+    0x13, 0x6C, 0x88, 0x55
+};
+
+static byte client_proof[] = {
+    0x0D, 0x49, 0xE1, 0x9C, 0x3A, 0x88, 0x43, 0x15, 0x45, 0xA8, 0xAC, 0xAB,
+    0xEA, 0x15, 0x1A, 0xEE, 0xF9, 0x38, 0x4D, 0x21
+};
+
+static byte server_proof[] = {
+    0xBD, 0xB1, 0x20, 0x70, 0x46, 0xC9, 0xD6, 0xCC, 0xE2, 0x1D, 0x75, 0xA2,
+    0xD0, 0xAF, 0xC5, 0xBC, 0xAE, 0x12, 0xFC, 0x75
+};
+
+static void test_SrpInit(void)
+{
+    Srp srp;
+
+    /* invalid params */
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpInit(NULL, SRP_TYPE_SHA, SRP_CLIENT_SIDE));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpInit(&srp, 255,          SRP_CLIENT_SIDE));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpInit(&srp, SRP_TYPE_SHA, 255            ));
+
+    /* success */
+    AssertIntEQ(0, wc_SrpInit(&srp, SRP_TYPE_SHA, SRP_CLIENT_SIDE));
+
+    wc_SrpTerm(&srp);
+}
+
+static void test_SrpSetUsername(void)
+{
+    Srp srp;
+
+    AssertIntEQ(0, wc_SrpInit(&srp, SRP_TYPE_SHA, SRP_CLIENT_SIDE));
+
+    /* invalid params */
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpSetUsername(NULL, username, usernameSz));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpSetUsername(&srp, NULL, usernameSz));
+
+    /* success */
+    AssertIntEQ(0, wc_SrpSetUsername(&srp, username, usernameSz));
+    AssertIntEQ((int) usernameSz, srp.userSz);
+    AssertIntEQ(0, XMEMCMP(srp.user, username, usernameSz));
+
+    wc_SrpTerm(&srp);
+}
+
+static void test_SrpSetParams(void)
+{
+    Srp srp;
+
+    AssertIntEQ(0, wc_SrpInit(&srp, SRP_TYPE_SHA, SRP_CLIENT_SIDE));
+
+    /* invalid call order */
+    AssertIntEQ(SRP_CALL_ORDER_E, wc_SrpSetParams(&srp, N,    sizeof(N),
+                                                        g,    sizeof(g),
+                                                        salt, sizeof(salt)));
+
+    /* fix call order */
+    AssertIntEQ(0, wc_SrpSetUsername(&srp, username, usernameSz));
+
+    /* invalid params */
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpSetParams(NULL, N,    sizeof(N),
+                                                    g,    sizeof(g),
+                                                    salt, sizeof(salt)));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpSetParams(&srp, NULL, sizeof(N),
+                                                    g,    sizeof(g),
+                                                    salt, sizeof(salt)));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpSetParams(&srp, N,    sizeof(N),
+                                                    NULL, sizeof(g),
+                                                    salt, sizeof(salt)));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpSetParams(&srp, N,    sizeof(N),
+                                                    g,    sizeof(g),
+                                                    NULL, sizeof(salt)));
+
+    /* success */
+    AssertIntEQ(0, wc_SrpSetParams(&srp, N,    sizeof(N),
+                                         g,    sizeof(g),
+                                         salt, sizeof(salt)));
+
+    AssertIntEQ(sizeof(salt), srp.saltSz);
+    AssertIntEQ(0, XMEMCMP(srp.salt, salt, srp.saltSz));
+
+    wc_SrpTerm(&srp);
+}
+
+static void test_SrpSetPassword(void)
+{
+    Srp srp;
+    byte v[64];
+    word32 vSz = 0;
+
+    AssertIntEQ(0, wc_SrpInit(&srp, SRP_TYPE_SHA, SRP_CLIENT_SIDE));
+    AssertIntEQ(0, wc_SrpSetUsername(&srp, username, usernameSz));
+
+    /* invalid call order */
+    AssertIntEQ(SRP_CALL_ORDER_E,
+                wc_SrpSetPassword(&srp, password, passwordSz));
+    AssertIntEQ(SRP_CALL_ORDER_E,
+                wc_SrpGetVerifier(&srp, v, &vSz));
+
+    /* fix call order */
+    AssertIntEQ(0, wc_SrpSetParams(&srp, N,    sizeof(N),
+                                         g,    sizeof(g),
+                                         salt, sizeof(salt)));
+
+    /* invalid params */
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpSetPassword(NULL, password, passwordSz));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpSetPassword(&srp, NULL,     passwordSz));
+
+    /* success */
+    AssertIntEQ(0, wc_SrpSetPassword(&srp, password, passwordSz));
+
+    /* invalid params */
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpGetVerifier(NULL, v,    &vSz));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpGetVerifier(&srp, NULL, &vSz));
+    AssertIntEQ(BUFFER_E,     wc_SrpGetVerifier(&srp, v,    &vSz));
+
+    /* success */
+    vSz = sizeof(v);
+    AssertIntEQ(0, wc_SrpGetVerifier(&srp, v, &vSz));
+    AssertIntEQ(vSz, sizeof(verifier));
+    AssertIntEQ(0, XMEMCMP(verifier, v, vSz));
+
+    /* invalid params - client side srp */
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpSetVerifier(&srp, v, vSz));
+
+    wc_SrpTerm(&srp);
+    AssertIntEQ(0, wc_SrpInit(&srp, SRP_TYPE_SHA, SRP_SERVER_SIDE));
+
+    /* invalid params */
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpSetVerifier(NULL, v,    vSz));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpSetVerifier(&srp, NULL, vSz));
+
+    /* success */
+    AssertIntEQ(0, wc_SrpSetVerifier(&srp, v, vSz));
+
+    wc_SrpTerm(&srp);
+}
+
+static void test_SrpGetPublic(void)
+{
+    Srp srp;
+    byte public[64];
+    word32 publicSz = 0;
+
+    AssertIntEQ(0, wc_SrpInit(&srp, SRP_TYPE_SHA, SRP_CLIENT_SIDE));
+    AssertIntEQ(0, wc_SrpSetUsername(&srp, username, usernameSz));
+    AssertIntEQ(0, wc_SrpSetParams(&srp, N,    sizeof(N),
+                                         g,    sizeof(g),
+                                         salt, sizeof(salt)));
+
+    /* invalid call order */
+    AssertIntEQ(SRP_CALL_ORDER_E, wc_SrpGetPublic(&srp, public, &publicSz));
+
+    /* fix call order */
+    AssertIntEQ(0, wc_SrpSetPassword(&srp, password, passwordSz));
+
+    /* invalid params */
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpGetPublic(NULL, public, &publicSz));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpGetPublic(&srp, NULL,   &publicSz));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpGetPublic(&srp, public, NULL));
+    AssertIntEQ(BUFFER_E,     wc_SrpGetPublic(&srp, public, &publicSz));
+
+    /* success */
+    publicSz = sizeof(public);
+    AssertIntEQ(0, wc_SrpSetPrivate(&srp, a, sizeof(a)));
+    AssertIntEQ(0, wc_SrpGetPublic(&srp, public, &publicSz));
+    AssertIntEQ(publicSz, sizeof(A));
+    AssertIntEQ(0, XMEMCMP(public, A, publicSz));
+
+    wc_SrpTerm(&srp);
+
+    AssertIntEQ(0, wc_SrpInit(&srp, SRP_TYPE_SHA, SRP_SERVER_SIDE));
+    AssertIntEQ(0, wc_SrpSetUsername(&srp, username, usernameSz));
+    AssertIntEQ(0, wc_SrpSetParams(&srp, N,    sizeof(N),
+                                         g,    sizeof(g),
+                                         salt, sizeof(salt)));
+
+    /* invalid call order */
+    AssertIntEQ(SRP_CALL_ORDER_E, wc_SrpGetPublic(&srp, public, &publicSz));
+
+    /* fix call order */
+    AssertIntEQ(0, wc_SrpSetVerifier(&srp, verifier, sizeof(verifier)));
+
+    /* success */
+    AssertIntEQ(0, wc_SrpSetPrivate(&srp, b, sizeof(b)));
+    AssertIntEQ(0, wc_SrpGetPublic(&srp, public, &publicSz));
+    AssertIntEQ(publicSz, sizeof(B));
+    AssertIntEQ(0, XMEMCMP(public, B, publicSz));
+
+    wc_SrpTerm(&srp);
+}
+
+static void test_SrpComputeKey(void)
+{
+    Srp cli, srv;
+    byte clientPubKey[64];
+    byte serverPubKey[64];
+    word32 clientPubKeySz = 64;
+    word32 serverPubKeySz = 64;
+
+    AssertIntEQ(0, wc_SrpInit(&cli, SRP_TYPE_SHA, SRP_CLIENT_SIDE));
+    AssertIntEQ(0, wc_SrpInit(&srv, SRP_TYPE_SHA, SRP_SERVER_SIDE));
+
+    /* invalid call order */
+    AssertIntEQ(SRP_CALL_ORDER_E, wc_SrpComputeKey(&cli,
+                                                   clientPubKey, clientPubKeySz,
+                                                   serverPubKey, serverPubKeySz));
+
+    /* fix call order */
+    AssertIntEQ(0, wc_SrpSetUsername(&cli, username, usernameSz));
+    AssertIntEQ(0, wc_SrpSetUsername(&srv, username, usernameSz));
+
+    AssertIntEQ(0, wc_SrpSetParams(&cli, N,    sizeof(N),
+                                         g,    sizeof(g),
+                                         salt, sizeof(salt)));
+    AssertIntEQ(0, wc_SrpSetParams(&srv, N,    sizeof(N),
+                                         g,    sizeof(g),
+                                         salt, sizeof(salt)));
+
+    AssertIntEQ(0, wc_SrpSetPassword(&cli, password, passwordSz));
+    AssertIntEQ(0, wc_SrpSetVerifier(&srv, verifier, sizeof(verifier)));
+
+    AssertIntEQ(0, wc_SrpSetPrivate(&cli, a, sizeof(a)));
+    AssertIntEQ(0, wc_SrpGetPublic(&cli, clientPubKey, &clientPubKeySz));
+    AssertIntEQ(0, XMEMCMP(clientPubKey, A, clientPubKeySz));
+    AssertIntEQ(0, wc_SrpSetPrivate(&srv, b, sizeof(b)));
+    AssertIntEQ(0, wc_SrpGetPublic(&srv, serverPubKey, &serverPubKeySz));
+    AssertIntEQ(0, XMEMCMP(serverPubKey, B, serverPubKeySz));
+
+    /* invalid params */
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpComputeKey(NULL,
+                                               clientPubKey, clientPubKeySz,
+                                               serverPubKey, serverPubKeySz));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpComputeKey(&cli,
+                                               NULL,         clientPubKeySz,
+                                               serverPubKey, serverPubKeySz));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpComputeKey(&cli,
+                                               clientPubKey, 0,
+                                               serverPubKey, serverPubKeySz));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpComputeKey(&cli,
+                                               clientPubKey, clientPubKeySz,
+                                               NULL,         serverPubKeySz));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpComputeKey(&cli,
+                                               clientPubKey, clientPubKeySz,
+                                               serverPubKey, 0));
+
+    /* success */
+    AssertIntEQ(0, wc_SrpComputeKey(&cli, clientPubKey, clientPubKeySz,
+                                          serverPubKey, serverPubKeySz));
+    AssertIntEQ(0, wc_SrpComputeKey(&srv, clientPubKey, clientPubKeySz,
+                                          serverPubKey, serverPubKeySz));
+    AssertIntEQ(0, XMEMCMP(cli.key, key, sizeof(key)));
+    AssertIntEQ(0, XMEMCMP(srv.key, key, sizeof(key)));
+
+    wc_SrpTerm(&cli);
+    wc_SrpTerm(&srv);
+}
+
+static void test_SrpGetProofAndVerify(void)
+{
+    Srp cli, srv;
+    byte clientPubKey[64];
+    byte serverPubKey[64];
+    word32 clientPubKeySz = 64;
+    word32 serverPubKeySz = 64;
+    byte clientProof[SRP_MAX_DIGEST_SIZE];
+    byte serverProof[SRP_MAX_DIGEST_SIZE];
+    word32 clientProofSz = SRP_MAX_DIGEST_SIZE;
+    word32 serverProofSz = SRP_MAX_DIGEST_SIZE;
+
+    AssertIntEQ(0, wc_SrpInit(&cli, SRP_TYPE_SHA, SRP_CLIENT_SIDE));
+    AssertIntEQ(0, wc_SrpInit(&srv, SRP_TYPE_SHA, SRP_SERVER_SIDE));
+
+    AssertIntEQ(0, wc_SrpSetUsername(&cli, username, usernameSz));
+    AssertIntEQ(0, wc_SrpSetUsername(&srv, username, usernameSz));
+
+    AssertIntEQ(0, wc_SrpSetParams(&cli, N,    sizeof(N),
+                                         g,    sizeof(g),
+                                         salt, sizeof(salt)));
+    AssertIntEQ(0, wc_SrpSetParams(&srv, N,    sizeof(N),
+                                         g,    sizeof(g),
+                                         salt, sizeof(salt)));
+
+    AssertIntEQ(0, wc_SrpSetPassword(&cli, password, passwordSz));
+    AssertIntEQ(0, wc_SrpSetVerifier(&srv, verifier, sizeof(verifier)));
+
+    AssertIntEQ(0, wc_SrpSetPrivate(&cli, a, sizeof(a)));
+    AssertIntEQ(0, wc_SrpGetPublic(&cli, clientPubKey, &clientPubKeySz));
+    AssertIntEQ(0, XMEMCMP(clientPubKey, A, clientPubKeySz));
+
+    AssertIntEQ(0, wc_SrpSetPrivate(&srv, b, sizeof(b)));
+    AssertIntEQ(0, wc_SrpGetPublic(&srv, serverPubKey, &serverPubKeySz));
+    AssertIntEQ(0, XMEMCMP(serverPubKey, B, serverPubKeySz));
+
+    AssertIntEQ(0, wc_SrpComputeKey(&cli, clientPubKey, clientPubKeySz,
+                                          serverPubKey, serverPubKeySz));
+    AssertIntEQ(0, XMEMCMP(cli.key, key, sizeof(key)));
+
+    AssertIntEQ(0, wc_SrpComputeKey(&srv, clientPubKey, clientPubKeySz,
+                                          serverPubKey, serverPubKeySz));
+    AssertIntEQ(0, XMEMCMP(srv.key, key, sizeof(key)));
+
+    /* invalid params */
+    serverProofSz = 0;
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpGetProof(NULL, clientProof,&clientProofSz));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpGetProof(&cli, NULL,       &clientProofSz));
+    AssertIntEQ(BAD_FUNC_ARG, wc_SrpGetProof(&cli, clientProof,NULL));
+    AssertIntEQ(BUFFER_E,     wc_SrpGetProof(&srv, serverProof,&serverProofSz));
+
+    AssertIntEQ(BAD_FUNC_ARG,
+                wc_SrpVerifyPeersProof(NULL, clientProof, clientProofSz));
+    AssertIntEQ(BAD_FUNC_ARG,
+                wc_SrpVerifyPeersProof(&cli, NULL,        clientProofSz));
+    AssertIntEQ(BUFFER_E,
+                wc_SrpVerifyPeersProof(&srv, serverProof, serverProofSz));
+    serverProofSz = SRP_MAX_DIGEST_SIZE;
+
+    /* success */
+    AssertIntEQ(0, wc_SrpGetProof(&cli, clientProof, &clientProofSz));
+    AssertIntEQ(0, XMEMCMP(clientProof, client_proof, sizeof(client_proof)));
+    AssertIntEQ(0, wc_SrpVerifyPeersProof(&srv, clientProof, clientProofSz));
+    AssertIntEQ(0, wc_SrpGetProof(&srv, serverProof, &serverProofSz));
+    AssertIntEQ(0, XMEMCMP(serverProof, server_proof, sizeof(server_proof)));
+    AssertIntEQ(0, wc_SrpVerifyPeersProof(&cli, serverProof, serverProofSz));
+
+    wc_SrpTerm(&cli);
+    wc_SrpTerm(&srv);
+}
+
+static int sha512_key_gen(Srp* srp, byte* secret, word32 size)
+{
+    Sha512 hash;
+    int r;
+
+    srp->key = (byte*)XMALLOC(SHA512_DIGEST_SIZE, NULL, DYNAMIC_TYPE_SRP);
+    if (srp->key == NULL)
+        return MEMORY_E;
+
+    srp->keySz = SHA512_DIGEST_SIZE;
+
+    r = wc_InitSha512(&hash);
+    if (!r) r = wc_Sha512Update(&hash, secret, size);
+    if (!r) r = wc_Sha512Final(&hash, srp->key);
+
+    XMEMSET(&hash, 0, sizeof(Sha512));
+
+    return r;
+}
+
+static void test_SrpKeyGenFunc_cb(void)
+{
+    Srp cli, srv;
+    byte clientPubKey[1024];
+    byte serverPubKey[1024];
+    word32 clientPubKeySz = 1024;
+    word32 serverPubKeySz = 1024;
+    byte clientProof[SRP_MAX_DIGEST_SIZE];
+    byte serverProof[SRP_MAX_DIGEST_SIZE];
+    word32 clientProofSz = SRP_MAX_DIGEST_SIZE;
+    word32 serverProofSz = SRP_MAX_DIGEST_SIZE;
+
+    byte username_[] = "alice";
+    word32 usernameSz_ = 5;
+
+    byte password_[] = "password123";
+    word32 passwordSz_ = 11;
+
+    byte N_[] = {
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
+        0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
+        0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
+        0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
+        0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
+        0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+        0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
+        0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+        0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
+        0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+        0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
+        0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
+        0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2,
+        0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
+        0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C,
+        0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
+        0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D,
+        0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
+        0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57,
+        0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
+        0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0,
+        0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
+        0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73,
+        0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
+        0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0,
+        0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
+        0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20,
+        0xA9, 0x3A, 0xD2, 0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+    };
+
+    byte g_[] = {
+        0x05
+    };
+
+    byte salt_[] = {
+        0xBE, 0xB2, 0x53, 0x79, 0xD1, 0xA8, 0x58, 0x1E, 0xB5, 0xA7, 0x27, 0x67,
+        0x3A, 0x24, 0x41, 0xEE
+    };
+
+    byte verifier_[] = {
+        0x9B, 0x5E, 0x06, 0x17, 0x01, 0xEA, 0x7A, 0xEB, 0x39, 0xCF, 0x6E, 0x35,
+        0x19, 0x65, 0x5A, 0x85, 0x3C, 0xF9, 0x4C, 0x75, 0xCA, 0xF2, 0x55, 0x5E,
+        0xF1, 0xFA, 0xF7, 0x59, 0xBB, 0x79, 0xCB, 0x47, 0x70, 0x14, 0xE0, 0x4A,
+        0x88, 0xD6, 0x8F, 0xFC, 0x05, 0x32, 0x38, 0x91, 0xD4, 0xC2, 0x05, 0xB8,
+        0xDE, 0x81, 0xC2, 0xF2, 0x03, 0xD8, 0xFA, 0xD1, 0xB2, 0x4D, 0x2C, 0x10,
+        0x97, 0x37, 0xF1, 0xBE, 0xBB, 0xD7, 0x1F, 0x91, 0x24, 0x47, 0xC4, 0xA0,
+        0x3C, 0x26, 0xB9, 0xFA, 0xD8, 0xED, 0xB3, 0xE7, 0x80, 0x77, 0x8E, 0x30,
+        0x25, 0x29, 0xED, 0x1E, 0xE1, 0x38, 0xCC, 0xFC, 0x36, 0xD4, 0xBA, 0x31,
+        0x3C, 0xC4, 0x8B, 0x14, 0xEA, 0x8C, 0x22, 0xA0, 0x18, 0x6B, 0x22, 0x2E,
+        0x65, 0x5F, 0x2D, 0xF5, 0x60, 0x3F, 0xD7, 0x5D, 0xF7, 0x6B, 0x3B, 0x08,
+        0xFF, 0x89, 0x50, 0x06, 0x9A, 0xDD, 0x03, 0xA7, 0x54, 0xEE, 0x4A, 0xE8,
+        0x85, 0x87, 0xCC, 0xE1, 0xBF, 0xDE, 0x36, 0x79, 0x4D, 0xBA, 0xE4, 0x59,
+        0x2B, 0x7B, 0x90, 0x4F, 0x44, 0x2B, 0x04, 0x1C, 0xB1, 0x7A, 0xEB, 0xAD,
+        0x1E, 0x3A, 0xEB, 0xE3, 0xCB, 0xE9, 0x9D, 0xE6, 0x5F, 0x4B, 0xB1, 0xFA,
+        0x00, 0xB0, 0xE7, 0xAF, 0x06, 0x86, 0x3D, 0xB5, 0x3B, 0x02, 0x25, 0x4E,
+        0xC6, 0x6E, 0x78, 0x1E, 0x3B, 0x62, 0xA8, 0x21, 0x2C, 0x86, 0xBE, 0xB0,
+        0xD5, 0x0B, 0x5B, 0xA6, 0xD0, 0xB4, 0x78, 0xD8, 0xC4, 0xE9, 0xBB, 0xCE,
+        0xC2, 0x17, 0x65, 0x32, 0x6F, 0xBD, 0x14, 0x05, 0x8D, 0x2B, 0xBD, 0xE2,
+        0xC3, 0x30, 0x45, 0xF0, 0x38, 0x73, 0xE5, 0x39, 0x48, 0xD7, 0x8B, 0x79,
+        0x4F, 0x07, 0x90, 0xE4, 0x8C, 0x36, 0xAE, 0xD6, 0xE8, 0x80, 0xF5, 0x57,
+        0x42, 0x7B, 0x2F, 0xC0, 0x6D, 0xB5, 0xE1, 0xE2, 0xE1, 0xD7, 0xE6, 0x61,
+        0xAC, 0x48, 0x2D, 0x18, 0xE5, 0x28, 0xD7, 0x29, 0x5E, 0xF7, 0x43, 0x72,
+        0x95, 0xFF, 0x1A, 0x72, 0xD4, 0x02, 0x77, 0x17, 0x13, 0xF1, 0x68, 0x76,
+        0xDD, 0x05, 0x0A, 0xE5, 0xB7, 0xAD, 0x53, 0xCC, 0xB9, 0x08, 0x55, 0xC9,
+        0x39, 0x56, 0x64, 0x83, 0x58, 0xAD, 0xFD, 0x96, 0x64, 0x22, 0xF5, 0x24,
+        0x98, 0x73, 0x2D, 0x68, 0xD1, 0xD7, 0xFB, 0xEF, 0x10, 0xD7, 0x80, 0x34,
+        0xAB, 0x8D, 0xCB, 0x6F, 0x0F, 0xCF, 0x88, 0x5C, 0xC2, 0xB2, 0xEA, 0x2C,
+        0x3E, 0x6A, 0xC8, 0x66, 0x09, 0xEA, 0x05, 0x8A, 0x9D, 0xA8, 0xCC, 0x63,
+        0x53, 0x1D, 0xC9, 0x15, 0x41, 0x4D, 0xF5, 0x68, 0xB0, 0x94, 0x82, 0xDD,
+        0xAC, 0x19, 0x54, 0xDE, 0xC7, 0xEB, 0x71, 0x4F, 0x6F, 0xF7, 0xD4, 0x4C,
+        0xD5, 0xB8, 0x6F, 0x6B, 0xD1, 0x15, 0x81, 0x09, 0x30, 0x63, 0x7C, 0x01,
+        0xD0, 0xF6, 0x01, 0x3B, 0xC9, 0x74, 0x0F, 0xA2, 0xC6, 0x33, 0xBA, 0x89
+    };
+
+    byte a_[] = {
+        0x60, 0x97, 0x55, 0x27, 0x03, 0x5C, 0xF2, 0xAD, 0x19, 0x89, 0x80, 0x6F,
+        0x04, 0x07, 0x21, 0x0B, 0xC8, 0x1E, 0xDC, 0x04, 0xE2, 0x76, 0x2A, 0x56,
+        0xAF, 0xD5, 0x29, 0xDD, 0xDA, 0x2D, 0x43, 0x93
+    };
+
+    byte A_[] = {
+        0xFA, 0xB6, 0xF5, 0xD2, 0x61, 0x5D, 0x1E, 0x32, 0x35, 0x12, 0xE7, 0x99,
+        0x1C, 0xC3, 0x74, 0x43, 0xF4, 0x87, 0xDA, 0x60, 0x4C, 0xA8, 0xC9, 0x23,
+        0x0F, 0xCB, 0x04, 0xE5, 0x41, 0xDC, 0xE6, 0x28, 0x0B, 0x27, 0xCA, 0x46,
+        0x80, 0xB0, 0x37, 0x4F, 0x17, 0x9D, 0xC3, 0xBD, 0xC7, 0x55, 0x3F, 0xE6,
+        0x24, 0x59, 0x79, 0x8C, 0x70, 0x1A, 0xD8, 0x64, 0xA9, 0x13, 0x90, 0xA2,
+        0x8C, 0x93, 0xB6, 0x44, 0xAD, 0xBF, 0x9C, 0x00, 0x74, 0x5B, 0x94, 0x2B,
+        0x79, 0xF9, 0x01, 0x2A, 0x21, 0xB9, 0xB7, 0x87, 0x82, 0x31, 0x9D, 0x83,
+        0xA1, 0xF8, 0x36, 0x28, 0x66, 0xFB, 0xD6, 0xF4, 0x6B, 0xFC, 0x0D, 0xDB,
+        0x2E, 0x1A, 0xB6, 0xE4, 0xB4, 0x5A, 0x99, 0x06, 0xB8, 0x2E, 0x37, 0xF0,
+        0x5D, 0x6F, 0x97, 0xF6, 0xA3, 0xEB, 0x6E, 0x18, 0x20, 0x79, 0x75, 0x9C,
+        0x4F, 0x68, 0x47, 0x83, 0x7B, 0x62, 0x32, 0x1A, 0xC1, 0xB4, 0xFA, 0x68,
+        0x64, 0x1F, 0xCB, 0x4B, 0xB9, 0x8D, 0xD6, 0x97, 0xA0, 0xC7, 0x36, 0x41,
+        0x38, 0x5F, 0x4B, 0xAB, 0x25, 0xB7, 0x93, 0x58, 0x4C, 0xC3, 0x9F, 0xC8,
+        0xD4, 0x8D, 0x4B, 0xD8, 0x67, 0xA9, 0xA3, 0xC1, 0x0F, 0x8E, 0xA1, 0x21,
+        0x70, 0x26, 0x8E, 0x34, 0xFE, 0x3B, 0xBE, 0x6F, 0xF8, 0x99, 0x98, 0xD6,
+        0x0D, 0xA2, 0xF3, 0xE4, 0x28, 0x3C, 0xBE, 0xC1, 0x39, 0x3D, 0x52, 0xAF,
+        0x72, 0x4A, 0x57, 0x23, 0x0C, 0x60, 0x4E, 0x9F, 0xBC, 0xE5, 0x83, 0xD7,
+        0x61, 0x3E, 0x6B, 0xFF, 0xD6, 0x75, 0x96, 0xAD, 0x12, 0x1A, 0x87, 0x07,
+        0xEE, 0xC4, 0x69, 0x44, 0x95, 0x70, 0x33, 0x68, 0x6A, 0x15, 0x5F, 0x64,
+        0x4D, 0x5C, 0x58, 0x63, 0xB4, 0x8F, 0x61, 0xBD, 0xBF, 0x19, 0xA5, 0x3E,
+        0xAB, 0x6D, 0xAD, 0x0A, 0x18, 0x6B, 0x8C, 0x15, 0x2E, 0x5F, 0x5D, 0x8C,
+        0xAD, 0x4B, 0x0E, 0xF8, 0xAA, 0x4E, 0xA5, 0x00, 0x88, 0x34, 0xC3, 0xCD,
+        0x34, 0x2E, 0x5E, 0x0F, 0x16, 0x7A, 0xD0, 0x45, 0x92, 0xCD, 0x8B, 0xD2,
+        0x79, 0x63, 0x93, 0x98, 0xEF, 0x9E, 0x11, 0x4D, 0xFA, 0xAA, 0xB9, 0x19,
+        0xE1, 0x4E, 0x85, 0x09, 0x89, 0x22, 0x4D, 0xDD, 0x98, 0x57, 0x6D, 0x79,
+        0x38, 0x5D, 0x22, 0x10, 0x90, 0x2E, 0x9F, 0x9B, 0x1F, 0x2D, 0x86, 0xCF,
+        0xA4, 0x7E, 0xE2, 0x44, 0x63, 0x54, 0x65, 0xF7, 0x10, 0x58, 0x42, 0x1A,
+        0x01, 0x84, 0xBE, 0x51, 0xDD, 0x10, 0xCC, 0x9D, 0x07, 0x9E, 0x6F, 0x16,
+        0x04, 0xE7, 0xAA, 0x9B, 0x7C, 0xF7, 0x88, 0x3C, 0x7D, 0x4C, 0xE1, 0x2B,
+        0x06, 0xEB, 0xE1, 0x60, 0x81, 0xE2, 0x3F, 0x27, 0xA2, 0x31, 0xD1, 0x84,
+        0x32, 0xD7, 0xD1, 0xBB, 0x55, 0xC2, 0x8A, 0xE2, 0x1F, 0xFC, 0xF0, 0x05,
+        0xF5, 0x75, 0x28, 0xD1, 0x5A, 0x88, 0x88, 0x1B, 0xB3, 0xBB, 0xB7, 0xFE
+    };
+
+    byte b_[] = {
+        0xE4, 0x87, 0xCB, 0x59, 0xD3, 0x1A, 0xC5, 0x50, 0x47, 0x1E, 0x81, 0xF0,
+        0x0F, 0x69, 0x28, 0xE0, 0x1D, 0xDA, 0x08, 0xE9, 0x74, 0xA0, 0x04, 0xF4,
+        0x9E, 0x61, 0xF5, 0xD1, 0x05, 0x28, 0x4D, 0x20
+    };
+
+    byte B_[] = {
+        0x40, 0xF5, 0x70, 0x88, 0xA4, 0x82, 0xD4, 0xC7, 0x73, 0x33, 0x84, 0xFE,
+        0x0D, 0x30, 0x1F, 0xDD, 0xCA, 0x90, 0x80, 0xAD, 0x7D, 0x4F, 0x6F, 0xDF,
+        0x09, 0xA0, 0x10, 0x06, 0xC3, 0xCB, 0x6D, 0x56, 0x2E, 0x41, 0x63, 0x9A,
+        0xE8, 0xFA, 0x21, 0xDE, 0x3B, 0x5D, 0xBA, 0x75, 0x85, 0xB2, 0x75, 0x58,
+        0x9B, 0xDB, 0x27, 0x98, 0x63, 0xC5, 0x62, 0x80, 0x7B, 0x2B, 0x99, 0x08,
+        0x3C, 0xD1, 0x42, 0x9C, 0xDB, 0xE8, 0x9E, 0x25, 0xBF, 0xBD, 0x7E, 0x3C,
+        0xAD, 0x31, 0x73, 0xB2, 0xE3, 0xC5, 0xA0, 0xB1, 0x74, 0xDA, 0x6D, 0x53,
+        0x91, 0xE6, 0xA0, 0x6E, 0x46, 0x5F, 0x03, 0x7A, 0x40, 0x06, 0x25, 0x48,
+        0x39, 0xA5, 0x6B, 0xF7, 0x6D, 0xA8, 0x4B, 0x1C, 0x94, 0xE0, 0xAE, 0x20,
+        0x85, 0x76, 0x15, 0x6F, 0xE5, 0xC1, 0x40, 0xA4, 0xBA, 0x4F, 0xFC, 0x9E,
+        0x38, 0xC3, 0xB0, 0x7B, 0x88, 0x84, 0x5F, 0xC6, 0xF7, 0xDD, 0xDA, 0x93,
+        0x38, 0x1F, 0xE0, 0xCA, 0x60, 0x84, 0xC4, 0xCD, 0x2D, 0x33, 0x6E, 0x54,
+        0x51, 0xC4, 0x64, 0xCC, 0xB6, 0xEC, 0x65, 0xE7, 0xD1, 0x6E, 0x54, 0x8A,
+        0x27, 0x3E, 0x82, 0x62, 0x84, 0xAF, 0x25, 0x59, 0xB6, 0x26, 0x42, 0x74,
+        0x21, 0x59, 0x60, 0xFF, 0xF4, 0x7B, 0xDD, 0x63, 0xD3, 0xAF, 0xF0, 0x64,
+        0xD6, 0x13, 0x7A, 0xF7, 0x69, 0x66, 0x1C, 0x9D, 0x4F, 0xEE, 0x47, 0x38,
+        0x26, 0x03, 0xC8, 0x8E, 0xAA, 0x09, 0x80, 0x58, 0x1D, 0x07, 0x75, 0x84,
+        0x61, 0xB7, 0x77, 0xE4, 0x35, 0x6D, 0xDA, 0x58, 0x35, 0x19, 0x8B, 0x51,
+        0xFE, 0xEA, 0x30, 0x8D, 0x70, 0xF7, 0x54, 0x50, 0xB7, 0x16, 0x75, 0xC0,
+        0x8C, 0x7D, 0x83, 0x02, 0xFD, 0x75, 0x39, 0xDD, 0x1F, 0xF2, 0xA1, 0x1C,
+        0xB4, 0x25, 0x8A, 0xA7, 0x0D, 0x23, 0x44, 0x36, 0xAA, 0x42, 0xB6, 0xA0,
+        0x61, 0x5F, 0x3F, 0x91, 0x5D, 0x55, 0xCC, 0x3B, 0x96, 0x6B, 0x27, 0x16,
+        0xB3, 0x6E, 0x4D, 0x1A, 0x06, 0xCE, 0x5E, 0x5D, 0x2E, 0xA3, 0xBE, 0xE5,
+        0xA1, 0x27, 0x0E, 0x87, 0x51, 0xDA, 0x45, 0xB6, 0x0B, 0x99, 0x7B, 0x0F,
+        0xFD, 0xB0, 0xF9, 0x96, 0x2F, 0xEE, 0x4F, 0x03, 0xBE, 0xE7, 0x80, 0xBA,
+        0x0A, 0x84, 0x5B, 0x1D, 0x92, 0x71, 0x42, 0x17, 0x83, 0xAE, 0x66, 0x01,
+        0xA6, 0x1E, 0xA2, 0xE3, 0x42, 0xE4, 0xF2, 0xE8, 0xBC, 0x93, 0x5A, 0x40,
+        0x9E, 0xAD, 0x19, 0xF2, 0x21, 0xBD, 0x1B, 0x74, 0xE2, 0x96, 0x4D, 0xD1,
+        0x9F, 0xC8, 0x45, 0xF6, 0x0E, 0xFC, 0x09, 0x33, 0x8B, 0x60, 0xB6, 0xB2,
+        0x56, 0xD8, 0xCA, 0xC8, 0x89, 0xCC, 0xA3, 0x06, 0xCC, 0x37, 0x0A, 0x0B,
+        0x18, 0xC8, 0xB8, 0x86, 0xE9, 0x5D, 0xA0, 0xAF, 0x52, 0x35, 0xFE, 0xF4,
+        0x39, 0x30, 0x20, 0xD2, 0xB7, 0xF3, 0x05, 0x69, 0x04, 0x75, 0x90, 0x42
+    };
+
+    byte key_[] = {
+        0x5C, 0xBC, 0x21, 0x9D, 0xB0, 0x52, 0x13, 0x8E, 0xE1, 0x14, 0x8C, 0x71,
+        0xCD, 0x44, 0x98, 0x96, 0x3D, 0x68, 0x25, 0x49, 0xCE, 0x91, 0xCA, 0x24,
+        0xF0, 0x98, 0x46, 0x8F, 0x06, 0x01, 0x5B, 0xEB, 0x6A, 0xF2, 0x45, 0xC2,
+        0x09, 0x3F, 0x98, 0xC3, 0x65, 0x1B, 0xCA, 0x83, 0xAB, 0x8C, 0xAB, 0x2B,
+        0x58, 0x0B, 0xBF, 0x02, 0x18, 0x4F, 0xEF, 0xDF, 0x26, 0x14, 0x2F, 0x73,
+        0xDF, 0x95, 0xAC, 0x50
+    };
+
+    AssertIntEQ(0, wc_SrpInit(&cli, SRP_TYPE_SHA512, SRP_CLIENT_SIDE));
+    AssertIntEQ(0, wc_SrpInit(&srv, SRP_TYPE_SHA512, SRP_SERVER_SIDE));
+
+    AssertIntEQ(0, wc_SrpSetUsername(&cli, username_, usernameSz_));
+    AssertIntEQ(0, wc_SrpSetUsername(&srv, username_, usernameSz_));
+
+    AssertIntEQ(0, wc_SrpSetParams(&cli, N_,    sizeof(N_),
+                                         g_,    sizeof(g_),
+                                         salt_, sizeof(salt_)));
+    AssertIntEQ(0, wc_SrpSetParams(&srv, N_,    sizeof(N_),
+                                         g_,    sizeof(g_),
+                                         salt_, sizeof(salt_)));
+
+    AssertIntEQ(0, wc_SrpSetPassword(&cli, password_, passwordSz_));
+    AssertIntEQ(0, wc_SrpSetVerifier(&srv, verifier_, sizeof(verifier_)));
+
+    AssertIntEQ(0, wc_SrpSetPrivate(&cli, a_, sizeof(a_)));
+    AssertIntEQ(0, wc_SrpGetPublic(&cli, clientPubKey, &clientPubKeySz));
+    AssertIntEQ(0, XMEMCMP(clientPubKey, A_, clientPubKeySz));
+
+    AssertIntEQ(0, wc_SrpSetPrivate(&srv, b_, sizeof(b_)));
+    AssertIntEQ(0, wc_SrpGetPublic(&srv, serverPubKey, &serverPubKeySz));
+    AssertIntEQ(0, XMEMCMP(serverPubKey, B_, serverPubKeySz));
+
+    cli.keyGenFunc_cb = sha512_key_gen;
+    AssertIntEQ(0, wc_SrpComputeKey(&cli, clientPubKey, clientPubKeySz,
+                                          serverPubKey, serverPubKeySz));
+    AssertIntEQ(0, XMEMCMP(cli.key, key_, sizeof(key_)));
+
+    srv.keyGenFunc_cb = sha512_key_gen;
+    AssertIntEQ(0, wc_SrpComputeKey(&srv, clientPubKey, clientPubKeySz,
+                                          serverPubKey, serverPubKeySz));
+    AssertIntEQ(0, XMEMCMP(srv.key, key_, sizeof(key_)));
+
+    AssertIntEQ(0, wc_SrpGetProof(&cli, clientProof, &clientProofSz));
+    AssertIntEQ(0, wc_SrpVerifyPeersProof(&srv, clientProof, clientProofSz));
+
+    AssertIntEQ(0, wc_SrpGetProof(&srv, serverProof, &serverProofSz));
+    AssertIntEQ(0, wc_SrpVerifyPeersProof(&cli, serverProof, serverProofSz));
+
+    wc_SrpTerm(&cli);
+    wc_SrpTerm(&srv);
+}
+
+#endif
+
+void SrpTest(void)
+{
+#ifdef WOLFCRYPT_HAVE_SRP
+    test_SrpInit();
+    test_SrpSetUsername();
+    test_SrpSetParams();
+    test_SrpSetPassword();
+    test_SrpGetPublic();
+    test_SrpComputeKey();
+    test_SrpGetProofAndVerify();
+    test_SrpKeyGenFunc_cb();
+#endif
+}

+ 3 - 2
tests/unit.c

@@ -77,6 +77,8 @@ int unit_test(int argc, char** argv)
     }
 #endif
 
+    SrpTest();
+
 #ifdef HAVE_CAVIUM
         CspShutdown(CAVIUM_DEV_ID);
 #endif
@@ -92,7 +94,7 @@ void wait_tcp_ready(func_args* args)
     (void)args;
 #elif defined(_POSIX_THREADS) && !defined(__MINGW32__)
     pthread_mutex_lock(&args->signal->mutex);
-    
+
     if (!args->signal->ready)
         pthread_cond_wait(&args->signal->cond, &args->signal->mutex);
     args->signal->ready = 0; /* reset */
@@ -176,4 +178,3 @@ void FreeTcpReady(tcp_ready* ready)
     (void)ready;
 #endif
 }
-

+ 5 - 5
tests/unit.h

@@ -27,8 +27,8 @@
 
 #define Fail(description, result) do {                                         \
     printf("\nERROR - %s line %d failed with:", __FILE__, __LINE__);           \
-    printf("\n\n    test:   "); printf description;                            \
-    printf("\n\n    result: "); printf result;                                 \
+    printf("\n    expected: "); printf description;                            \
+    printf("\n    result:   "); printf result; printf("\n\n");                 \
     abort();                                                                   \
 } while(0)
 
@@ -76,9 +76,9 @@
 
 
 void ApiTest(void);
-int SuiteTest(void);
-int HashTest(void);
+int  SuiteTest(void);
+int  HashTest(void);
+void SrpTest(void);
 
 
 #endif /* CyaSSL_UNIT_H */
-

+ 9 - 0
wolfcrypt/src/error.c

@@ -328,6 +328,15 @@ const char* wc_GetErrorString(int error)
     case ECC_PRIV_KEY_E:
         return " ECC private key is not valid error";
 
+    case SRP_CALL_ORDER_E:
+        return "SRP function called in the wrong order error";
+
+    case SRP_VERIFY_E:
+        return "SRP proof verification error";
+
+    case SRP_BAD_KEY_E:
+        return "SRP bad key values error";
+
     default:
         return "unknown error number";
 

+ 20 - 21
wolfcrypt/src/hmac.c

@@ -134,31 +134,31 @@ static int InitHmac(Hmac* hmac, int type)
             ret = wc_InitSha(&hmac->hash.sha);
         break;
         #endif
-        
+
         #ifndef NO_SHA256
         case SHA256:
             ret = wc_InitSha256(&hmac->hash.sha256);
         break;
         #endif
-        
+
         #ifdef WOLFSSL_SHA384
         case SHA384:
             ret = wc_InitSha384(&hmac->hash.sha384);
         break;
         #endif
-        
+
         #ifdef WOLFSSL_SHA512
         case SHA512:
             ret = wc_InitSha512(&hmac->hash.sha512);
         break;
         #endif
-        
-        #ifdef HAVE_BLAKE2 
+
+        #ifdef HAVE_BLAKE2
         case BLAKE2B_ID:
             ret = wc_InitBlake2b(&hmac->hash.blake2b, BLAKE2B_256);
         break;
         #endif
-        
+
         default:
             return BAD_FUNC_ARG;
     }
@@ -287,7 +287,7 @@ int wc_HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
         break;
         #endif
 
-        #ifdef HAVE_BLAKE2 
+        #ifdef HAVE_BLAKE2
         case BLAKE2B_ID:
         {
             hmac_block_size = BLAKE2B_BLOCKBYTES;
@@ -367,7 +367,7 @@ static int HmacKeyInnerHash(Hmac* hmac)
         break;
         #endif
 
-        #ifdef HAVE_BLAKE2 
+        #ifdef HAVE_BLAKE2
         case BLAKE2B_ID:
             ret = wc_Blake2bUpdate(&hmac->hash.blake2b,
                                          (byte*) hmac->ipad,BLAKE2B_BLOCKBYTES);
@@ -438,7 +438,7 @@ int wc_HmacUpdate(Hmac* hmac, const byte* msg, word32 length)
         break;
         #endif
 
-        #ifdef HAVE_BLAKE2 
+        #ifdef HAVE_BLAKE2
         case BLAKE2B_ID:
             ret = wc_Blake2bUpdate(&hmac->hash.blake2b, msg, length);
             if (ret != 0)
@@ -570,7 +570,7 @@ int wc_HmacFinal(Hmac* hmac, byte* hash)
         break;
         #endif
 
-        #ifdef HAVE_BLAKE2 
+        #ifdef HAVE_BLAKE2
         case BLAKE2B_ID:
         {
             ret = wc_Blake2bFinal(&hmac->hash.blake2b, (byte*) hmac->innerHash,
@@ -622,7 +622,7 @@ int wc_HmacInitCavium(Hmac* hmac, int devId)
     hmac->devId   = devId;
     hmac->magic   = WOLFSSL_HMAC_CAVIUM_MAGIC;
     hmac->data    = NULL;        /* buffered input data */
-   
+
     hmac->innerHashKeyed = 0;
 
     return 0;
@@ -650,7 +650,7 @@ static void HmacCaviumFinal(Hmac* hmac, byte* hash)
                 (byte*)hmac->ipad, hmac->dataLen, hmac->data, hash, &requestId,
                 hmac->devId) != 0) {
         WOLFSSL_MSG("Cavium Hmac failed");
-    } 
+    }
     hmac->innerHashKeyed = 0;  /* tell update to start over if used again */
 }
 
@@ -685,7 +685,7 @@ static void HmacCaviumUpdate(Hmac* hmac, const byte* msg, word32 length)
     if (hmac->dataLen)
         XMEMCPY(tmp, hmac->data,  hmac->dataLen);
     XMEMCPY(tmp + hmac->dataLen, msg, add);
-        
+
     hmac->dataLen += add;
     XFREE(hmac->data, NULL, DYNAMIC_TYPE_CAVIUM_TMP);
     hmac->data = tmp;
@@ -751,31 +751,31 @@ static INLINE int GetHashSizeByType(int type)
             return SHA_DIGEST_SIZE;
         break;
         #endif
-        
+
         #ifndef NO_SHA256
         case SHA256:
             return SHA256_DIGEST_SIZE;
         break;
         #endif
-        
+
         #ifdef WOLFSSL_SHA384
         case SHA384:
             return SHA384_DIGEST_SIZE;
         break;
         #endif
-        
+
         #ifdef WOLFSSL_SHA512
         case SHA512:
             return SHA512_DIGEST_SIZE;
         break;
         #endif
-        
-        #ifdef HAVE_BLAKE2 
+
+        #ifdef HAVE_BLAKE2
         case BLAKE2B_ID:
             return BLAKE2B_OUTBYTES;
         break;
         #endif
-        
+
         default:
             return BAD_FUNC_ARG;
         break;
@@ -824,7 +824,7 @@ int wc_HKDF(int type, const byte* inKey, word32 inKeySz,
         localSalt = tmp;
         saltSz    = hashSz;
     }
-    
+
     do {
     ret = wc_HmacSetKey(&myHmac, type, localSalt, saltSz);
     if (ret != 0)
@@ -876,4 +876,3 @@ int wc_HKDF(int type, const byte* inKey, word32 inKeySz,
 
 #endif /* HAVE_FIPS */
 #endif /* NO_HMAC */
-

+ 677 - 0
wolfcrypt/src/srp.c

@@ -0,0 +1,677 @@
+/* srp.c
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+    #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#ifdef WOLFCRYPT_HAVE_SRP
+
+#include <wolfssl/wolfcrypt/srp.h>
+#include <wolfssl/wolfcrypt/random.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+#ifdef NO_INLINE
+    #include <wolfssl/wolfcrypt/misc.h>
+#else
+    #include <wolfcrypt/src/misc.c>
+#endif
+
+/** Computes the session key using the Mask Generation Function 1. */
+static int wc_SrpSetKey(Srp* srp, byte* secret, word32 size);
+
+static int SrpHashInit(SrpHash* hash, SrpType type)
+{
+    hash->type = type;
+
+    switch (type) {
+    #ifndef NO_SHA
+        case SRP_TYPE_SHA:
+            return wc_InitSha(&hash->data.sha);
+    #endif
+
+    #ifndef NO_SHA256
+        case SRP_TYPE_SHA256:
+            return wc_InitSha256(&hash->data.sha256);
+    #endif
+
+    #ifdef WOLFSSL_SHA384
+        case SRP_TYPE_SHA384:
+            return wc_InitSha384(&hash->data.sha384);
+    #endif
+
+    #ifdef WOLFSSL_SHA512
+        case SRP_TYPE_SHA512:
+            return wc_InitSha512(&hash->data.sha512);
+    #endif
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+}
+
+static int SrpHashUpdate(SrpHash* hash, const byte* data, word32 size)
+{
+    switch (hash->type) {
+    #ifndef NO_SHA
+        case SRP_TYPE_SHA:
+            return wc_ShaUpdate(&hash->data.sha, data, size);
+    #endif
+
+    #ifndef NO_SHA256
+        case SRP_TYPE_SHA256:
+            return wc_Sha256Update(&hash->data.sha256, data, size);
+    #endif
+
+    #ifdef WOLFSSL_SHA384
+        case SRP_TYPE_SHA384:
+            return wc_Sha384Update(&hash->data.sha384, data, size);
+    #endif
+
+    #ifdef WOLFSSL_SHA512
+        case SRP_TYPE_SHA512:
+            return wc_Sha512Update(&hash->data.sha512, data, size);
+    #endif
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+}
+
+static int SrpHashFinal(SrpHash* hash, byte* digest)
+{
+    switch (hash->type) {
+    #ifndef NO_SHA
+        case SRP_TYPE_SHA:
+            return wc_ShaFinal(&hash->data.sha, digest);
+    #endif
+
+    #ifndef NO_SHA256
+        case SRP_TYPE_SHA256:
+            return wc_Sha256Final(&hash->data.sha256, digest);
+    #endif
+
+    #ifdef WOLFSSL_SHA384
+        case SRP_TYPE_SHA384:
+            return wc_Sha384Final(&hash->data.sha384, digest);
+    #endif
+
+    #ifdef WOLFSSL_SHA512
+        case SRP_TYPE_SHA512:
+            return wc_Sha512Final(&hash->data.sha512, digest);
+    #endif
+
+        default:
+            return BAD_FUNC_ARG;
+    }
+}
+
+static word32 SrpHashSize(SrpType type)
+{
+    switch (type) {
+    #ifndef NO_SHA
+        case SRP_TYPE_SHA:
+            return SHA_DIGEST_SIZE;
+    #endif
+
+    #ifndef NO_SHA256
+        case SRP_TYPE_SHA256:
+            return SHA256_DIGEST_SIZE;
+    #endif
+
+    #ifdef WOLFSSL_SHA384
+        case SRP_TYPE_SHA384:
+            return SHA384_DIGEST_SIZE;
+    #endif
+
+    #ifdef WOLFSSL_SHA512
+        case SRP_TYPE_SHA512:
+            return SHA512_DIGEST_SIZE;
+    #endif
+
+        default:
+            return 0;
+    }
+}
+
+int wc_SrpInit(Srp* srp, SrpType type, SrpSide side)
+{
+    int r;
+
+    /* validating params */
+
+    if (!srp)
+        return BAD_FUNC_ARG;
+
+    if (side != SRP_CLIENT_SIDE && side != SRP_SERVER_SIDE)
+        return BAD_FUNC_ARG;
+
+    if (type != SRP_TYPE_SHA    && type != SRP_TYPE_SHA256 &&
+        type != SRP_TYPE_SHA384 && type != SRP_TYPE_SHA512)
+        return BAD_FUNC_ARG;
+
+    /* initializing variables */
+
+    XMEMSET(srp, 0, sizeof(Srp));
+
+    if ((r = SrpHashInit(&srp->client_proof, type)) != 0)
+        return r;
+
+    if ((r = SrpHashInit(&srp->server_proof, type)) != 0)
+        return r;
+
+    if ((r = mp_init_multi(&srp->N,    &srp->g, &srp->auth,
+                           &srp->priv, 0, 0)) != 0)
+        return r;
+
+    srp->side = side;    srp->type   = type;
+    srp->salt = NULL;    srp->saltSz = 0;
+    srp->user = NULL;    srp->userSz = 0;
+    srp->key  = NULL;    srp->keySz  = 0;
+
+    srp->keyGenFunc_cb = wc_SrpSetKey;
+
+    return 0;
+}
+
+void wc_SrpTerm(Srp* srp)
+{
+    if (srp) {
+        mp_clear(&srp->N);    mp_clear(&srp->g);
+        mp_clear(&srp->auth); mp_clear(&srp->priv);
+
+        ForceZero(srp->salt, srp->saltSz);
+        XFREE(srp->salt, NULL, DYNAMIC_TYPE_SRP);
+        ForceZero(srp->user, srp->userSz);
+        XFREE(srp->user, NULL, DYNAMIC_TYPE_SRP);
+        ForceZero(srp->key, srp->keySz);
+        XFREE(srp->key, NULL, DYNAMIC_TYPE_SRP);
+
+        ForceZero(srp, sizeof(Srp));
+    }
+}
+
+int wc_SrpSetUsername(Srp* srp, const byte* username, word32 size)
+{
+    if (!srp || !username)
+        return BAD_FUNC_ARG;
+
+    srp->user = (byte*)XMALLOC(size, NULL, DYNAMIC_TYPE_SRP);
+    if (srp->user == NULL)
+        return MEMORY_E;
+
+    srp->userSz = size;
+    XMEMCPY(srp->user, username, srp->userSz);
+
+    return 0;
+}
+
+int wc_SrpSetParams(Srp* srp, const byte* N,    word32 nSz,
+                              const byte* g,    word32 gSz,
+                              const byte* salt, word32 saltSz)
+{
+    SrpHash hash;
+    byte digest1[SRP_MAX_DIGEST_SIZE];
+    byte digest2[SRP_MAX_DIGEST_SIZE];
+    byte pad = 0;
+    int i, j, r;
+
+    if (!srp || !N || !g || !salt || nSz < gSz)
+        return BAD_FUNC_ARG;
+
+    if (!srp->user)
+        return SRP_CALL_ORDER_E;
+
+    /* Set N */
+    if (mp_read_unsigned_bin(&srp->N, N, nSz) != MP_OKAY)
+        return MP_READ_E;
+
+    if (mp_count_bits(&srp->N) < SRP_DEFAULT_MIN_BITS)
+        return BAD_FUNC_ARG;
+
+    /* Set g */
+    if (mp_read_unsigned_bin(&srp->g, g, gSz) != MP_OKAY)
+        return MP_READ_E;
+
+    if (mp_cmp(&srp->N, &srp->g) != MP_GT)
+        return BAD_FUNC_ARG;
+
+    /* Set salt */
+    if (srp->salt) {
+        ForceZero(srp->salt, srp->saltSz);
+        XFREE(srp->salt, NULL, DYNAMIC_TYPE_SRP);
+    }
+
+    srp->salt = (byte*)XMALLOC(saltSz, NULL, DYNAMIC_TYPE_SRP);
+    if (srp->salt == NULL)
+        return MEMORY_E;
+
+    XMEMCPY(srp->salt, salt, saltSz);
+    srp->saltSz = saltSz;
+
+    /* Set k = H(N, g) */
+            r = SrpHashInit(&hash, srp->type);
+    if (!r) r = SrpHashUpdate(&hash, (byte*) N, nSz);
+    for (i = 0; (word32)i < nSz - gSz; i++)
+        SrpHashUpdate(&hash, &pad, 1);
+    if (!r) r = SrpHashUpdate(&hash, (byte*) g, gSz);
+    if (!r) r = SrpHashFinal(&hash, srp->k);
+
+    /* update client proof */
+
+    /* digest1 = H(N) */
+    if (!r) r = SrpHashInit(&hash, srp->type);
+    if (!r) r = SrpHashUpdate(&hash, (byte*) N, nSz);
+    if (!r) r = SrpHashFinal(&hash, digest1);
+
+    /* digest2 = H(g) */
+    if (!r) r = SrpHashInit(&hash, srp->type);
+    if (!r) r = SrpHashUpdate(&hash, (byte*) g, gSz);
+    if (!r) r = SrpHashFinal(&hash, digest2);
+
+    /* digest1 = H(N) ^ H(g) */
+    if (r == 0) {
+        for (i = 0, j = SrpHashSize(srp->type); i < j; i++)
+            digest1[i] ^= digest2[i];
+    }
+
+    /* digest2 = H(user) */
+    if (!r) r = SrpHashInit(&hash, srp->type);
+    if (!r) r = SrpHashUpdate(&hash, srp->user, srp->userSz);
+    if (!r) r = SrpHashFinal(&hash, digest2);
+
+    /* client proof = H( H(N) ^ H(g) | H(user) | salt) */
+    if (!r) r = SrpHashUpdate(&srp->client_proof, digest1, j);
+    if (!r) r = SrpHashUpdate(&srp->client_proof, digest2, j);
+    if (!r) r = SrpHashUpdate(&srp->client_proof, salt, saltSz);
+
+    return r;
+}
+
+int wc_SrpSetPassword(Srp* srp, const byte* password, word32 size)
+{
+    SrpHash hash;
+    byte digest[SRP_MAX_DIGEST_SIZE];
+    word32 digestSz;
+    int r;
+
+    if (!srp || !password || srp->side != SRP_CLIENT_SIDE)
+        return BAD_FUNC_ARG;
+
+    if (!srp->salt)
+        return SRP_CALL_ORDER_E;
+
+    digestSz = SrpHashSize(srp->type);
+
+    /* digest = H(username | ':' | password) */
+            r = SrpHashInit(&hash, srp->type);
+    if (!r) r = SrpHashUpdate(&hash, srp->user, srp->userSz);
+    if (!r) r = SrpHashUpdate(&hash, (const byte*) ":", 1);
+    if (!r) r = SrpHashUpdate(&hash, password, size);
+    if (!r) r = SrpHashFinal(&hash, digest);
+
+    /* digest = H(salt | H(username | ':' | password)) */
+    if (!r) r = SrpHashInit(&hash, srp->type);
+    if (!r) r = SrpHashUpdate(&hash, srp->salt, srp->saltSz);
+    if (!r) r = SrpHashUpdate(&hash, digest, digestSz);
+    if (!r) r = SrpHashFinal(&hash, digest);
+
+    /* Set x (private key) */
+    if (!r) r = mp_read_unsigned_bin(&srp->auth, digest, digestSz);
+
+    ForceZero(digest, SRP_MAX_DIGEST_SIZE);
+
+    return r;
+}
+
+int wc_SrpGetVerifier(Srp* srp, byte* verifier, word32* size)
+{
+    mp_int v;
+    int r;
+
+    if (!srp || !verifier || !size || srp->side != SRP_CLIENT_SIDE)
+        return BAD_FUNC_ARG;
+
+    if (mp_iszero(&srp->auth))
+        return SRP_CALL_ORDER_E;
+
+    r = mp_init(&v);
+    if (r != MP_OKAY)
+        return MP_INIT_E;
+
+    /* v = g ^ x % N */
+    if (!r) r = mp_exptmod(&srp->g, &srp->auth, &srp->N, &v);
+    if (!r) r = *size < (word32)mp_unsigned_bin_size(&v) ? BUFFER_E : MP_OKAY;
+    if (!r) r = mp_to_unsigned_bin(&v, verifier);
+    if (!r) *size = mp_unsigned_bin_size(&v);
+
+    mp_clear(&v);
+
+    return r;
+}
+
+int wc_SrpSetVerifier(Srp* srp, const byte* verifier, word32 size)
+{
+    if (!srp || !verifier || srp->side != SRP_SERVER_SIDE)
+        return BAD_FUNC_ARG;
+
+    return mp_read_unsigned_bin(&srp->auth, verifier, size);
+}
+
+int wc_SrpSetPrivate(Srp* srp, const byte* private, word32 size)
+{
+    mp_int p;
+    int r;
+
+    if (!srp || !private || !size)
+        return BAD_FUNC_ARG;
+
+    if (mp_iszero(&srp->auth))
+        return SRP_CALL_ORDER_E;
+
+    r = mp_init(&p);
+    if (r != MP_OKAY)
+        return MP_INIT_E;
+    if (!r) r = mp_read_unsigned_bin(&p, private, size);
+    if (!r) r = mp_mod(&p, &srp->N, &srp->priv);
+    if (!r) r = mp_iszero(&srp->priv) ? SRP_BAD_KEY_E : 0;
+
+    mp_clear(&p);
+
+    return r;
+}
+
+/** Generates random data using wolfcrypt RNG. */
+static int wc_SrpGenPrivate(Srp* srp, byte* private, word32 size)
+{
+    RNG rng;
+    int r = wc_InitRng(&rng);
+
+    if (!r) r = wc_RNG_GenerateBlock(&rng, private, size);
+    if (!r) r = wc_SrpSetPrivate(srp, private, size);
+    if (!r) wc_FreeRng(&rng);
+
+    return r;
+}
+
+int wc_SrpGetPublic(Srp* srp, byte* public, word32* size)
+{
+    mp_int pubkey;
+    word32 modulusSz;
+    int r;
+
+    if (!srp || !public || !size)
+        return BAD_FUNC_ARG;
+
+    if (mp_iszero(&srp->auth))
+        return SRP_CALL_ORDER_E;
+
+    modulusSz = mp_unsigned_bin_size(&srp->N);
+    if (*size < modulusSz)
+        return BUFFER_E;
+
+    r = mp_init(&pubkey);
+    if (r != MP_OKAY)
+        return MP_INIT_E;
+
+    /* priv = random() */
+    if (mp_iszero(&srp->priv))
+        r = wc_SrpGenPrivate(srp, public, modulusSz);
+
+    /* client side: A = g ^ a % N */
+    if (srp->side == SRP_CLIENT_SIDE) {
+        if (!r) r = mp_exptmod(&srp->g, &srp->priv, &srp->N, &pubkey);
+
+    /* server side: B = (k * v + (g ^ b % N)) % N */
+    } else {
+        mp_int i, j;
+
+        if (mp_init_multi(&i, &j, 0, 0, 0, 0) == MP_OKAY) {
+            if (!r) r = mp_read_unsigned_bin(&i, srp->k,SrpHashSize(srp->type));
+            if (!r) r = mp_iszero(&i) ? SRP_BAD_KEY_E : 0;
+            if (!r) r = mp_exptmod(&srp->g, &srp->priv, &srp->N, &pubkey);
+            if (!r) r = mp_mulmod(&i, &srp->auth, &srp->N, &j);
+            if (!r) r = mp_add(&j, &pubkey, &i);
+            if (!r) r = mp_mod(&i, &srp->N, &pubkey);
+
+            mp_clear(&i); mp_clear(&j);
+        }
+    }
+
+    /* extract public key to buffer */
+    XMEMSET(public, 0, modulusSz);
+    if (!r) r = mp_to_unsigned_bin(&pubkey, public);
+    if (!r) *size = mp_unsigned_bin_size(&pubkey);
+    mp_clear(&pubkey);
+
+    return r;
+}
+
+static int wc_SrpSetKey(Srp* srp, byte* secret, word32 size)
+{
+    SrpHash hash;
+    byte digest[SRP_MAX_DIGEST_SIZE];
+    word32 i, j, digestSz = SrpHashSize(srp->type);
+    byte counter[4];
+    int r = BAD_FUNC_ARG;
+
+    srp->key = (byte*)XMALLOC(2 * digestSz, NULL, DYNAMIC_TYPE_SRP);
+    if (srp->key == NULL)
+        return MEMORY_E;
+
+    srp->keySz = 2 * digestSz;
+
+    for (i = j = 0; j < srp->keySz; i++) {
+        counter[0] = (i >> 24) & 0xFF;
+        counter[1] = (i >> 16) & 0xFF;
+        counter[2] = (i >>  8) & 0xFF;
+        counter[3] =  i        & 0xFF;
+
+        r = SrpHashInit(&hash, srp->type);
+        if (!r) r = SrpHashUpdate(&hash, secret, size);
+        if (!r) r = SrpHashUpdate(&hash, counter, 4);
+
+        if(j + digestSz > srp->keySz) {
+            if (!r) r = SrpHashFinal(&hash, digest);
+            XMEMCPY(srp->key + j, digest, srp->keySz - j);
+            j = srp->keySz;
+        }
+        else {
+            if (!r) r = SrpHashFinal(&hash, srp->key + j);
+            j += digestSz;
+        }
+    }
+
+    ForceZero(digest, sizeof(digest));
+    ForceZero(&hash, sizeof(SrpHash));
+
+    return r;
+}
+
+int wc_SrpComputeKey(Srp* srp, byte* clientPubKey, word32 clientPubKeySz,
+                               byte* serverPubKey, word32 serverPubKeySz)
+{
+    SrpHash hash;
+    byte *secret;
+    byte digest[SRP_MAX_DIGEST_SIZE];
+    word32 i, secretSz, digestSz;
+    mp_int u, s, temp1, temp2;
+    byte pad = 0;
+    int r;
+
+    /* validating params */
+
+    if (!srp || !clientPubKey || clientPubKeySz == 0
+             || !serverPubKey || serverPubKeySz == 0)
+        return BAD_FUNC_ARG;
+
+    if (mp_iszero(&srp->priv))
+        return SRP_CALL_ORDER_E;
+
+    /* initializing variables */
+
+    if ((r = SrpHashInit(&hash, srp->type)) != 0)
+        return r;
+
+    digestSz = SrpHashSize(srp->type);
+    secretSz = mp_unsigned_bin_size(&srp->N);
+
+    if ((secret = (byte*)XMALLOC(secretSz, NULL, DYNAMIC_TYPE_SRP)) == NULL)
+        return MEMORY_E;
+
+    if ((r = mp_init_multi(&u, &s, &temp1, &temp2, 0, 0)) != MP_OKAY) {
+        XFREE(secret, NULL, DYNAMIC_TYPE_SRP);
+        return r;
+    }
+
+    /* building u (random scrambling parameeter) */
+
+    /* H(A) */
+    for (i = 0; !r && i < secretSz - clientPubKeySz; i++)
+        r = SrpHashUpdate(&hash, &pad, 1);
+    if (!r) r = SrpHashUpdate(&hash, clientPubKey, clientPubKeySz);
+
+    /* H(A | B) */
+    for (i = 0; !r && i < secretSz - serverPubKeySz; i++)
+        r = SrpHashUpdate(&hash, &pad, 1);
+    if (!r) r = SrpHashUpdate(&hash, serverPubKey, serverPubKeySz);
+
+    /* set u */
+    if (!r) r = SrpHashFinal(&hash, digest);
+    if (!r) r = mp_read_unsigned_bin(&u, digest, SrpHashSize(srp->type));
+
+    /* building s (secret) */
+
+    if (!r && srp->side == SRP_CLIENT_SIDE) {
+
+        /* temp1 = B - k * v; rejects k == 0, B == 0 and B >= N. */
+        r = mp_read_unsigned_bin(&temp1, srp->k, digestSz);
+        if (!r) r = mp_iszero(&temp1) ? SRP_BAD_KEY_E : 0;
+        if (!r) r = mp_exptmod(&srp->g, &srp->auth, &srp->N, &temp2);
+        if (!r) r = mp_mulmod(&temp1, &temp2, &srp->N, &s);
+        if (!r) r = mp_read_unsigned_bin(&temp2, serverPubKey, serverPubKeySz);
+        if (!r) r = mp_iszero(&temp2) ? SRP_BAD_KEY_E : 0;
+        if (!r) r = mp_cmp(&temp2, &srp->N) != MP_LT ? SRP_BAD_KEY_E : 0;
+        if (!r) r = mp_sub(&temp2, &s, &temp1);
+
+        /* temp2 = a + u * x */
+        if (!r) r = mp_mulmod(&u, &srp->auth, &srp->N, &s);
+        if (!r) r = mp_add(&srp->priv, &s, &temp2);
+
+        /* secret = temp1 ^ temp2 % N */
+        if (!r) r = mp_exptmod(&temp1, &temp2, &srp->N, &s);
+
+    } else if (!r && srp->side == SRP_SERVER_SIDE) {
+        /* temp1 = v ^ u % N */
+        r = mp_exptmod(&srp->auth, &u, &srp->N, &temp1);
+
+        /* temp2 = A * temp1 % N; rejects A == 0, A >= N */
+        if (!r) r = mp_read_unsigned_bin(&s, clientPubKey, clientPubKeySz);
+        if (!r) r = mp_iszero(&s) ? SRP_BAD_KEY_E : 0;
+        if (!r) r = mp_cmp(&s, &srp->N) != MP_LT ? SRP_BAD_KEY_E : 0;
+        if (!r) r = mp_mulmod(&s, &temp1, &srp->N, &temp2);
+
+        /* rejects A * v ^ u % N >= 1, A * v ^ u % N == -1 % N */
+        if (!r) r = mp_read_unsigned_bin(&temp1, (const byte*)"\001", 1);
+        if (!r) r = mp_cmp(&temp2, &temp1) != MP_GT ? SRP_BAD_KEY_E : 0;
+        if (!r) r = mp_sub(&srp->N, &temp1, &s);
+        if (!r) r = mp_cmp(&temp2, &s) == MP_EQ ? SRP_BAD_KEY_E : 0;
+
+        /* secret = temp2 * b % N */
+        if (!r) r = mp_exptmod(&temp2, &srp->priv, &srp->N, &s);
+    }
+
+    /* building session key from secret */
+
+    if (!r) r = mp_to_unsigned_bin(&s, secret);
+    if (!r) r = srp->keyGenFunc_cb(srp, secret, mp_unsigned_bin_size(&s));
+
+    /* updating client proof = H( H(N) ^ H(g) | H(user) | salt | A | B | K) */
+
+    if (!r) r = SrpHashUpdate(&srp->client_proof, clientPubKey, clientPubKeySz);
+    if (!r) r = SrpHashUpdate(&srp->client_proof, serverPubKey, serverPubKeySz);
+    if (!r) r = SrpHashUpdate(&srp->client_proof, srp->key,     srp->keySz);
+
+    /* updating server proof = H(A) */
+
+    if (!r) r = SrpHashUpdate(&srp->server_proof, clientPubKey, clientPubKeySz);
+
+    XFREE(secret, NULL, DYNAMIC_TYPE_SRP);
+    mp_clear(&u); mp_clear(&s); mp_clear(&temp1); mp_clear(&temp2);
+
+    return r;
+}
+
+int wc_SrpGetProof(Srp* srp, byte* proof, word32* size)
+{
+    int r;
+
+    if (!srp || !proof || !size)
+        return BAD_FUNC_ARG;
+
+    if (*size < SrpHashSize(srp->type))
+        return BUFFER_E;
+
+    if ((r = SrpHashFinal(srp->side == SRP_CLIENT_SIDE
+                          ? &srp->client_proof
+                          : &srp->server_proof, proof)) != 0)
+        return r;
+
+    *size = SrpHashSize(srp->type);
+
+    if (srp->side == SRP_CLIENT_SIDE) {
+        /* server proof = H( A | client proof | K) */
+        if (!r) r = SrpHashUpdate(&srp->server_proof, proof, *size);
+        if (!r) r = SrpHashUpdate(&srp->server_proof, srp->key, srp->keySz);
+    }
+
+    return r;
+}
+
+int wc_SrpVerifyPeersProof(Srp* srp, byte* proof, word32 size)
+{
+    byte digest[SRP_MAX_DIGEST_SIZE];
+    int r;
+
+    if (!srp || !proof)
+        return BAD_FUNC_ARG;
+
+    if (size != SrpHashSize(srp->type))
+        return BUFFER_E;
+
+    r = SrpHashFinal(srp->side == SRP_CLIENT_SIDE ? &srp->server_proof
+                                                  : &srp->client_proof, digest);
+
+    if (srp->side == SRP_SERVER_SIDE) {
+        /* server proof = H( A | client proof | K) */
+        if (!r) r = SrpHashUpdate(&srp->server_proof, proof, size);
+        if (!r) r = SrpHashUpdate(&srp->server_proof, srp->key, srp->keySz);
+    }
+
+    if (!r && XMEMCMP(proof, digest, size) != 0)
+        r = SRP_VERIFY_E;
+
+    return r;
+}
+
+#endif /* WOLFCRYPT_HAVE_SRP */

+ 104 - 0
wolfcrypt/test/test.c

@@ -53,6 +53,7 @@
 #include <wolfssl/wolfcrypt/hmac.h>
 #include <wolfssl/wolfcrypt/dh.h>
 #include <wolfssl/wolfcrypt/dsa.h>
+#include <wolfssl/wolfcrypt/srp.h>
 #include <wolfssl/wolfcrypt/hc128.h>
 #include <wolfssl/wolfcrypt/rabbit.h>
 #include <wolfssl/wolfcrypt/chacha.h>
@@ -179,6 +180,7 @@ int  camellia_test(void);
 int  rsa_test(void);
 int  dh_test(void);
 int  dsa_test(void);
+int  srp_test(void);
 int  random_test(void);
 int  pwdbased_test(void);
 int  ripemd_test(void);
@@ -500,6 +502,13 @@ int wolfcrypt_test(void* args)
         printf( "DSA      test passed!\n");
 #endif
 
+#ifdef WOLFCRYPT_HAVE_SRP
+    if ( (ret = srp_test()) != 0)
+        return err_sys("SRP      test failed!\n", ret);
+    else
+        printf( "SRP      test passed!\n");
+#endif
+
 #ifndef NO_PWDBASED
     if ( (ret = pwdbased_test()) != 0)
         return err_sys("PWDBASED test failed!\n", ret);
@@ -4541,6 +4550,101 @@ int dsa_test(void)
 
 #endif /* NO_DSA */
 
+#ifdef WOLFCRYPT_HAVE_SRP
+
+int srp_test(void)
+{
+    Srp cli, srv;
+    int r;
+
+    byte clientPubKey[80]; /* A */
+    byte serverPubKey[80]; /* B */
+    word32 clientPubKeySz = 80;
+    word32 serverPubKeySz = 80;
+    byte clientProof[SRP_MAX_DIGEST_SIZE]; /* M1 */
+    byte serverProof[SRP_MAX_DIGEST_SIZE]; /* M2 */
+    word32 clientProofSz = SRP_MAX_DIGEST_SIZE;
+    word32 serverProofSz = SRP_MAX_DIGEST_SIZE;
+
+    byte username[] = "user";
+    word32 usernameSz = 4;
+
+    byte password[] = "password";
+    word32 passwordSz = 8;
+
+    byte N[] = {
+        0xC9, 0x4D, 0x67, 0xEB, 0x5B, 0x1A, 0x23, 0x46, 0xE8, 0xAB, 0x42, 0x2F,
+        0xC6, 0xA0, 0xED, 0xAE, 0xDA, 0x8C, 0x7F, 0x89, 0x4C, 0x9E, 0xEE, 0xC4,
+        0x2F, 0x9E, 0xD2, 0x50, 0xFD, 0x7F, 0x00, 0x46, 0xE5, 0xAF, 0x2C, 0xF7,
+        0x3D, 0x6B, 0x2F, 0xA2, 0x6B, 0xB0, 0x80, 0x33, 0xDA, 0x4D, 0xE3, 0x22,
+        0xE1, 0x44, 0xE7, 0xA8, 0xE9, 0xB1, 0x2A, 0x0E, 0x46, 0x37, 0xF6, 0x37,
+        0x1F, 0x34, 0xA2, 0x07, 0x1C, 0x4B, 0x38, 0x36, 0xCB, 0xEE, 0xAB, 0x15,
+        0x03, 0x44, 0x60, 0xFA, 0xA7, 0xAD, 0xF4, 0x83
+    };
+
+    byte g[] = {
+        0x02
+    };
+
+    byte salt[] = {
+        0xB2, 0xE5, 0x8E, 0xCC, 0xD0, 0xCF, 0x9D, 0x10, 0x3A, 0x56
+    };
+
+    byte verifier[] = {
+        0x7C, 0xAB, 0x17, 0xFE, 0x54, 0x3E, 0x8C, 0x13, 0xF2, 0x3D, 0x21, 0xE7,
+        0xD2, 0xAF, 0xAF, 0xDB, 0xA1, 0x52, 0x69, 0x9D, 0x49, 0x01, 0x79, 0x91,
+        0xCF, 0xD1, 0x3F, 0xE5, 0x28, 0x72, 0xCA, 0xBE, 0x13, 0xD1, 0xC2, 0xDA,
+        0x65, 0x34, 0x55, 0x8F, 0x34, 0x0E, 0x05, 0xB8, 0xB4, 0x0F, 0x7F, 0x6B,
+        0xBB, 0xB0, 0x6B, 0x50, 0xD8, 0xB1, 0xCC, 0xB7, 0x81, 0xFE, 0xD4, 0x42,
+        0xF5, 0x11, 0xBC, 0x8A, 0x28, 0xEB, 0x50, 0xB3, 0x46, 0x08, 0xBA, 0x24,
+        0xA2, 0xFB, 0x7F, 0x2E, 0x0A, 0xA5, 0x33, 0xCC
+    };
+
+    /* client knows username and password.   */
+    /* server knows N, g, salt and verifier. */
+
+            r = wc_SrpInit(&cli, SRP_TYPE_SHA, SRP_CLIENT_SIDE);
+    if (!r) r = wc_SrpSetUsername(&cli, username, usernameSz);
+
+    /* client sends username to server */
+
+    if (!r) r = wc_SrpInit(&srv, SRP_TYPE_SHA, SRP_SERVER_SIDE);
+    if (!r) r = wc_SrpSetUsername(&srv, username, usernameSz);
+    if (!r) r = wc_SrpSetParams(&srv, N,    sizeof(N),
+                                      g,    sizeof(g),
+                                      salt, sizeof(salt));
+    if (!r) r = wc_SrpSetVerifier(&srv, verifier, sizeof(verifier));
+    if (!r) r = wc_SrpGetPublic(&srv, serverPubKey, &serverPubKeySz);
+
+    /* server sends N, g, salt and B to client */
+
+    if (!r) r = wc_SrpSetParams(&cli, N,    sizeof(N),
+                                      g,    sizeof(g),
+                                      salt, sizeof(salt));
+    if (!r) r = wc_SrpSetPassword(&cli, password, passwordSz);
+    if (!r) r = wc_SrpGetPublic(&cli, clientPubKey, &clientPubKeySz);
+    if (!r) r = wc_SrpComputeKey(&cli, clientPubKey, clientPubKeySz,
+                                       serverPubKey, serverPubKeySz);
+    if (!r) r = wc_SrpGetProof(&cli, clientProof, &clientProofSz);
+
+    /* client sends A and M1 to server */
+
+    if (!r) r = wc_SrpComputeKey(&srv, clientPubKey, clientPubKeySz,
+                                       serverPubKey, serverPubKeySz);
+    if (!r) r = wc_SrpVerifyPeersProof(&srv, clientProof, clientProofSz);
+    if (!r) r = wc_SrpGetProof(&srv, serverProof, &serverProofSz);
+
+    /* server sends M2 to client */
+
+    if (!r) r = wc_SrpVerifyPeersProof(&cli, serverProof, serverProofSz);
+
+    wc_SrpTerm(&cli);
+    wc_SrpTerm(&srv);
+
+    return r;
+}
+
+#endif /* WOLFCRYPT_HAVE_SRP */
 
 #ifdef OPENSSL_EXTRA
 

+ 4 - 2
wolfssl/wolfcrypt/error-crypt.h

@@ -151,6 +151,10 @@ enum {
     ECC_INF_E           = -215,  /* ECC point infinity error */
     ECC_PRIV_KEY_E      = -216,  /* ECC private key not valid error */
 
+    SRP_CALL_ORDER_E    = -217,  /* SRP function called in the wrong order. */
+    SRP_VERIFY_E        = -218,  /* SRP proof verification failed. */
+    SRP_BAD_KEY_E       = -219,  /* SRP bad ephemeral values. */
+
     MIN_CODE_E          = -300   /* errors -101 - -299 */
 };
 
@@ -163,5 +167,3 @@ WOLFSSL_API const char* wc_GetErrorString(int error);
     } /* extern "C" */
 #endif
 #endif /* WOLF_CRYPT_ERROR_H */
-
-

+ 1 - 1
wolfssl/wolfcrypt/include.am

@@ -46,6 +46,7 @@ nobase_include_HEADERS+= \
                          wolfssl/wolfcrypt/blake2-int.h \
                          wolfssl/wolfcrypt/blake2-impl.h \
                          wolfssl/wolfcrypt/tfm.h \
+                         wolfssl/wolfcrypt/srp.h \
                          wolfssl/wolfcrypt/types.h \
                          wolfssl/wolfcrypt/visibility.h \
                          wolfssl/wolfcrypt/logging.h \
@@ -57,4 +58,3 @@ noinst_HEADERS+= \
                          wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h \
                          wolfssl/wolfcrypt/port/ti/ti-hash.h \
                          wolfssl/wolfcrypt/port/ti/ti-ccm.h
-

+ 308 - 0
wolfssl/wolfcrypt/srp.h

@@ -0,0 +1,308 @@
+/* srp.h
+ *
+ * Copyright (C) 2006-2015 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL. (formerly known as CyaSSL)
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef WOLFCRYPT_HAVE_SRP
+
+#ifndef WOLFCRYPT_SRP_H
+#define WOLFCRYPT_SRP_H
+
+#include <wolfssl/wolfcrypt/types.h>
+#include <wolfssl/wolfcrypt/sha.h>
+#include <wolfssl/wolfcrypt/sha256.h>
+#include <wolfssl/wolfcrypt/sha512.h>
+#include <wolfssl/wolfcrypt/integer.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+/* Select the largest available hash for the buffer size. */
+#if defined(WOLFSSL_SHA512)
+    #define SRP_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
+#elif defined(WOLFSSL_SHA384)
+    #define SRP_MAX_DIGEST_SIZE SHA384_DIGEST_SIZE
+#elif !defined(NO_SHA256)
+    #define SRP_MAX_DIGEST_SIZE SHA256_DIGEST_SIZE
+#elif !defined(NO_SHA)
+    #define SRP_MAX_DIGEST_SIZE SHA_DIGEST_SIZE
+#else
+    #error "You have to have some kind of SHA hash if you want to use SRP."
+#endif
+
+/* Set the minimum number of bits acceptable in an SRP modulus */
+#define SRP_DEFAULT_MIN_BITS 512
+
+/**
+ * SRP side, client or server.
+ */
+typedef enum {
+    SRP_CLIENT_SIDE  = 0,
+    SRP_SERVER_SIDE  = 1,
+} SrpSide;
+
+/**
+ * SRP hash type, SHA[1|256|384|512].
+ */
+typedef enum {
+    #ifndef NO_SHA
+        SRP_TYPE_SHA    = 1,
+    #endif
+    #ifndef NO_SHA256
+        SRP_TYPE_SHA256 = 2,
+    #endif
+    #ifdef WOLFSSL_SHA384
+        SRP_TYPE_SHA384 = 3,
+    #endif
+    #ifdef WOLFSSL_SHA512
+        SRP_TYPE_SHA512 = 4,
+    #endif
+} SrpType;
+
+/**
+ * SRP hash struct.
+ */
+typedef struct {
+    byte type;
+    union {
+        #ifndef NO_SHA
+            Sha sha;
+        #endif
+        #ifndef NO_SHA256
+            Sha256 sha256;
+        #endif
+        #ifdef WOLFSSL_SHA384
+            Sha384 sha384;
+        #endif
+        #ifdef WOLFSSL_SHA512
+            Sha512 sha512;
+        #endif
+    } data;
+} SrpHash;
+
+typedef struct Srp {
+    SrpSide side;                   /**< Client or Server, @see SrpSide.      */
+    SrpType type;                   /**< Hash type, @see SrpType.             */
+    byte*   user;                   /**< Username, login.                     */
+    word32  userSz;                 /**< Username length.                     */
+    byte*   salt;                   /**< Small salt.                          */
+    word32  saltSz;                 /**< Salt length.                         */
+    mp_int  N;                      /**< Modulus. N = 2q+1, [q, N] are primes.*/
+    mp_int  g;                      /**< Generator. A generator modulo N.     */
+    byte    k[SRP_MAX_DIGEST_SIZE]; /**< Multiplier parameeter. k = H(N, g)   */
+    mp_int  auth;                   /**< Client: x = H(salt + H(user:pswd))   */
+                                    /**< Server: v = g ^ x % N                */
+    mp_int  priv;                   /**< Private ephemeral value.             */
+    SrpHash client_proof;           /**< Client proof. Sent to the Server.    */
+    SrpHash server_proof;           /**< Server proof. Sent to the Client.    */
+    byte*   key;                    /**< Session key.                         */
+    word32  keySz;                  /**< Session key length.                  */
+    int (*keyGenFunc_cb) (struct Srp* srp, byte* secret, word32 size);
+        /**< Function responsible for generating the session key.             */
+        /**< It MUST use XMALLOC with type DYNAMIC_TYPE_SRP to allocate the   */
+        /**< key buffer for this structure and set keySz to the buffer size.  */
+        /**< The default function used by this implementation is a modified   */
+        /**< version of t_mgf1 that uses the proper hash function according   */
+        /**< to srp->type.                                                    */
+} Srp;
+
+/**
+ * Initializes the Srp struct for usage.
+ *
+ * @param[out] srp   the Srp structure to be initialized.
+ * @param[in]  type  the hash type to be used.
+ * @param[in]  side  the side of the communication.
+ *
+ * @return 0 on success, {@literal <} 0 on error. @see error-crypt.h
+ */
+WOLFSSL_API int wc_SrpInit(Srp* srp, SrpType type, SrpSide side);
+
+/**
+ * Releases the Srp struct resources after usage.
+ *
+ * @param[in,out] srp    the Srp structure to be terminated.
+ */
+WOLFSSL_API void wc_SrpTerm(Srp* srp);
+
+/**
+ * Sets the username.
+ *
+ * This function MUST be called after wc_SrpInit.
+ *
+ * @param[in,out] srp       the Srp structure.
+ * @param[in]     username  the buffer containing the username.
+ * @param[in]     size      the username size in bytes
+ *
+ * @return 0 on success, {@literal <} 0 on error. @see error-crypt.h
+ */
+WOLFSSL_API int wc_SrpSetUsername(Srp* srp, const byte* username, word32 size);
+
+
+/**
+ * Sets the srp parameeters based on the username.
+ *
+ * This function MUST be called after wc_SrpSetUsername.
+ *
+ * @param[in,out] srp       the Srp structure.
+ * @param[in]     N         the Modulus. N = 2q+1, [q, N] are primes.
+ * @param[in]     nSz       the N size in bytes.
+ * @param[in]     g         the Generator modulo N.
+ * @param[in]     gSz       the g size in bytes
+ * @param[in]     salt      a small random salt. Specific for each username.
+ * @param[in]     saltSz    the salt size in bytes
+ *
+ * @return 0 on success, {@literal <} 0 on error. @see error-crypt.h
+ */
+WOLFSSL_API int wc_SrpSetParams(Srp* srp, const byte* N,    word32 nSz,
+                                          const byte* g,    word32 gSz,
+                                          const byte* salt, word32 saltSz);
+
+/**
+ * Sets the password.
+ *
+ * Setting the password does not persists the clear password data in the
+ * srp structure. The client calculates x = H(salt + H(user:pswd)) and stores
+ * it in the auth field.
+ *
+ * This function MUST be called after wc_SrpSetParams and is CLIENT SIDE ONLY.
+ *
+ * @param[in,out] srp       the Srp structure.
+ * @param[in]     password  the buffer containing the password.
+ * @param[in]     size      the password size in bytes.
+ *
+ * @return 0 on success, {@literal <} 0 on error. @see error-crypt.h
+ */
+WOLFSSL_API int wc_SrpSetPassword(Srp* srp, const byte* password, word32 size);
+
+/**
+ * Sets the password.
+ *
+ * This function MUST be called after wc_SrpSetParams and is SERVER SIDE ONLY.
+ *
+ * @param[in,out] srp       the Srp structure.
+ * @param[in]     verifier  the buffer containing the verifier.
+ * @param[in]     size      the verifier size in bytes.
+ *
+ * @return 0 on success, {@literal <} 0 on error. @see error-crypt.h
+ */
+WOLFSSL_API int wc_SrpSetVerifier(Srp* srp, const byte* verifier, word32 size);
+
+/**
+ * Gets the verifier.
+ *
+ * The client calculates the verifier with v = g ^ x % N.
+ * This function MAY be called after wc_SrpSetPassword and is SERVER SIDE ONLY.
+ *
+ * @param[in,out] srp       the Srp structure.
+ * @param[out]    verifier  the buffer to write the verifier.
+ * @param[in,out] size      the buffer size in bytes. Will be updated with the
+ *                          verifier size.
+ *
+ * @return 0 on success, {@literal <} 0 on error. @see error-crypt.h
+ */
+WOLFSSL_API int wc_SrpGetVerifier(Srp* srp, byte* verifier, word32* size);
+
+/**
+ * Sets the private ephemeral value.
+ *
+ * The private ephemeral value is known as:
+ *   a at the client side. a = random()
+ *   b at the server side. b = random()
+ * This function is handy for unit test cases or if the developer wants to use
+ * an external random source to set the ephemeral value.
+ * This function MAY be called before wc_SrpGetPublic.
+ *
+ * @param[in,out] srp       the Srp structure.
+ * @param[in]     private   the ephemeral value.
+ * @param[in]     size      the private size in bytes.
+ *
+ * @return 0 on success, {@literal <} 0 on error. @see error-crypt.h
+ */
+WOLFSSL_API int wc_SrpSetPrivate(Srp* srp, const byte* private, word32 size);
+
+/**
+ * Gets the public ephemeral value.
+ *
+ * The public ephemeral value is known as:
+ *   A at the client side. A = g ^ a % N
+ *   B at the server side. B = (k * v + (g ˆ b % N)) % N
+ * This function MUST be called after wc_SrpSetPassword or wc_SrpSetVerifier.
+ *
+ * @param[in,out] srp       the Srp structure.
+ * @param[out]    public    the buffer to write the public ephemeral value.
+ * @param[in,out] size      the the buffer size in bytes. Will be updated with
+ *                          the ephemeral value size.
+ *
+ * @return 0 on success, {@literal <} 0 on error. @see error-crypt.h
+ */
+WOLFSSL_API int wc_SrpGetPublic(Srp* srp, byte* public, word32* size);
+
+
+/**
+ * Computes the session key.
+ *
+ * This function is handy for unit test cases or if the developer wants to use
+ * an external random source to set the ephemeral value.
+ * This function MUST be called after wc_SrpSetPassword or wc_SrpSetVerifier.
+ *
+ * @param[in,out] srp       the Srp structure.
+ * @param[out]    public    the buffer to write the public ephemeral value.
+ * @param[in,out] size      the the buffer size in bytes. Will be updated with
+                            the ephemeral value size.
+ *
+ * @return 0 on success, {@literal <} 0 on error. @see error-crypt.h
+ */
+WOLFSSL_API int wc_SrpComputeKey(Srp* srp,
+                                 byte* clientPubKey, word32 clientPubKeySz,
+                                 byte* serverPubKey, word32 serverPubKeySz);
+
+/**
+ * Gets the proof.
+ *
+ * This function MUST be called after wc_SrpComputeKey.
+ *
+ * @param[in,out] srp   the Srp structure.
+ * @param[out]    proof the buffer to write the proof.
+ * @param[in,out] size  the buffer size in bytes. Will be updated with the
+ *                          proof size.
+ *
+ * @return 0 on success, {@literal <} 0 on error. @see error-crypt.h
+ */
+WOLFSSL_API int wc_SrpGetProof(Srp* srp, byte* proof, word32* size);
+
+/**
+ * Verifies the peers proof.
+ *
+ * This function MUST be called before wc_SrpGetSessionKey.
+ *
+ * @param[in,out] srp   the Srp structure.
+ * @param[in]     proof the peers proof.
+ * @param[in]     size  the proof size in bytes.
+ *
+ * @return 0 on success, {@literal <} 0 on error. @see error-crypt.h
+ */
+WOLFSSL_API int wc_SrpVerifyPeersProof(Srp* srp, byte* proof, word32 size);
+
+#ifdef __cplusplus
+   } /* extern "C" */
+#endif
+
+#endif /* WOLFCRYPT_SRP_H */
+#endif /* WOLFCRYPT_HAVE_SRP */

+ 2 - 1
wolfssl/wolfcrypt/types.h

@@ -271,7 +271,8 @@
 	    DYNAMIC_TYPE_TLSX         = 43,
 	    DYNAMIC_TYPE_OCSP         = 44,
 	    DYNAMIC_TYPE_SIGNATURE    = 45,
-	    DYNAMIC_TYPE_HASHES       = 46
+	    DYNAMIC_TYPE_HASHES       = 46,
+		DYNAMIC_TYPE_SRP          = 47,
 	};
 
 	/* max error buffer string size */