diff --git a/configure.ac b/configure.ac index bc15219aa..cb3cbaed3 100644 --- a/configure.ac +++ b/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 "---" - diff --git a/src/include.am b/src/include.am index b4ba39ddd..6c2629bc0 100644 --- a/src/include.am +++ b/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 - diff --git a/tests/include.am b/tests/include.am index f276f3af0..802ec5ad1 100644 --- a/tests/include.am +++ b/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) diff --git a/tests/srp.c b/tests/srp.c new file mode 100644 index 000000000..691bbdabe --- /dev/null +++ b/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 +#endif + +#include + +#include +#include +#include + +#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 +} diff --git a/tests/unit.c b/tests/unit.c index 73ae2bcd7..3a7f2452c 100644 --- a/tests/unit.c +++ b/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 } - diff --git a/tests/unit.h b/tests/unit.h index bccd6d2ce..1a038a21f 100644 --- a/tests/unit.h +++ b/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 */ - diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index 7d1d5ebe7..37b78422a 100644 --- a/wolfcrypt/src/error.c +++ b/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"; diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index 242adfa55..50716f5d9 100644 --- a/wolfcrypt/src/hmac.c +++ b/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 */ - diff --git a/wolfcrypt/src/srp.c b/wolfcrypt/src/srp.c new file mode 100644 index 000000000..7d9560911 --- /dev/null +++ b/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 +#endif + +#include + +#ifdef WOLFCRYPT_HAVE_SRP + +#include +#include +#include + +#ifdef NO_INLINE + #include +#else + #include +#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 */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index f85ee6373..b7888b0c2 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -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 diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index 79991fdf4..340d1db75 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/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 */ - - diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 67949fc28..8387ed7df 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/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 - diff --git a/wolfssl/wolfcrypt/srp.h b/wolfssl/wolfcrypt/srp.h new file mode 100644 index 000000000..3992a07ea --- /dev/null +++ b/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 +#include +#include +#include +#include + +#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 */ diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 3d379e216..0675af337 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/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 */