diff --git a/contrib/mbedtls/meson.build b/contrib/mbedtls/meson.build index 6819bab11bf9f33af4fcc9ca361698499f571132..06929f90b88dc71a7e3a23463b2a33bf9a989b25 100644 --- a/contrib/mbedtls/meson.build +++ b/contrib/mbedtls/meson.build @@ -12,6 +12,11 @@ if not builtin_mbedtls endif if mbedcrypto_lib.found() mbedcrypto_lib_found = true + mpi_random_test = ''' +#include <mbedtls/bignum.h> +void test_has_func() { mbedtls_mpi_random(NULL, 0, NULL, NULL, NULL); } +''' + cdata.set10('MBEDTLS_HAS_MPI_RANDOM', cc.compiles(mpi_random_test, name: 'MbedTLS has mbedtls_mpi_random()', dependencies: mbedcrypto_lib)) endif endif if builtin_mbedtls and not mbedcrypto_lib_found @@ -93,13 +98,9 @@ if builtin_mbedtls and not mbedcrypto_lib_found ) inc += mbedcrypto_lib_includes mbedcrypto_lib_found = true + cdata.set10('MBEDTLS_HAS_MPI_RANDOM', false) # We could compile libmbedcrypto.a using make on contrib/mbedtls and copy to the build folder instead #my_mbedcrypto_inc = mbedcrypto_lib_includes #my_mbedcrypto_lib = static_library('mbedcrypto') #mbedcrypto_lib = declare_dependency(link_with : my_mbedcrypto_lib, include_directories : my_mbedcrypto_inc) endif -if mbedcrypto_lib_found - deps += mbedcrypto_lib - platform_files += 'contrib/srp.c' - platform_files += 'src/eap.c' -endif \ No newline at end of file diff --git a/contrib/srp.c b/contrib/srp.c deleted file mode 100644 index fab531b09fd0fc398c6d526e81d01b7dde6186ef..0000000000000000000000000000000000000000 --- a/contrib/srp.c +++ /dev/null @@ -1,1208 +0,0 @@ -/* - * Secure Remote Password 6a implementation based on mbedtls. - * - * Copyright (c) 2017 Johannes Schriewer - * https://github.com/dunkelstern/mbedtls-csrp - * - * Copyright (c) 2015 Dieter Wimberger - * https://github.com/dwimberger/mbedtls-csrp - * - * Derived from: - * Copyright (c) 2010 Tom Cocagne. All rights reserved. - * https://github.com/cocagne/csrp - * - * The MIT License (MIT) - * - * Copyright (c) 2015 Tom Cocagne, Dieter Wimberger - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include <time.h> - -#include <stdlib.h> -#include <string.h> - -#include "mbedtls/bignum.h" -#include "mbedtls/entropy.h" -#include "mbedtls/ctr_drbg.h" -#include "mbedtls/sha1.h" -#include "mbedtls/sha256.h" -#include "mbedtls/sha512.h" - -#include "mbedtls/version.h" - -#if MBEDTLS_VERSION_NUMBER > 0x02070000 -#define USE_SHA_RET 1 -#else -#define USE_SHA_RET 0 -#endif - -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 -#include <mbedtls/compat-2.x.h> -#endif - - -#define DEBUG_EXTRACT_SRP_EXCHANGE 0 - -#include "srp.h" - -static int g_initialized = 0; -static mbedtls_entropy_context entropy_ctx; -static mbedtls_ctr_drbg_context ctr_drbg_ctx; -static mbedtls_mpi * RR; - -typedef struct -{ - BIGNUM *N; - BIGNUM *g; -} NGConstant; - -struct NGHex -{ - const char * n_hex; - const char * g_hex; -}; - -/* All constants here were pulled from Appendix A of RFC 5054 */ -static struct NGHex global_Ng_constants[] = { - { /* 512 */ - "D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B" - "1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3", - "2" - }, - { /* 768 */ - "B344C7C4F8C495031BB4E04FF8F84EE95008163940B9558276744D91F7CC9F402653BE7147F" - "00F576B93754BCDDF71B636F2099E6FFF90E79575F3D0DE694AFF737D9BE9713CEF8D837ADA" - "6380B1093E94B6A529A8C6C2BE33E0867C60C3262B", - "2" - }, - { /* 1024 */ - "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496" - "EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8E" - "F4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA" - "9AFD5138FE8376435B9FC61D2FC0EB06E3", - "2" - }, - { /* 2048 */ - "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4" - "A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60" - "95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF" - "747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B907" - "8717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB37861" - "60279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DB" - "FBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", - "2" - }, - { /* 4096 */ - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" - "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" - "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" - "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" - "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" - "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" - "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" - "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" - "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" - "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" - "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" - "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" - "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" - "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" - "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" - "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" - "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" - "FFFFFFFFFFFFFFFF", - "5" - }, - { /* 8192 */ - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" - "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" - "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" - "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" - "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" - "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" - "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" - "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" - "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" - "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" - "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" - "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" - "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" - "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" - "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" - "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" - "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" - "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" - "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" - "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" - "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" - "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" - "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" - "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" - "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" - "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" - "6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA" - "3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C" - "5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" - "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886" - "2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6" - "6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5" - "0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268" - "359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6" - "FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" - "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", - "13" - }, - {0,0} /* null sentinel */ -}; - - -static NGConstant * new_ng( SRP_NGType ng_type, const char * n_hex, const char * g_hex ) -{ - NGConstant * ng = (NGConstant *) malloc( sizeof(NGConstant) ); - ng->N = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - ng->g = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(ng->N); - mbedtls_mpi_init(ng->g); - - if( !ng || !ng->N || !ng->g ) - { - if (ng->N) - mbedtls_mpi_free(ng->N); - if (ng->g) - mbedtls_mpi_free(ng->g); - free(ng); - return 0; - } - - if ( ng_type != SRP_NG_CUSTOM ) - { - n_hex = global_Ng_constants[ ng_type ].n_hex; - g_hex = global_Ng_constants[ ng_type ].g_hex; - } - - mbedtls_mpi_read_string( ng->N, 16, n_hex); - mbedtls_mpi_read_string( ng->g, 16, g_hex); - - return ng; -} - -static void delete_ng( NGConstant * ng ) -{ - if (ng) - { - mbedtls_mpi_free( ng->N ); - mbedtls_mpi_free( ng->g ); - free(ng->N); - free(ng->g); - free(ng); - } -} - - -typedef union -{ - mbedtls_sha1_context sha; - mbedtls_sha256_context sha256; - mbedtls_sha512_context sha512; -} HashCTX; - -struct SRPSession -{ - SRP_HashAlgorithm hash_alg; - NGConstant *ng; -}; - -struct SRPVerifier -{ - SRP_HashAlgorithm hash_alg; - NGConstant *ng; - - const char * username; - const unsigned char * bytes_B; - int authenticated; - - unsigned char M [SHA512_DIGEST_LENGTH]; - unsigned char H_AMK [SHA512_DIGEST_LENGTH]; - unsigned char session_key [SHA512_DIGEST_LENGTH]; -}; - - -struct SRPUser -{ - SRP_HashAlgorithm hash_alg; - NGConstant *ng; - - BIGNUM *a; - BIGNUM *A; - BIGNUM *S; - - const unsigned char * bytes_A; - int authenticated; - - const char * username; - const unsigned char * password; - size_t password_len; - - unsigned char M [SHA512_DIGEST_LENGTH]; - unsigned char H_AMK [SHA512_DIGEST_LENGTH]; - unsigned char session_key [SHA512_DIGEST_LENGTH]; -}; - - -static void hash_init( SRP_HashAlgorithm alg, HashCTX *c ) -{ - switch (alg) - { - case SRP_SHA1 : - mbedtls_sha1_init( &c->sha ); - break; - case SRP_SHA256: - mbedtls_sha256_init( &c->sha256 ); - break; - case SRP_SHA512: - mbedtls_sha512_init( &c->sha512 ); - break; - default: - return; - }; -} - -/* -static void hash_start( SRP_HashAlgorithm alg, HashCTX *c ) -{ - switch (alg) - { - case SRP_SHA1 : mbedtls_sha1_starts( &c->sha ); - case SRP_SHA224: mbedtls_sha256_starts( &c->sha256, 1 ); - case SRP_SHA256: mbedtls_sha256_starts( &c->sha256, 0 ); - case SRP_SHA384: mbedtls_sha512_starts( &c->sha512, 1 ); - case SRP_SHA512: mbedtls_sha512_starts( &c->sha512, 0 ); - default: - return; - }; -}*/ - - -static int hash_update( SRP_HashAlgorithm alg, HashCTX *c, const void *data, size_t len ) -{ -#if !USE_SHA_RET - switch (alg) - { - case SRP_SHA1 : mbedtls_sha1_update( &c->sha, data, len ); break; - case SRP_SHA224: mbedtls_sha256_update( &c->sha256, data, len ); break; - case SRP_SHA256: mbedtls_sha256_update( &c->sha256, data, len ); break; - case SRP_SHA384: mbedtls_sha512_update( &c->sha512, data, len ); break; - case SRP_SHA512: mbedtls_sha512_update( &c->sha512, data, len ); break; - default: - return -1; - }; - return 0; -#else - switch (alg) - { - case SRP_SHA1: - return mbedtls_sha1_update_ret( &c->sha, data, len ); - case SRP_SHA224: - return mbedtls_sha256_update_ret( &c->sha256, data, len ); - case SRP_SHA256: - return mbedtls_sha256_update_ret( &c->sha256, data, len ); - case SRP_SHA384: - return mbedtls_sha512_update_ret( &c->sha512, data, len ); - case SRP_SHA512: - return mbedtls_sha512_update_ret( &c->sha512, data, len ); - default: - return -1; - }; -#endif -} -static int hash_final( SRP_HashAlgorithm alg, HashCTX *c, unsigned char *md ) -{ -#if !USE_SHA_RET - switch (alg) - { - case SRP_SHA1 : mbedtls_sha1_finish( &c->sha, md ); break; - case SRP_SHA224: mbedtls_sha256_finish( &c->sha256, md ); break; - case SRP_SHA256: mbedtls_sha256_finish( &c->sha256, md ); break; - case SRP_SHA384: mbedtls_sha512_finish( &c->sha512, md ); break; - case SRP_SHA512: mbedtls_sha512_finish( &c->sha512, md ); break; - default: - return -1; - }; - return 0; -#else - switch (alg) - { - case SRP_SHA1 : - return mbedtls_sha1_finish_ret( &c->sha, md ); - case SRP_SHA224: - return mbedtls_sha256_finish_ret( &c->sha256, md ); - case SRP_SHA256: - return mbedtls_sha256_finish_ret( &c->sha256, md ); - case SRP_SHA384: - return mbedtls_sha512_finish_ret( &c->sha512, md ); - case SRP_SHA512: - return mbedtls_sha512_finish_ret( &c->sha512, md ); - default: - return -1; - }; -#endif -} -static int hash( SRP_HashAlgorithm alg, const unsigned char *d, size_t n, unsigned char *md ) -{ -#if !USE_SHA_RET - switch (alg) - { - case SRP_SHA1 : mbedtls_sha1( d, n, md ); break; - case SRP_SHA224: mbedtls_sha256( d, n, md, 1); break; - case SRP_SHA256: mbedtls_sha256( d, n, md, 0); break; - case SRP_SHA384: mbedtls_sha512( d, n, md, 1 ); break; - case SRP_SHA512: mbedtls_sha512( d, n, md, 0 ); break; - default: - return -1; - }; - return 0; -#else - switch (alg) - { - case SRP_SHA1 : - return mbedtls_sha1_ret( d, n, md ); - case SRP_SHA224: - return mbedtls_sha256_ret( d, n, md, 1); - case SRP_SHA256: - return mbedtls_sha256_ret( d, n, md, 0); - case SRP_SHA384: - return mbedtls_sha512_ret( d, n, md, 1 ); - case SRP_SHA512: - return mbedtls_sha512_ret( d, n, md, 0 ); - default: - return -1; - }; -#endif -} -static int hash_length( SRP_HashAlgorithm alg ) -{ - switch (alg) - { - case SRP_SHA1 : return SHA1_DIGEST_LENGTH; - case SRP_SHA224: return SHA224_DIGEST_LENGTH; - case SRP_SHA256: return SHA256_DIGEST_LENGTH; - case SRP_SHA384: return SHA384_DIGEST_LENGTH; - case SRP_SHA512: return SHA512_DIGEST_LENGTH; - default: - return -1; - }; -} - - -static BIGNUM * H_nn( SRP_HashAlgorithm alg, const BIGNUM * n1, const BIGNUM * n2 ) -{ - unsigned char buff[ SHA512_DIGEST_LENGTH ]; - size_t len_n1 = mbedtls_mpi_size(n1); - size_t len_n2 = mbedtls_mpi_size(n2); - size_t nbytes = len_n1 + len_n2; - unsigned char * bin = (unsigned char *) malloc( nbytes ); - if (!bin) - return 0; - - mbedtls_mpi_write_binary( n1, bin, len_n1 ); - mbedtls_mpi_write_binary( n2, bin+len_n1, len_n2 ); - hash( alg, bin, nbytes, buff ); - free(bin); - BIGNUM * bn; - bn = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(bn); - mbedtls_mpi_read_binary( bn, buff, hash_length(alg) ); - return bn; -} - -static BIGNUM * H_ns( SRP_HashAlgorithm alg, const BIGNUM * n, const unsigned char * bytes, size_t len_bytes ) -{ - unsigned char buff[ SHA512_DIGEST_LENGTH ]; - size_t len_n = mbedtls_mpi_size(n); - size_t nbytes = len_n + len_bytes; - unsigned char * bin = (unsigned char *) malloc( nbytes ); - if (!bin) - return 0; - mbedtls_mpi_write_binary( n, bin, len_n ); - memcpy( bin + len_n, bytes, len_bytes ); - hash( alg, bin, nbytes, buff ); - free(bin); - - BIGNUM * bn; - bn = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(bn); - mbedtls_mpi_read_binary( bn, buff, hash_length(alg) ); - return bn; -} - -static BIGNUM * calculate_x( SRP_HashAlgorithm alg, const BIGNUM * salt, const char * username, const unsigned char * password, size_t password_len ) -{ - unsigned char ucp_hash[SHA512_DIGEST_LENGTH]; - HashCTX ctx; - - hash_init( alg, &ctx ); - - if (hash_update( alg, &ctx, username, strlen(username) ) != 0) - return NULL; - - if (hash_update( alg, &ctx, ":", 1 ) != 0) - return NULL; - - if (hash_update( alg, &ctx, password, password_len ) != 0) - return NULL; - - if (hash_final( alg, &ctx, ucp_hash ) != 0) - return NULL; - - return H_ns( alg, salt, ucp_hash, hash_length(alg) ); -} - -static void update_hash_n( SRP_HashAlgorithm alg, HashCTX *ctx, const BIGNUM * n ) -{ - unsigned long len = mbedtls_mpi_size(n); - unsigned char * n_bytes = (unsigned char *) malloc( len ); - if (!n_bytes) - return; - mbedtls_mpi_write_binary( n, n_bytes, len ); - hash_update(alg, ctx, n_bytes, len); - free(n_bytes); -} - -static void hash_num( SRP_HashAlgorithm alg, const BIGNUM * n, unsigned char * dest ) -{ - size_t nbytes = mbedtls_mpi_size(n); - unsigned char * bin = (unsigned char *) malloc( nbytes ); - if(!bin) - return; - mbedtls_mpi_write_binary( n, bin, nbytes ); - hash( alg, bin, nbytes, dest ); - free(bin); -} - -static void calculate_M( SRP_HashAlgorithm alg, NGConstant *ng, unsigned char * dest, const char * I, const BIGNUM * s, - const BIGNUM * A, const BIGNUM * B, const unsigned char * K ) -{ - unsigned char H_N[ SHA512_DIGEST_LENGTH ] = { '\0' }; - unsigned char H_g[ SHA512_DIGEST_LENGTH ] = { '\0' }; - unsigned char H_I[ SHA512_DIGEST_LENGTH ] = { '\0' }; - unsigned char H_xor[ SHA512_DIGEST_LENGTH ] = { '\0' }; - HashCTX ctx; - int i = 0; - int hash_len = hash_length(alg); - - hash_num( alg, ng->N, H_N ); - hash_num( alg, ng->g, H_g ); - - hash(alg, (const unsigned char *)I, strlen(I), H_I); - - - for (i=0; i < hash_len; i++ ) - H_xor[i] = H_N[i] ^ H_g[i]; - - hash_init( alg, &ctx ); - - hash_update( alg, &ctx, H_xor, hash_len ); - hash_update( alg, &ctx, H_I, hash_len ); - update_hash_n( alg, &ctx, s ); - update_hash_n( alg, &ctx, A ); - update_hash_n( alg, &ctx, B ); - hash_update( alg, &ctx, K, hash_len ); - - hash_final( alg, &ctx, dest ); -} - -static void calculate_H_AMK( SRP_HashAlgorithm alg, unsigned char *dest, const BIGNUM * A, const unsigned char * M, const unsigned char * K ) -{ - HashCTX ctx; - - hash_init( alg, &ctx ); - - update_hash_n( alg, &ctx, A ); - hash_update( alg, &ctx, M, hash_length(alg) ); - hash_update( alg, &ctx, K, hash_length(alg) ); - - hash_final( alg, &ctx, dest ); -} - - -static void init_random() -{ - if (g_initialized) - return; - - mbedtls_entropy_init( &entropy_ctx ); - mbedtls_ctr_drbg_init( &ctr_drbg_ctx ); - - unsigned char hotBits[128] = { - 82, 42, 71, 87, 124, 241, 30, 1, 54, 239, 240, 121, 89, 9, 151, 11, 60, - 226, 142, 47, 115, 157, 100, 126, 242, 132, 46, 12, 56, 197, 194, 76, - 198, 122, 90, 241, 255, 43, 120, 209, 69, 21, 195, 212, 100, 251, 18, - 111, 30, 238, 24, 199, 238, 236, 138, 225, 45, 15, 42, 83, 114, 132, - 165, 141, 32, 185, 167, 100, 131, 23, 236, 9, 11, 51, 130, 136, 97, 161, - 36, 174, 129, 234, 2, 54, 119, 184, 70, 103, 118, 109, 122, 15, 24, 23, - 166, 203, 102, 160, 77, 100, 17, 4, 132, 138, 215, 204, 109, 245, 122, - 9, 184, 89, 70, 247, 125, 97, 213, 240, 85, 243, 91, 226, 127, 64, 136, - 37, 154, 232 -}; - - mbedtls_ctr_drbg_seed( - &ctr_drbg_ctx, - mbedtls_entropy_func, - &entropy_ctx, - hotBits, - 128 - ); - - RR = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(RR); - g_initialized = 1; - -} - - -/*********************************************************************************************************** - * - * Exported Functions - * - ***********************************************************************************************************/ - -struct SRPSession * srp_session_new( SRP_HashAlgorithm alg, - SRP_NGType ng_type, - const char * n_hex, const char * g_hex) -{ - struct SRPSession * session; - - session = (struct SRPSession *)malloc(sizeof(struct SRPSession)); - memset(session, 0, sizeof(struct SRPSession)); - - session->hash_alg = alg; - session->ng = new_ng( ng_type, n_hex, g_hex ); - - return session; -} - -void srp_session_delete(struct SRPSession *session) -{ - delete_ng( session->ng ); - free(session); -} - - -void srp_random_seed( const unsigned char * random_data, size_t data_length ) -{ - g_initialized = 1; - - - if( mbedtls_ctr_drbg_seed( &ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx, - (const unsigned char *) random_data, - data_length ) != 0 ) - { - return; - } - -} - - -void srp_create_salted_verification_key( struct SRPSession *session, - const char * username, - const unsigned char * password, size_t len_password, - const unsigned char ** bytes_s, size_t * len_s, - const unsigned char ** bytes_v, size_t * len_v) -{ - - - BIGNUM * s; - BIGNUM * v; - BIGNUM * x = 0; - - s = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(s); - v = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(v); - - if( !session || !s || !v ) - goto cleanup_and_exit; - - init_random(); /* Only happens once */ - - mbedtls_mpi_fill_random( s, 32, - &mbedtls_ctr_drbg_random, - &ctr_drbg_ctx ); - - x = calculate_x( session->hash_alg, s, username, password, len_password ); - - if( !x ) - goto cleanup_and_exit; - - mbedtls_mpi_exp_mod(v, session->ng->g, x, session->ng->N, RR); - - *len_s = mbedtls_mpi_size(s); - *len_v = mbedtls_mpi_size(v); - - *bytes_s = (const unsigned char *) malloc( *len_s ); - *bytes_v = (const unsigned char *) malloc( *len_v ); - - if (!bytes_s || !bytes_v) - goto cleanup_and_exit; -#if DEBUG_EXTRACT_SRP_EXCHANGE - mbedtls_mpi_write_file("Salt:", s, 16, NULL); - mbedtls_mpi_write_file("Verifier:", v, 16, NULL); -#endif - mbedtls_mpi_write_binary( s, (unsigned char *)*bytes_s, *len_s ); - mbedtls_mpi_write_binary( v, (unsigned char *)*bytes_v, *len_v ); - - cleanup_and_exit: - mbedtls_mpi_free(s); - free(s); - mbedtls_mpi_free(v); - free(v); - mbedtls_mpi_free(x); - free(x); - //TODO: BN_CTX_free(ctx); -} - - - -/* Out: bytes_B, len_B. - * - * On failure, bytes_B will be set to NULL and len_B will be set to 0 - */ -struct SRPVerifier * srp_verifier_new( struct SRPSession *session, - const char *username, - const unsigned char * bytes_s, size_t len_s, - const unsigned char * bytes_v, size_t len_v, - const unsigned char * bytes_A, size_t len_A, - const unsigned char ** bytes_B, size_t * len_B) -{ - - BIGNUM *s; - s = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(s); - mbedtls_mpi_read_binary(s, bytes_s, len_s); - - BIGNUM *v; - v = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(v); - mbedtls_mpi_read_binary(v, bytes_v, len_v); - - BIGNUM *A; - A = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(A); - mbedtls_mpi_read_binary(A, bytes_A, len_A); - - BIGNUM *u = 0; - - BIGNUM *B; - B = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(B); - - BIGNUM *S; - S = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(S); - - BIGNUM *b; - b = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(b); - - BIGNUM *k = 0; - - BIGNUM *tmp1; - tmp1 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(tmp1); - - BIGNUM *tmp2; - tmp2 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(tmp2); - - size_t ulen = strlen(username) + 1; - - struct SRPVerifier *ver = 0; - ver = (struct SRPVerifier *) malloc( sizeof(struct SRPVerifier) ); - - *len_B = 0; - *bytes_B = 0; - - if( !session || !B || !S || !b || !tmp1 || !tmp2 || !ver ) { - goto cleanup_and_exit; - } - - init_random(); /* Only happens once */ - - ver->hash_alg = session->hash_alg; - ver->ng = session->ng; - - ver->username = (char *) malloc( ulen ); // FIXME - if (!ver->username) - { - free(ver); - ver = 0; - goto cleanup_and_exit; - } - memcpy( (char*)ver->username, username, ulen ); - - ver->authenticated = 0; - - /* SRP-6a safety check */ - mbedtls_mpi_mod_mpi( tmp1, A, session->ng->N ); - if ( mbedtls_mpi_cmp_int( tmp1, 0 ) != 0) - { - mbedtls_mpi_fill_random( b, 32, - &mbedtls_ctr_drbg_random, - &ctr_drbg_ctx ); - - k = H_nn(session->hash_alg, session->ng->N, session->ng->g); - - /* B = kv + g^b */ - mbedtls_mpi_mul_mpi( tmp1, k, v); - mbedtls_mpi_exp_mod( tmp2, session->ng->g, b, session->ng->N, RR ); - mbedtls_mpi_add_mpi( tmp1, tmp1, tmp2 ); - mbedtls_mpi_mod_mpi( B, tmp1, session->ng->N ); - - u = H_nn(session->hash_alg, A, B); - - /* S = (A *(v^u)) ^ b */ - mbedtls_mpi_exp_mod(tmp1, v, u, session->ng->N, RR); - mbedtls_mpi_mul_mpi(tmp2, A, tmp1); - mbedtls_mpi_exp_mod(S, tmp2, b, session->ng->N, RR); - - hash_num(session->hash_alg, S, ver->session_key); - - calculate_M( session->hash_alg, session->ng, ver->M, username, s, A, B, ver->session_key ); - calculate_H_AMK( session->hash_alg, ver->H_AMK, A, ver->M, ver->session_key ); - -#if DEBUG_EXTRACT_SRP_EXCHANGE - mbedtls_mpi_write_file("Server k:", k, 16, NULL); - mbedtls_mpi_write_file("Server b:", b, 16, NULL); - mbedtls_mpi_write_file("Server B:", B, 16, NULL); - mbedtls_mpi_write_file("Server u:", u, 16, NULL); - mbedtls_mpi_write_file("Server S:", S, 16, NULL); - fprintf(stderr, "Server K:"); - for (int i =0; i < SHA256_DIGEST_LENGTH; i++) { - fprintf(stderr, "%02X", ver->session_key[i]); - } - fprintf(stderr, "\n"); - fprintf(stderr, "Server M1:"); - for (int i =0; i < SHA256_DIGEST_LENGTH; i++) { - fprintf(stderr, "%02X", ver->M[i]); - } - fprintf(stderr, "\n"); - fprintf(stderr, "Server M2:"); - for (int i =0; i < SHA256_DIGEST_LENGTH; i++) { - fprintf(stderr, "%02X", ver->H_AMK[i]); - } - fprintf(stderr, "\n"); -#endif - - *len_B = mbedtls_mpi_size(B); - *bytes_B = malloc( *len_B ); - - if( !*bytes_B ) - { - free( (void*) ver->username ); - free( ver ); - ver = 0; - *len_B = 0; - goto cleanup_and_exit; - } - - mbedtls_mpi_write_binary( B, (unsigned char *)*bytes_B, *len_B ); - ver->bytes_B = *bytes_B; - } - - cleanup_and_exit: - mbedtls_mpi_free(s); - free(s); - mbedtls_mpi_free(v); - free(v); - mbedtls_mpi_free(A); - free(A); - if (u) {mbedtls_mpi_free(u); free(u);} - if (k) {mbedtls_mpi_free(k); free(k);} - mbedtls_mpi_free(B); - free(B); - mbedtls_mpi_free(S); - free(S); - mbedtls_mpi_free(b); - free(b); - mbedtls_mpi_free(tmp1); - free(tmp1); - mbedtls_mpi_free(tmp2); - free(tmp2); - - return ver; -} - - - - -void srp_verifier_delete( struct SRPVerifier * ver ) -{ - if (ver) - { - //delete_ng( ver->ng ); - free( (char *) ver->username ); - if(ver->bytes_B !=0) { - free( (unsigned char *) ver->bytes_B ); - } - memset(ver, 0, sizeof(*ver)); - free( ver ); - } -} - - - -int srp_verifier_is_authenticated( struct SRPVerifier * ver ) -{ - return ver->authenticated; -} - - -const char * srp_verifier_get_username( struct SRPVerifier * ver ) -{ - return ver->username; -} - - -const unsigned char * srp_verifier_get_session_key( struct SRPVerifier * ver, size_t * key_length ) -{ - if (key_length) - *key_length = hash_length( ver->hash_alg ); - return ver->session_key; -} - - -int srp_verifier_get_session_key_length( struct SRPVerifier * ver ) -{ - return hash_length( ver->hash_alg ); -} - - -/* user_M must be exactly SHA512_DIGEST_LENGTH bytes in size */ -void srp_verifier_verify_session( struct SRPVerifier * ver, const unsigned char * user_M, const unsigned char ** bytes_HAMK ) -{ - if ( memcmp( ver->M, user_M, hash_length(ver->hash_alg) ) == 0 ) - { - ver->authenticated = 1; - *bytes_HAMK = ver->H_AMK; - } - else - *bytes_HAMK = NULL; -} - -/*******************************************************************************/ - -struct SRPUser * srp_user_new( struct SRPSession *session, const char * username, - const unsigned char * bytes_password, size_t len_password) -{ - struct SRPUser *usr = (struct SRPUser *) calloc(1, sizeof(struct SRPUser) ); - size_t ulen = strlen(username) + 1; - - if (!usr) - goto err_exit; - - init_random(); /* Only happens once */ - - usr->hash_alg = session->hash_alg; - usr->ng = session->ng; - - usr->a = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - usr->A = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - usr->S = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - - mbedtls_mpi_init(usr->a); - mbedtls_mpi_init(usr->A); - mbedtls_mpi_init(usr->S); - - if (!usr->ng || !usr->a || !usr->A || !usr->S) - goto err_exit; - - usr->username = (const char *) malloc(ulen); - usr->password = (const unsigned char *) malloc(len_password); - usr->password_len = len_password; - - if (!usr->username || !usr->password) - goto err_exit; - - memcpy((char *)usr->username, username, ulen); - memcpy((char *)usr->password, bytes_password, len_password); - - usr->authenticated = 0; - - usr->bytes_A = 0; - - return usr; - - err_exit: - if (usr) - { - mbedtls_mpi_free(usr->a); - mbedtls_mpi_free(usr->A); - mbedtls_mpi_free(usr->S); - if (usr->username) - free((void*)usr->username); - if (usr->password) - { - memset((void*)usr->password, 0, usr->password_len); - free((void*)usr->password); - } - free(usr); - } - - return 0; -} - - - -void srp_user_delete( struct SRPUser * usr ) -{ - if( usr ) - { - mbedtls_mpi_free( usr->a ); - mbedtls_mpi_free( usr->A ); - mbedtls_mpi_free( usr->S ); - free(usr->a); - free(usr->A); - free(usr->S); - - //delete_ng( usr->ng ); - - memset((void*)usr->password, 0, usr->password_len); - - free((char *)usr->username); - free((char *)usr->password); - - if (usr->bytes_A) - free( (char *)usr->bytes_A ); - - memset(usr, 0, sizeof(*usr)); - free( usr ); - } -} - - - -int srp_user_is_authenticated( struct SRPUser * usr) -{ - return usr->authenticated; -} - - -const char * srp_user_get_username( struct SRPUser * usr ) -{ - return usr->username; -} - - - -const unsigned char * srp_user_get_session_key( struct SRPUser * usr, size_t * key_length ) -{ - if (key_length) - *key_length = hash_length( usr->hash_alg ); - return usr->session_key; -} - - -int srp_user_get_session_key_length( struct SRPUser * usr ) -{ - return hash_length( usr->hash_alg ); -} - - - -/* Output: username, bytes_A, len_A */ -void srp_user_start_authentication( struct SRPUser * usr, const char ** username, - const unsigned char ** bytes_A, size_t * len_A ) -{ - - mbedtls_mpi_fill_random( usr->a, 32, &mbedtls_ctr_drbg_random, &ctr_drbg_ctx); - mbedtls_mpi_exp_mod(usr->A, usr->ng->g, usr->a, usr->ng->N, RR); - -#if DEBUG_EXTRACT_SRP_EXCHANGE - mbedtls_mpi_write_file("User a:", usr->a, 16, NULL); - mbedtls_mpi_write_file("User A:", usr->A, 16, NULL); -#endif - - *len_A = mbedtls_mpi_size(usr->A); - *bytes_A = malloc( *len_A ); - - if (!*bytes_A) - { - *len_A = 0; - *bytes_A = 0; - *username = 0; - return; - } - - mbedtls_mpi_write_binary( usr->A, (unsigned char *) *bytes_A, *len_A ); - - usr->bytes_A = *bytes_A; - *username = usr->username; -} - - -/* Output: bytes_M. Buffer length is SHA512_DIGEST_LENGTH */ -void srp_user_process_challenge( struct SRPUser * usr, - const unsigned char * bytes_s, size_t len_s, - const unsigned char * bytes_B, size_t len_B, - const unsigned char ** bytes_M, size_t * len_M ) -{ - BIGNUM *u = 0; - BIGNUM *x = 0; - BIGNUM *k = 0; - - BIGNUM *s; - s = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(s); - mbedtls_mpi_read_binary(s, bytes_s, len_s); - - BIGNUM *B; - B = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(B); - mbedtls_mpi_read_binary(B, bytes_B, len_B); - - BIGNUM *v; - v = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(v); - - BIGNUM *tmp1; - tmp1 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(tmp1); - - BIGNUM *tmp2; - tmp2 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(tmp2); - - BIGNUM *tmp3; - tmp3 = (mbedtls_mpi *) malloc(sizeof(mbedtls_mpi)); - mbedtls_mpi_init(tmp3); - - *len_M = 0; - *bytes_M = 0; - - if( !s || !B || !v || !tmp1 || !tmp2 || !tmp3 ) - goto cleanup_and_exit; - - u = H_nn(usr->hash_alg, usr->A, B); - - if (!u) - goto cleanup_and_exit; - - x = calculate_x( usr->hash_alg, s, usr->username, usr->password, usr->password_len ); - - if (!x) - goto cleanup_and_exit; - - k = H_nn(usr->hash_alg, usr->ng->N, usr->ng->g); - -#if DEBUG_EXTRACT_SRP_EXCHANGE - mbedtls_mpi_write_file("User u:", u, 16, NULL); - mbedtls_mpi_write_file("User x:", x, 16, NULL); - mbedtls_mpi_write_file("User k:", k, 16, NULL); -#endif - - if (!k) - goto cleanup_and_exit; - - /* SRP-6a safety check */ - if( mbedtls_mpi_cmp_int( B, 0 ) != 0 && mbedtls_mpi_cmp_int( u, 0 ) !=0 ) - { - mbedtls_mpi_exp_mod(v, usr->ng->g, x, usr->ng->N, RR); - /* S = (B - k*(g^x)) ^ (a + ux) */ - mbedtls_mpi_mul_mpi( tmp1, u, x ); - mbedtls_mpi_mod_mpi( tmp1, tmp1, usr->ng->N); - mbedtls_mpi_add_mpi( tmp2, usr->a, tmp1); - mbedtls_mpi_mod_mpi( tmp2, tmp2, usr->ng->N); - /* tmp2 = (a + ux) */ - mbedtls_mpi_exp_mod( tmp1, usr->ng->g, x, usr->ng->N, RR); - mbedtls_mpi_mul_mpi( tmp3, k, tmp1 ); - mbedtls_mpi_mod_mpi( tmp3, tmp3, usr->ng->N); - /* tmp3 = k*(g^x) */ - mbedtls_mpi_sub_mpi(tmp1, B, tmp3); - /* tmp1 = (B - K*(g^x)) */ - mbedtls_mpi_exp_mod( usr->S, tmp1, tmp2, usr->ng->N, RR); - - hash_num(usr->hash_alg, usr->S, usr->session_key); - - calculate_M( usr->hash_alg, usr->ng, usr->M, usr->username, s, usr->A, B, usr->session_key ); - calculate_H_AMK( usr->hash_alg, usr->H_AMK, usr->A, usr->M, usr->session_key ); - -#if DEBUG_EXTRACT_SRP_EXCHANGE - mbedtls_mpi_write_file("User S:", usr->S, 16, NULL); - fprintf(stderr, "User K:"); - for (int i =0; i < SHA256_DIGEST_LENGTH; i++) { - fprintf(stderr, "%02X", usr->session_key[i]); - } - fprintf(stderr, "\n"); - fprintf(stderr, "User M1:"); - for (int i =0; i < SHA256_DIGEST_LENGTH; i++) { - fprintf(stderr, "%02X", usr->M[i]); - } - fprintf(stderr, "\n"); - fprintf(stderr, "User M2:"); - for (int i =0; i < SHA256_DIGEST_LENGTH; i++) { - fprintf(stderr, "%02X", usr->H_AMK[i]); - } - fprintf(stderr, "\n"); -#endif - - *bytes_M = usr->M; - if (len_M) { - *len_M = hash_length( usr->hash_alg ); - } - } - else - { - *bytes_M = NULL; - if (len_M) - *len_M = 0; - } - - cleanup_and_exit: - - mbedtls_mpi_free(s); - mbedtls_mpi_free(B); - mbedtls_mpi_free(u); - mbedtls_mpi_free(x); - mbedtls_mpi_free(k); - mbedtls_mpi_free(v); - mbedtls_mpi_free(tmp1); - mbedtls_mpi_free(tmp2); - mbedtls_mpi_free(tmp3); - free(s); - free(B); - free(u); - free(x); - free(k); - free(v); - free(tmp1); - free(tmp2); - free(tmp3); -} - - -void srp_user_verify_session( struct SRPUser * usr, const unsigned char * bytes_HAMK ) -{ - if ( memcmp( usr->H_AMK, bytes_HAMK, hash_length(usr->hash_alg) ) == 0 ) - usr->authenticated = 1; -} diff --git a/contrib/srp.h b/contrib/srp.h deleted file mode 100644 index fcfc0b875b22425380df2fd391079e7997928dba..0000000000000000000000000000000000000000 --- a/contrib/srp.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Secure Remote Password 6a implementation based on mbedtls. - * - * Copyright (c) 2017 Johannes Schriewer - * https://github.com/dunkelstern/mbedtls-csrp - * - * Copyright (c) 2015 Dieter Wimberger - * https://github.com/dwimberger/mbedtls-csrp - * - * Derived from: - * Copyright (c) 2010 Tom Cocagne. All rights reserved. - * https://github.com/cocagne/csrp - * - * The MIT License (MIT) - * - * Copyright (c) 2015 Tom Cocagne, Dieter Wimberger - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -/* - * - * Purpose: This is a direct implementation of the Secure Remote Password - * Protocol version 6a as described by - * http://srp.stanford.edu/design.html - * - * Author: tom.cocagne@gmail.com (Tom Cocagne), Dieter Wimberger - * - * Dependencies: mbedtls - * - * Usage: Refer to test_srp.c for a demonstration - * - * Notes: - * This library allows multiple combinations of hashing algorithms and - * prime number constants. For authentication to succeed, the hash and - * prime number constants must match between - * srp_create_salted_verification_key(), srp_user_new(), - * and srp_verifier_new(). A recommended approach is to determine the - * desired level of security for an application and globally define the - * hash and prime number constants to the predetermined values. - * - * As one might suspect, more bits means more security. As one might also - * suspect, more bits also means more processing time. The test_srp.c - * program can be easily modified to profile various combinations of - * hash & prime number pairings. - */ - -#ifdef __cplusplus -extern "C" { -#endif -#include <stddef.h> - -#ifndef SRP_H -#define SRP_H - -#define SHA1_DIGEST_LENGTH 20 -#define SHA224_DIGEST_LENGTH 28 -#define SHA256_DIGEST_LENGTH 32 -#define SHA384_DIGEST_LENGTH 48 -#define SHA512_DIGEST_LENGTH 64 -#define BIGNUM mbedtls_mpi - -struct SRPSession; -struct SRPVerifier; -struct SRPUser; - -typedef enum -{ - SRP_NG_512, - SRP_NG_768, - SRP_NG_1024, - SRP_NG_2048, - SRP_NG_4096, - SRP_NG_8192, - SRP_NG_CUSTOM -} SRP_NGType; - -typedef enum -{ - SRP_SHA1, - SRP_SHA224, - SRP_SHA256, - SRP_SHA384, - SRP_SHA512 -} SRP_HashAlgorithm; - -/* This library will automatically seed the mbedtls random number generator. - * - * The random data should include at least as many bits of entropy as the - * largest hash function used by the application. So, for example, if a - * 512-bit hash function is used, the random data requies at least 512 - * bits of entropy. - * - * Passing a null pointer to this function will cause this library to skip - * seeding the random number generator. - * - * Notes: - * * This function is optional on Windows & Linux and mandatory on all - * other platforms. - */ -void srp_random_seed( const unsigned char * random_data, size_t data_length ); - - -/* - * The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type. - * If provided, they must contain ASCII text of the hexidecimal notation. - */ -struct SRPSession * srp_session_new( SRP_HashAlgorithm alg, - SRP_NGType ng_type, - const char * n_hex, const char * g_hex); - -void srp_session_delete(struct SRPSession *session); - -/* Out: bytes_s, len_s, bytes_v, len_v - * - * The caller is responsible for freeing the memory allocated for bytes_s and bytes_v - */ -void srp_create_salted_verification_key( struct SRPSession * session, - const char * username, - const unsigned char * password, size_t len_password, - const unsigned char ** bytes_s, size_t * len_s, - const unsigned char ** bytes_v, size_t * len_v); - - -/* Out: bytes_B, len_B. - * - * On failure, bytes_B will be set to NULL and len_B will be set to 0 - */ -struct SRPVerifier * srp_verifier_new( struct SRPSession * session, - const char * username, - const unsigned char * bytes_s, size_t len_s, - const unsigned char * bytes_v, size_t len_v, - const unsigned char * bytes_A, size_t len_A, - const unsigned char ** bytes_B, size_t * len_B); - - -void srp_verifier_delete( struct SRPVerifier * ver ); - - -int srp_verifier_is_authenticated( struct SRPVerifier * ver ); - - -const char * srp_verifier_get_username( struct SRPVerifier * ver ); - -/* key_length may be null */ -const unsigned char * srp_verifier_get_session_key( struct SRPVerifier * ver, size_t * key_length ); - - -int srp_verifier_get_session_key_length( struct SRPVerifier * ver ); - - -/* user_M must be exactly srp_verifier_get_session_key_length() bytes in size */ -void srp_verifier_verify_session( struct SRPVerifier * ver, - const unsigned char * user_M, - const unsigned char ** bytes_HAMK ); - -/*******************************************************************************/ - -/* The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type */ -struct SRPUser * srp_user_new( struct SRPSession *session, - const char * username, - const unsigned char * bytes_password, size_t len_password); - -void srp_user_delete( struct SRPUser * usr ); - -int srp_user_is_authenticated( struct SRPUser * usr); - - -const char * srp_user_get_username( struct SRPUser * usr ); - -/* key_length may be null */ -const unsigned char * srp_user_get_session_key( struct SRPUser * usr, size_t * key_length ); - -int srp_user_get_session_key_length( struct SRPUser * usr ); - -/* Output: username, bytes_A, len_A */ -void srp_user_start_authentication( struct SRPUser * usr, const char ** username, - const unsigned char ** bytes_A, size_t * len_A ); - -/* Output: bytes_M, len_M (len_M may be null and will always be - * srp_user_get_session_key_length() bytes in size) */ -void srp_user_process_challenge( struct SRPUser * usr, - const unsigned char * bytes_s, size_t len_s, - const unsigned char * bytes_B, size_t len_B, - const unsigned char ** bytes_M, size_t * len_M ); - -/* bytes_HAMK must be exactly srp_user_get_session_key_length() bytes in size */ -void srp_user_verify_session( struct SRPUser * usr, const unsigned char * bytes_HAMK ); - -#endif /* Include Guard */ -#ifdef __cplusplus -} -#endif diff --git a/include/librist/config.h.in b/include/librist/config.h.in index 7a288f92244ae9671eca11123dd50d54eb4d989a..feb270a06396a76c17def06a1ff5b83cfaa4947a 100644 --- a/include/librist/config.h.in +++ b/include/librist/config.h.in @@ -8,8 +8,6 @@ #ifndef LIBRIST_CONFIG_H #define LIBRIST_CONFIG_H -#define HAVE_MBEDTLS @HAVE_MBEDTLS@ - -#define HAVE_NETTLE @HAVE_NETTLE@ +#define HAVE_SRP_SUPPORT @HAVE_SRP_SUPPORT@ #endif /* LIBRIST_CONFIG_H */ diff --git a/include/librist/librist_srp.h b/include/librist/librist_srp.h index 49d015cb13524ba727602914de1f08e29c37604c..2091e83c410797c419194cd2f4872adf643c83ca 100644 --- a/include/librist/librist_srp.h +++ b/include/librist/librist_srp.h @@ -9,10 +9,11 @@ #ifndef _LIBRIST_SRP_H_ #define _LIBRIST_SRP_H_ #include "librist_config.h" -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT #include "librist.h" -#include <stddef.h> #include <stdbool.h> +#include <stddef.h> +#include <stdint.h> #ifdef __cplusplus extern "C" { @@ -47,6 +48,56 @@ typedef void (*user_verifier_lookup_t)(char * username, char **generator_ascii, void *user_data); +/** + * @brief SRP User lookup function + * + * The SRP User lookup function is called inside the process of authentication + * the calling application MUST implement this function if it desires to so run + * as a RIST MAIN profile server with SRP authentication enabled. + * Userlookup is assumed to have been successful if both verifier params and both salt + * params are set by the lookup function. + * If the verifier function sets a non-zero generation number libRIST will periodically + * poll it to see if salt/verifier has changed, it will do this with verifier_len, verifier, + * salt_len, etc. set to NULL. On changes it will request the client to re-authenticate + * itself. If the libRIST supplied generation number is non-zero AND the generation number + * is left unchanged NO data must be set on the other variables. + * Leave generation number at 0 to keep the old behaviour of unconditionally periodically + * reauthenticating clients. + * libRIST will take ownership of all heap allocated data. + * + * @bug Previous releases of libRIST had an error in combined hashing of multiple data + sources. The error produced reproducable hashes that are not matching with + correctly hashed data. This reflects in the SRP file and also results in + incompatibilty with the newly created nettle+gmp crypto backend. + To ensure compatibilty with previous libRIST releases it's recommended to have + both old and new verifier/salt pairs availabe and in the lookup function return + the maximum requested version. Where 0 is the legacy compatible version and 1 + is the new correct version. + Compatibility with the broken hashing will be removed in a future release. + * + * @param username IN the username attempting authentication + * @param verifier_len OUT len in bytes of the verifier. + * @param verifier OUT verifier bytes, MUST be heap allocated. + * @param salt_len OUT salt len in bytes of the salt. + * @param salt OUT salt bytes, MUST be heap allocated. + * @param use_default_2048_bit_n_modulus OUT Use the default 2048 bit modulus, when true N Prime modulus & generator MUST be NULL. + * @param n_modulus_ascii OUT N Prime modulus in hex as a zero terminated C string, MUST be heap allocated or NULL. + * @param generator_ascii OUT Generator in hex as a zero terminated C string, MUST be heap allocated or NULL. + * @param hashversion IN/OUT IN: the maximum supported hashversion that should be looked up. OUT: the hashversion of the found salt/verifier pair. + * @param generation IN/OUT IN: generation number the library has cached for the requested user. OUT: generation number of the returned data. + * @param user_data IN pointer to user data. + * + **/ +typedef void (*user_verifier_lookup_2_t)(char * username, + size_t *verifier_len, char **verifier, + size_t *salt_len, char **salt, + bool *use_default_2048_bit_n_modulus, + char **n_modulus_ascii, + char **generator_ascii, + int *hashversion, + uint64_t *generation, + void *user_data); + /** * @brief Enable SRP authentication * @@ -61,7 +112,8 @@ typedef void (*user_verifier_lookup_t)(char * username, * @param userdata IN optional user data to be supplied to lookup function. * **/ -RIST_API int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_t lookup_func, void *userdata); +RIST_API RIST_DEPRECATED int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_t lookup_func, void *userdata); +RIST_API int rist_enable_eap_srp_2(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_2_t lookup_func, void *userdata); #ifdef __cplusplus } diff --git a/include/librist/meson.build b/include/librist/meson.build index 159528280925a4b1aa96e2ca61c3e803844856b6..596c2e76bf915a3834d8d93e63dd41fb47bc291e 100644 --- a/include/librist/meson.build +++ b/include/librist/meson.build @@ -16,8 +16,7 @@ version_h_target = configure_file(input: 'version.h.in', configuration: version_h_data) config_h_data = configuration_data() -config_h_data.set10('HAVE_MBEDTLS', mbedcrypto_lib_found) -config_h_data.set10('HAVE_NETTLE', use_nettle) +config_h_data.set10('HAVE_SRP_SUPPORT', mbedcrypto_lib_found or use_nettle) config_h_target = configure_file(input: 'config.h.in', output: 'librist_config.h', configuration: config_h_data) diff --git a/meson.build b/meson.build index a921e1f82a5fbc87736b7bd121b55250d67bb3a3..ed573ae6f843d41c2a89e3b9c2a4d4b6d8ac182d 100755 --- a/meson.build +++ b/meson.build @@ -37,7 +37,6 @@ librist_src_root = meson.current_source_dir() deps = [] platform_files = [] -contrib_libs = [] inc = [] inc += include_directories('.', 'src', 'include/librist', 'include', 'contrib') @@ -200,13 +199,28 @@ if get_option('use_tun') endif endif +crypto_deps = [] + mbedcrypto_lib_found = false if use_mbedtls message('Building mbedtls') subdir('contrib/mbedtls') + + crypto_deps += mbedcrypto_lib elif use_nettle - deps += dependency('nettle') + crypto_deps = [dependency('nettle'), dependency('hogweed')] + test_mini_gmp = ''' +#include <nettle/bignum.h> +#if !NETTLE_USE_MINI_GMP + #error "Need to link gmp" +#endif +''' + if not cc.compiles(test_mini_gmp, name: 'Nettle with mini-gmp?', dependencies: crypto_deps) + crypto_deps += dependency('gmp') + endif + crypto_deps += dependency('gnutls')#Just for random numbers at the moment :/ endif +deps += crypto_deps subdir('include') @@ -234,6 +248,19 @@ if not mbedcrypto_lib_found and not use_nettle ] endif +have_srp = mbedcrypto_lib_found or use_nettle + +if have_srp + platform_files += 'src/eap.c' + platform_files += 'src/crypto/srp_constants.c' + platform_files += 'src/crypto/srp.c' +endif + +cdata.set10('HAVE_MBEDTLS', mbedcrypto_lib_found) +cdata.set10('HAVE_NETTLE', use_nettle and not mbedcrypto_lib_found) +# Generate config.h +config_file = configure_file(output: 'config.h', configuration: cdata) + librist = library('librist', 'src/crypto/crypto.c', 'src/crypto/psk.c', @@ -251,6 +278,7 @@ librist = library('librist', 'contrib/stdio-shim.c', 'contrib/time-shim.c', 'contrib/pthread-shim.c', + config_file, platform_files, rev_target, include_directories: inc, @@ -310,9 +338,6 @@ endif librist_dep = declare_dependency(include_directories: inc, link_with : librist) -# Generate config.h -config_h_target = configure_file(output: 'config.h', configuration: cdata) - if get_option('built_tools') message('Building tools') subdir('tools') diff --git a/src/crypto/psk.c b/src/crypto/psk.c index 97b994d35b563f9eac1b40524dd0c9461bcc0ecd..6443fbfd0196682d10f59391a062ff5d555bd768 100644 --- a/src/crypto/psk.c +++ b/src/crypto/psk.c @@ -5,9 +5,11 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include "config.h" #include "psk.h" #include "log-private.h" #include "crypto-private.h" +#include <string.h> #if HAVE_MBEDTLS #include "mbedtls/aes.h" @@ -215,3 +217,15 @@ void _librist_crypto_psk_encrypt(struct rist_key *key, uint32_t seq_nbe, uint8_t _librist_crypto_psk_aes_ctr(key, seq_nbe, gre_version, inbuf, outbuf, payload_len); return; } + +int _librist_crypto_psk_set_passphrase(struct rist_key *key, char *passsphrase, size_t passphrase_len) { + if (passphrase_len > sizeof(key->password) -1) { + return -1; + } + memcpy(key->password, passsphrase, passphrase_len); + do { + key->gre_nonce = prand_u32(); + } while (!key->gre_nonce); + _librist_crypto_aes_key(key); + return 0; +} diff --git a/src/crypto/psk.h b/src/crypto/psk.h index 0452cecc45f97e7a0aea80c23baeda4bbc2ba6b3..4aed1f3533814c1907339bc45923520aece2f7e7 100644 --- a/src/crypto/psk.h +++ b/src/crypto/psk.h @@ -8,6 +8,7 @@ #ifndef RIST_CRYPTO_PSK_H #define RIST_CRYPTO_PSK_H +#include "config.h" #include "common/attributes.h" #include "librist/librist_config.h" #if HAVE_MBEDTLS @@ -46,6 +47,6 @@ RIST_PRIV int _librist_crypto_psk_rist_key_destroy(struct rist_key *key); RIST_PRIV int _librist_crypto_psk_rist_key_clone(struct rist_key *key_in, struct rist_key *key_out); RIST_PRIV void _librist_crypto_psk_decrypt(struct rist_key *key, uint32_t nonce, uint32_t seq_nbe, uint8_t gre_version,const uint8_t inbuf[], uint8_t outbuf[], size_t payload_len); RIST_PRIV void _librist_crypto_psk_encrypt(struct rist_key *key, uint32_t seq_nbe, uint8_t gre_version,const uint8_t inbuf[],uint8_t outbuf[], size_t payload_len); - +RIST_PRIV int _librist_crypto_psk_set_passphrase(struct rist_key *key, char *passsphrase, size_t passphrase_len); #endif diff --git a/src/crypto/srp.c b/src/crypto/srp.c new file mode 100644 index 0000000000000000000000000000000000000000..704ff0ba5acc4eb7d91522a6b6a550259543fde6 --- /dev/null +++ b/src/crypto/srp.c @@ -0,0 +1,992 @@ +#include "srp.h" + +#include "config.h" +#include "crypto/srp_constants.h" +#include "vcs_version.h" +#include "pthread-shim.h" + +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> + +#define DEBUG_EXTRACT_SRP_EXCHANGE 0 +#ifndef DEBUG_USE_EXAMPLE_CONSTANTS +#define DEBUG_USE_EXAMPLE_CONSTANTS 0 +#endif + +#if DEBUG_EXTRACT_SRP_EXCHANGE +static void print_hash(const uint8_t *buf, char *specifier) { + char outbuf[SHA256_DIGEST_LENGTH*2 +1]; + size_t j; + for (j = 0; j < SHA256_DIGEST_LENGTH; j++) { + outbuf[2 * j] = (buf[j] >> 4) + 48; + outbuf[2 * j + 1] = (buf[j] & 15) + 48; + if (outbuf[2 * j] > 57) + outbuf[2 * j] += 7; + if (outbuf[2 * j + 1] > 57) + outbuf[2 * j + 1] += 7; + } + outbuf[2 * j] = '\0'; + + fprintf(stderr, "%s%s\n", specifier, outbuf); +} +#endif + +#if !defined(_WIN32) || HAVE_PTHREADS +static pthread_once_t entropy_init_once = PTHREAD_ONCE_INIT; +#endif +#if defined(_WIN32) && !HAVE_PTHREADS +static INIT_ONCE entropy_init_once = INIT_ONCE_STATIC_INIT; +#endif + +#if HAVE_MBEDTLS +#include <mbedtls/bignum.h> +#include <mbedtls/entropy.h> +#include <mbedtls/ctr_drbg.h> +#include <mbedtls/sha256.h> +#include <mbedtls/version.h> + +#if MBEDTLS_VERSION_NUMBER > 0x02070000 +#define USE_SHA_RET 1 +#else +#define USE_SHA_RET 0 +#endif + +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 +#include <mbedtls/compat-2.x.h> +#endif + +#define BIGNUM mbedtls_mpi +#define BIGNUM_INIT(num) mbedtls_mpi_init(num) +#define BIGNUM_FREE(num) mbedtls_mpi_free(num) +#define BIGNUM_GET_BINARY_SIZE(num) mbedtls_mpi_size(num) +#define BIGNUM_FROM_ARRAY(num, array, size) ret = mbedtls_mpi_read_binary(num, array, size) +#define BIGNUM_FROM_STRING(num, str) ret = mbedtls_mpi_read_string(num, 16, str) +#if MBEDTLS_HAS_MPI_RANDOM +#define BIGNUM_RANDOM(num, max) ret = mbedtls_mpi_random(num, 0, max, mbedtls_ctr_drbg_random, &ctr_drbg_ctx); +#else +#define BIGNUM_RANDOM(num, max) ret = mbedtls_mpi_fill_random(num, 32, mbedtls_ctr_drbg_random, &ctr_drbg_ctx); +#endif +#define BIGNUM_MOD_RED(out, a, b) ret = mbedtls_mpi_mod_mpi(out, a, b) +#define BIGNUM_EXP_MOD(out, base, exp, mod) ret = mbedtls_mpi_exp_mod(out, base, exp, mod, NULL) +#define BIGNUM_MULT_BIG(prod, a, b) ret = mbedtls_mpi_mul_mpi(prod, a, b) +#define BIGNUM_ADD_BIG(prod, a, b) ret = mbedtls_mpi_add_mpi(prod, a, b) +#define BIGNUM_SUB_BIG(prod, a, b) ret = mbedtls_mpi_sub_mpi(prod, a, b) +#define BIGNUM_EQUALS(num, comp) (mbedtls_mpi_cmp_int(num, comp) == 0) +#define BIGNUM_WRITE_BYTES(num, bytes, bytes_size) if (mbedtls_mpi_write_binary(num, bytes, bytes_size) != 0) {return -1; } +#define BIGNUM_WRITE_BYTES_ALLOC(num, bytes_pp, len_p, lbl) do {\ + *len_p = mbedtls_mpi_size(num); \ + *bytes_pp = malloc(*len_p); \ + if (!*bytes_pp) { goto lbl; } \ + if (mbedtls_mpi_write_binary(num, *bytes_pp, *len_p) != 0) {goto lbl; } \ +} while(false) +#define BIGNUM_PRINT(prefix, num) mbedtls_mpi_write_file(prefix, num, 16, stderr) +#define HASH_CONTEXT mbedtls_sha256_context + +void librist_crypto_srp_mbedtls_hash_init(HASH_CONTEXT *ctx, bool correct_init) { + mbedtls_sha256_init(ctx); + if (correct_init) { +#if USE_SHA_RET + mbedtls_sha256_starts_ret(ctx, 0); +#else + mbedtls_sha256_starts(ctx, 0); +#endif + } +} + +#define HASH_CONTEXT_INIT(ctx, correct) librist_crypto_srp_mbedtls_hash_init(ctx, correct) +#define HASH_CONTEXT_FREE(ctx) mbedtls_sha256_free(ctx) +static mbedtls_entropy_context entropy_ctx; +static mbedtls_ctr_drbg_context ctr_drbg_ctx; + + +#elif HAVE_NETTLE +#include <nettle/sha2.h> +#include <nettle/bignum.h> +#include <gnutls/crypto.h> +#define BIGNUM MP_INT +#define BIGNUM_INIT(num) mpz_init(num) +#define BIGNUM_FREE(num) mpz_clear(num) +#define BIGNUM_GET_BINARY_SIZE(num) ((mpz_sizeinbase(num, 2) +7) /8) +#define BIGNUM_FROM_ARRAY(num, array, size) mpz_import(num, size, 1, 1, 0, 0, array) +#define BIGNUM_FROM_STRING(num, str) ret = mpz_set_str(num, str, 16) +#define BIGNUM_RANDOM(num, max) nettle_mpz_random(num, NULL, gnutls_random_wrapper, max); +#define BIGNUM_MOD_RED(out, a, b) mpz_mod(out, a, b) +#define BIGNUM_EXP_MOD(out, base, exp, mod) mpz_powm(out, base, exp, mod) +#define BIGNUM_MULT_BIG(prod, a, b) mpz_mul(prod, a, b) +#define BIGNUM_ADD_BIG(prod, a, b) mpz_add(prod, a, b) +#define BIGNUM_SUB_BIG(prod, a, b) mpz_sub(prod, a, b) +#define BIGNUM_EQUALS(num, comp) (mpz_cmp_ui(num, comp) == 0) +#define BIGNUM_WRITE_BYTES(num, bytes, bytes_size) mpz_export(bytes, NULL, 1, 1, 0, 0, num) +#define BIGNUM_WRITE_BYTES_ALLOC(num, bytes_pp, len_p, lbl) do {\ + *bytes_pp = mpz_export(NULL, len_p, 1, 1, 0, 0, num); \ + if (!*bytes_pp) { goto lbl; } \ +} while (false) +#define BIGNUM_PRINT(prefix, num) do { \ + fprintf(stderr, prefix); \ + mpz_out_str(stderr, 16, num); \ + fprintf(stderr, "\n"); \ +} while(false) +#define HASH_CONTEXT struct sha256_ctx +#define HASH_CONTEXT_INIT(ctx, correct) (void)(correct); nettle_sha256_init(ctx) +#define HASH_CONTEXT_FREE(ctx) + +void gnutls_random_wrapper(void *ctx, size_t length, uint8_t *dst) { + (void)ctx; + int ret; + int i=0; + do { + ret = gnutls_rnd(GNUTLS_RND_NONCE, dst, length);//This call is thread-safe + i++; + } while (ret != 0 && i < 10); +} +#endif + +static int librist_crypto_srp_hash_update(HASH_CONTEXT *hash_ctx, const void *data, size_t len) +{ +#if HAVE_MBEDTLS +#if !USE_SHA_RET + mbedtls_sha256_update( hash_ctx, data, len ); +#else + return mbedtls_sha256_update_ret( hash_ctx, data, len ); +#endif +#else + nettle_sha256_update( hash_ctx, len, data); + return 0; +#endif +} + +static int librist_crypto_srp_hash_update_bignum(HASH_CONTEXT *hash_ctx, const BIGNUM *num) { + uint8_t bytes[1024]; + size_t size = BIGNUM_GET_BINARY_SIZE(num); + if (size > sizeof(bytes)) + return -1; + + BIGNUM_WRITE_BYTES(num, bytes, size); + + return librist_crypto_srp_hash_update(hash_ctx, bytes, size); +} + +static int librist_crypto_srp_hash_final(HASH_CONTEXT *hash_ctx, uint8_t *data) +{ +#if HAVE_MBEDTLS +#if !USE_SHA_RET + mbedtls_sha256_finish( hash_ctx, data); +#else + return mbedtls_sha256_finish_ret( hash_ctx, data); +#endif +#else + nettle_sha256_digest( hash_ctx, SHA256_DIGEST_LENGTH, data); +#endif + return 0; +} + +static int librist_crypto_srp_hash(const uint8_t *indata, size_t inlen, uint8_t outdata[SHA256_DIGEST_LENGTH]) +{ +#if HAVE_MBEDTLS +#if !USE_SHA_RET + mbedtls_sha256(hash_data, salt_len + SHA256_DIGEST_LENGTH, x_hash, 0) +#else + return mbedtls_sha256_ret(indata, inlen, outdata, 0); +#endif +#else + HASH_CONTEXT hash_ctx; + HASH_CONTEXT_INIT(&hash_ctx, true); + librist_crypto_srp_hash_update(&hash_ctx, indata, inlen); + librist_crypto_srp_hash_final(&hash_ctx, outdata); +#endif + return 0; +} + +#if HAVE_PTHREADS +static void librist_crypto_srp_init_random_func(void) +#else +static BOOL librist_crypto_srp_init_random_func(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) +#endif +{ +#if HAVE_MBEDTLS + mbedtls_entropy_init(&entropy_ctx); + mbedtls_ctr_drbg_init(&ctr_drbg_ctx); + //ctr_drbg_ctx is threadsafe, so can be used by multiple threads freely, seeding isn't though. + const char user_custom[] = "libRIST librist_crypto_srp_init_random "LIBRIST_VERSION; + mbedtls_ctr_drbg_seed(&ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx, (const unsigned char *)user_custom, sizeof(user_custom)); +#endif +} + +static inline void librist_crypto_srp_init_random(void) { +#if HAVE_PTHREADS + pthread_once(&entropy_init_once, librist_crypto_srp_init_random_func); +#else + InitOnceExecuteOnce(&entropy_init_once, librist_crypto_srp_init_random_func, NULL, NULL); +#endif +} + +//Calculates the value of x as follows: x = SHA256(s, SHA256(I | “:†| P)) +static int librist_crypto_srp_calc_x(BIGNUM *salt, const char * username, const char * password, size_t password_len, BIGNUM *x, bool correct) +{ + HASH_CONTEXT hash_ctx; + HASH_CONTEXT_INIT(&hash_ctx, correct); + int ret = 0; + + if (librist_crypto_srp_hash_update(&hash_ctx, username, strlen(username)) != 0) + return -1; + if (librist_crypto_srp_hash_update(&hash_ctx, ":", 1) != 0) + return -1; + if (librist_crypto_srp_hash_update(&hash_ctx, password, password_len) != 0) + return -1; + + size_t salt_len = BIGNUM_GET_BINARY_SIZE(salt); + uint8_t *hash_data = malloc(salt_len + SHA256_DIGEST_LENGTH); + if (!hash_data) + return -1; + + if (librist_crypto_srp_hash_final(&hash_ctx, &hash_data[salt_len]) != 0) + goto failed; + + BIGNUM_WRITE_BYTES(salt, hash_data, salt_len); + if (ret != 0) + goto failed; + + HASH_CONTEXT_FREE(&hash_ctx); + + uint8_t x_hash[SHA256_DIGEST_LENGTH]; + + if (librist_crypto_srp_hash( hash_data, salt_len + SHA256_DIGEST_LENGTH, x_hash) != 0) + goto failed; + + BIGNUM_FROM_ARRAY(x, x_hash, SHA256_DIGEST_LENGTH); + if (ret != 0) + goto failed; + + free(hash_data); + return 0; + +failed: + free(hash_data); + return -1; +} + +static int librist_crypto_srp_hash_2_bignum(BIGNUM *A, BIGNUM *B, uint8_t hash_out[SHA256_DIGEST_LENGTH]) +{ + size_t A_size = BIGNUM_GET_BINARY_SIZE(A); + size_t B_size = BIGNUM_GET_BINARY_SIZE(B); + uint8_t AB[2048]; + + if (A_size + B_size > sizeof(AB)) + return -1; + BIGNUM_WRITE_BYTES(A, AB, A_size); + BIGNUM_WRITE_BYTES(B, &AB[A_size], B_size); + + return librist_crypto_srp_hash(AB, A_size+B_size, hash_out); +} + +static int librist_crypto_srp_hash_bignum(BIGNUM *in, uint8_t hash_out[SHA256_DIGEST_LENGTH]) +{ + size_t size = BIGNUM_GET_BINARY_SIZE(in); + uint8_t in_bytes[1024]; + if (size > sizeof(in_bytes)) + return -1; + BIGNUM_WRITE_BYTES(in, in_bytes, size); + return librist_crypto_srp_hash(in_bytes, size, hash_out); +} + +static int librist_crypto_srp_calculate_m(BIGNUM *N, BIGNUM *g, const char *I, BIGNUM *s, BIGNUM *A, BIGNUM *B, const uint8_t K[SHA256_DIGEST_LENGTH], uint8_t m1_out[SHA256_DIGEST_LENGTH], bool correct) { +#if DEBUG_EXTRACT_SRP_EXCHANGE + fprintf(stderr, "\n\n%s\n", __func__); + fprintf(stderr, "DOING CORRECT? %d\n", correct); + BIGNUM_PRINT("N: ", N); + BIGNUM_PRINT("g: ", g); + fprintf(stderr, "I: %s\n", I); + BIGNUM_PRINT("s: ",s); + BIGNUM_PRINT("A: ", A); + BIGNUM_PRINT("B: ", B); + print_hash(K, "K: "); +#endif + uint8_t hash_tmp[SHA256_DIGEST_LENGTH]; + { + uint8_t hash_N[SHA256_DIGEST_LENGTH]; + uint8_t hash_g[SHA256_DIGEST_LENGTH]; + + librist_crypto_srp_hash_bignum(N, hash_N); + librist_crypto_srp_hash_bignum(g, hash_g); + + for (size_t i=0; i < sizeof(hash_tmp); i++) + hash_tmp[i] = hash_N[i] ^ hash_g[i]; + } + +#if DEBUG_EXTRACT_SRP_EXCHANGE + print_hash(hash_tmp, "XOR: "); +#endif + + + int ret = -1; + HASH_CONTEXT hash_ctx; + HASH_CONTEXT_INIT(&hash_ctx, correct); + + if (librist_crypto_srp_hash_update(&hash_ctx, hash_tmp, sizeof(hash_tmp)) != 0) + goto out; + + if (librist_crypto_srp_hash((const uint8_t *)I, strlen(I), hash_tmp) != 0) + goto out; + + if (librist_crypto_srp_hash_update(&hash_ctx, hash_tmp, sizeof(hash_tmp)) != 0) + goto out; + + if (librist_crypto_srp_hash_update_bignum(&hash_ctx, s) != 0) + goto out; + + if (librist_crypto_srp_hash_update_bignum(&hash_ctx, A) != 0) + goto out; + + if (librist_crypto_srp_hash_update_bignum(&hash_ctx, B) != 0) + goto out; + + if (librist_crypto_srp_hash_update(&hash_ctx, K, SHA256_DIGEST_LENGTH) != 0) + goto out; + + if (librist_crypto_srp_hash_final(&hash_ctx, m1_out) != 0) + goto out; + + ret = 0; + +#if DEBUG_EXTRACT_SRP_EXCHANGE + print_hash(m1_out, "M1: "); + fprintf(stderr, "\n\n"); +#endif + +out: + HASH_CONTEXT_FREE(&hash_ctx); + return ret; +} + +static int librist_crypto_srp_calculate_m2(const BIGNUM *A,const uint8_t M1[SHA256_DIGEST_LENGTH],const uint8_t K[SHA256_DIGEST_LENGTH], uint8_t M2_OUT[SHA256_DIGEST_LENGTH], bool correct) { + HASH_CONTEXT hash_ctx; + HASH_CONTEXT_INIT(&hash_ctx, correct); + int ret; + ret = librist_crypto_srp_hash_update_bignum(&hash_ctx, A); + if (ret != 0) + goto out; + + ret = librist_crypto_srp_hash_update(&hash_ctx, M1, SHA256_DIGEST_LENGTH); + if (ret != 0) + goto out; + + ret = librist_crypto_srp_hash_update(&hash_ctx, K, SHA256_DIGEST_LENGTH); + if (ret != 0) + goto out; + + ret = librist_crypto_srp_hash_final(&hash_ctx, M2_OUT); + +out: + HASH_CONTEXT_FREE(&hash_ctx); + + return ret; +} + + +struct librist_crypto_srp_authenticator_ctx { + //Static values once created + BIGNUM N; + BIGNUM g; + BIGNUM v; + BIGNUM s; + + //Supplied by client + BIGNUM A; + + //Random number in range 0, N-1 + BIGNUM b; + BIGNUM k; + BIGNUM B; + + //Session key + uint8_t key[SHA256_DIGEST_LENGTH]; + + uint8_t m2[SHA256_DIGEST_LENGTH]; + + bool correct_hashing_init; +}; + +struct librist_crypto_srp_authenticator_ctx *librist_crypto_srp_authenticator_ctx_create(const char* n_hex, const char *g_hex, const uint8_t *v_bytes, size_t v_len, const uint8_t *s_bytes, size_t s_len, bool correct) { + if (!v_bytes || !s_bytes || v_len == 0 || s_len == 0) + return NULL; + struct librist_crypto_srp_authenticator_ctx *ctx = calloc(1, sizeof(*ctx)); + if (!ctx) + return NULL; + + ctx->correct_hashing_init = correct; + BIGNUM_INIT(&ctx->N); + BIGNUM_INIT(&ctx->g); + BIGNUM_INIT(&ctx->v); + BIGNUM_INIT(&ctx->s); + + int ret = 0; + BIGNUM_FROM_STRING(&ctx->N, n_hex); + if (ret != 0) + goto fail; + + BIGNUM_FROM_STRING(&ctx->g, g_hex); + if (ret != 0) + goto fail; + + BIGNUM_FROM_ARRAY(&ctx->v, v_bytes, v_len); + if (ret != 0) + goto fail; + + BIGNUM_FROM_ARRAY(&ctx->s, s_bytes, s_len); + if (ret != 0) + goto fail; + + + BIGNUM_INIT(&ctx->A); + BIGNUM_INIT(&ctx->b); + return ctx; + +fail: + BIGNUM_FREE(&ctx->N); + BIGNUM_FREE(&ctx->g); + BIGNUM_FREE(&ctx->v); + BIGNUM_FREE(&ctx->s); + free(ctx); + return NULL; +} + +void librist_crypto_srp_authenticator_ctx_free(struct librist_crypto_srp_authenticator_ctx *ctx) { + if (ctx == NULL) + return; + BIGNUM_FREE(&ctx->N); + BIGNUM_FREE(&ctx->g); + BIGNUM_FREE(&ctx->v); + BIGNUM_FREE(&ctx->s); + + BIGNUM_FREE(&ctx->A); + BIGNUM_FREE(&ctx->b); + BIGNUM_FREE(&ctx->k); + BIGNUM_FREE(&ctx->B); + + free(ctx); +} + +int librist_crypto_srp_authenticator_write_g_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t *g_buf, size_t g_buf_len) { + size_t size = BIGNUM_GET_BINARY_SIZE(&ctx->g); + if (g_buf_len < size) + return -1; + + BIGNUM_WRITE_BYTES(&ctx->g, g_buf, size); + return (int)size; +} + +int librist_crypto_srp_authenticator_write_n_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t *n_buf, size_t n_buf_len) { + size_t size = BIGNUM_GET_BINARY_SIZE(&ctx->N); + if (n_buf_len < size) + return -1; + + BIGNUM_WRITE_BYTES(&ctx->N, n_buf, size); + return (int)size; +} + +int librist_crypto_srp_authenticator_write_B_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t* B_buf, size_t B_buf_len) { + size_t size = BIGNUM_GET_BINARY_SIZE(&ctx->B); + if (B_buf_len < size) + return -1; + + BIGNUM_WRITE_BYTES(&ctx->B, B_buf, size); + return (int)size; +} + +void librist_crypto_srp_authenticator_write_M2_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t* m2_buf) { + memcpy(m2_buf, ctx->m2, sizeof(ctx->m2)); +} + +//We received A, verify that it's secure, set b and then calculate: +//k=SHA256(N,g) +//B=(kv + g^b) % N +int librist_crypto_srp_authenticator_handle_A(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t *A_buf, size_t A_buf_len) { + int ret = 0; + BIGNUM_FROM_ARRAY(&ctx->A, A_buf, A_buf_len); + if (ret != 0) + return -1; + + BIGNUM tmp; + BIGNUM_INIT(&tmp); + BIGNUM_MOD_RED(&tmp, &ctx->A, &ctx->N); + if (ret != 0) + goto out; + + if (BIGNUM_EQUALS(&tmp, 0)) + goto out; + + + librist_crypto_srp_init_random(); + //Set b +#if DEBUG_USE_EXAMPLE_CONSTANTS + const char b_hex[] = "ED0D58FF861A1FC75A0829BEA5F1392D2B13AB2B05CBCD6ED1E71AAAD761E856"; + BIGNUM_FROM_STRING(&ctx->b, b_hex); +#else + BIGNUM_RANDOM(&ctx->b, &ctx->N); + if (ret != 0) + goto out; +#endif + + + //calc k + uint8_t k_hash[SHA256_DIGEST_LENGTH]; + librist_crypto_srp_hash_2_bignum(&ctx->N, &ctx->g, k_hash); + BIGNUM_FROM_ARRAY(&ctx->k, k_hash, sizeof(k_hash)); + if (ret != 0) + goto out; + + BIGNUM tmp2; + BIGNUM_INIT(&tmp2); + + //calc B + BIGNUM_MULT_BIG(&tmp, &ctx->k, &ctx->v); + if (ret != 0) + goto b_out; + + BIGNUM_EXP_MOD(&tmp2, &ctx->g, &ctx->b, &ctx->N); + if (ret != 0) + goto b_out; + + BIGNUM_ADD_BIG(&tmp, &tmp, &tmp2); + if (ret != 0) + goto b_out; + + BIGNUM_MOD_RED(&ctx->B, &tmp, &ctx->N); + if (ret != 0) + goto b_out; + +#if DEBUG_EXTRACT_SRP_EXCHANGE + fprintf(stderr, "%s\n", __func__); + BIGNUM_PRINT("b: ", &ctx->b); + BIGNUM_PRINT("k: ", &ctx->k); + BIGNUM_PRINT("B: ", &ctx->B); +#endif + + +b_out: + BIGNUM_FREE(&tmp2); + +out: + BIGNUM_FREE(&tmp); + return ret; +} + +//Calculate M1 & verify against client supplied M1 value +//u = SHA256(A, B) +//S = ((Av^u) ^ b) % N +//K = SHA256(S) +//M1 = SHA256(SHA256(N) xor SHA256(g), SHA256(I, s, A, B, K) +//Verify that client supplied M1 matches our calculation +//Then calculate M2: +//M2 = SHA256(A, M1, K) +int librist_crypto_srp_authenticator_verify_m1(struct librist_crypto_srp_authenticator_ctx *ctx, const char *username, uint8_t *client_m1_buf) { + uint8_t u_hash[SHA256_DIGEST_LENGTH]; + if (librist_crypto_srp_hash_2_bignum(&ctx->A, &ctx->B, u_hash) != 0) { + return -1; + } + + int ret = 0; + BIGNUM u; + BIGNUM tmp1; + BIGNUM tmp2; + BIGNUM_INIT(&u); + BIGNUM_INIT(&tmp1); + BIGNUM_INIT(&tmp2); + + BIGNUM_FROM_ARRAY(&u, u_hash, sizeof(u_hash)); + if (ret != 0) + goto out; + + BIGNUM_EXP_MOD(&tmp1, &ctx->v, &u, &ctx->N); + if (ret != 0) + goto out; + + BIGNUM_MULT_BIG(&tmp2, &ctx->A, &tmp1); + if (ret != 0) + goto out; + + //tmp1 -> S + BIGNUM_EXP_MOD(&tmp1, &tmp2, &ctx->b, &ctx->N); + + librist_crypto_srp_hash_bignum(&tmp1, ctx->key); + +#if DEBUG_EXTRACT_SRP_EXCHANGE + fprintf(stderr, "%s\n", __func__); + BIGNUM_PRINT("u: ", &u); + BIGNUM_PRINT("S: ", &tmp1); + print_hash(ctx->key, "K: "); +#endif + + uint8_t m1_buf[SHA256_DIGEST_LENGTH]; + ret = librist_crypto_srp_calculate_m(&ctx->N, &ctx->g, username, &ctx->s, &ctx->A, &ctx->B, ctx->key, m1_buf, ctx->correct_hashing_init); + if (ret != 0) + goto out; + +#if DEBUG_EXTRACT_SRP_EXCHANGE + print_hash(m1_buf, "M1: "); +#endif + + ret = memcmp(m1_buf, client_m1_buf, sizeof(m1_buf)); + if (ret != 0) + goto out; + + ret = librist_crypto_srp_calculate_m2(&ctx->A, m1_buf, ctx->key, ctx->m2, ctx->correct_hashing_init); + +#if DEBUG_EXTRACT_SRP_EXCHANGE + print_hash(ctx->key, "M2: "); +#endif +out: + BIGNUM_FREE(&u); + BIGNUM_FREE(&tmp1); + BIGNUM_FREE(&tmp2); + + return ret; +} + +struct librist_crypto_srp_client_ctx { + //Static values once created + BIGNUM N; + BIGNUM g; + BIGNUM s; + BIGNUM a; + BIGNUM A; + + //Supplied by server + BIGNUM B; + + BIGNUM k; + + //Session key + uint8_t key[SHA256_DIGEST_LENGTH]; + + uint8_t m1[SHA256_DIGEST_LENGTH]; + + bool correct_hashing_init; +}; + +int librist_crypto_srp_client_write_A_bytes(struct librist_crypto_srp_client_ctx *ctx, uint8_t *A_buf, size_t A_buf_len) { + size_t size = BIGNUM_GET_BINARY_SIZE(&ctx->A); + if (A_buf_len < size) + return -1; + + BIGNUM_WRITE_BYTES(&ctx->A, A_buf, size); + return (int)size; +} + +void librist_crypto_srp_client_write_M1_bytes(struct librist_crypto_srp_client_ctx *ctx, uint8_t M1_buf[SHA256_DIGEST_LENGTH]) { + memcpy(M1_buf, ctx->m1, sizeof(ctx->m1)); +} + + +//We've received B from the server so now we compute: +//x = SHA256(s, SHA256(I, “:â€, P)) +//k = SHA256(N, g) +//u = SHA256(A, B) +//S = ((B – kg^x) ^ (a +ux)) % N +//K = SHA256(S) +//M1 = SHA256(SHA256(N) xor SHA256(g), SHA256(I, s, A, B, K)) +int librist_crypto_srp_client_handle_B(struct librist_crypto_srp_client_ctx *ctx, uint8_t *B_bytes, size_t B_len, const char *username, const char *password) { + int ret = 0; + + BIGNUM_FROM_ARRAY(&ctx->B, B_bytes, B_len); + if (ret != 0) + return -1; + + BIGNUM u; + BIGNUM x; + BIGNUM tmp1; + BIGNUM tmp2; + BIGNUM tmp3; + BIGNUM tmp4; + + BIGNUM_INIT(&u); + BIGNUM_INIT(&x); + BIGNUM_INIT(&tmp1); + BIGNUM_INIT(&tmp2); + BIGNUM_INIT(&tmp3); + BIGNUM_INIT(&tmp4); + + //Safety check: exit early if B mod N equals 0 + BIGNUM_MOD_RED(&tmp1, &ctx->B, &ctx->N); + if (ret != 0) + goto out; + + if (BIGNUM_EQUALS(&tmp1, 0)) + goto out; + + //Calculate u & execute safety check + { + uint8_t u_hash[SHA256_DIGEST_LENGTH]; + ret =librist_crypto_srp_hash_2_bignum(&ctx->A, &ctx->B, u_hash); + if (ret != 0) + goto out; + + + BIGNUM_FROM_ARRAY(&u, u_hash, sizeof(u_hash)); + //Safety check: exit early if u mod N equals 0 + BIGNUM_MOD_RED(&tmp1, &u, &ctx->N); + if (ret != 0) + goto out; + + if (BIGNUM_EQUALS(&tmp1, 0)) + goto out; + } + + //Calculate k + { + uint8_t k_hash[SHA256_DIGEST_LENGTH]; + ret = librist_crypto_srp_hash_2_bignum(&ctx->N, &ctx->g, k_hash); + if (ret != 0) + goto out; + + BIGNUM_FROM_ARRAY(&tmp4, k_hash, sizeof(k_hash)); + } + + ret = librist_crypto_srp_calc_x(&ctx->s, username, password, strlen(password), &x, ctx->correct_hashing_init); + if (ret != 0) + goto out; + +#if DEBUG_EXTRACT_SRP_EXCHANGE + fprintf(stderr, "%s\n", __func__); + BIGNUM_PRINT("u: ", &u); + BIGNUM_PRINT("k: ", &tmp4); + BIGNUM_PRINT("x: ", &x); +#endif + + //Calculate 'v' (g^x) + BIGNUM_EXP_MOD(&tmp2, &ctx->g, &x, &ctx->N); + if (ret != 0) + goto out; + + // k (tmp4) * g^x (tmp2) + BIGNUM_MULT_BIG(&tmp3, &tmp4, &tmp2); + if (ret != 0) + goto out; + + // B - kg^x (tmp3) + BIGNUM_SUB_BIG(&tmp1, &ctx->B, &tmp3); + if (ret != 0) + goto out; + + //u * x + BIGNUM_MULT_BIG(&tmp3, &u, &x); + if (ret != 0) + goto out; + + //a + ux (tmp3) + BIGNUM_ADD_BIG(&tmp2, &ctx->a, &tmp3); + if (ret != 0) + goto out; + + //S = ((B – kg^x) (tmp1) ^ (a +ux)) (tmp2) % N + BIGNUM_EXP_MOD(&tmp3, &tmp1, &tmp2, &ctx->N); + if (ret != 0) + goto out; + + ret = librist_crypto_srp_hash_bignum(&tmp3, ctx->key); + if (ret != 0) + goto out; + +#if DEBUG_EXTRACT_SRP_EXCHANGE + BIGNUM_PRINT("S: ", &tmp3); + print_hash(ctx->key, "K: "); +#endif + + ret = librist_crypto_srp_calculate_m(&ctx->N, &ctx->g, username, &ctx->s, &ctx->A, &ctx->B, ctx->key, ctx->m1, ctx->correct_hashing_init); + +out: + BIGNUM_FREE(&u); + BIGNUM_FREE(&x); + BIGNUM_FREE(&tmp4); + BIGNUM_FREE(&tmp1); + BIGNUM_FREE(&tmp2); + BIGNUM_FREE(&tmp3); + return ret; +} + +int librist_crypto_srp_client_verify_m2(struct librist_crypto_srp_client_ctx *ctx, uint8_t *m2) { + uint8_t calc_m2[SHA256_DIGEST_LENGTH]; + int ret = librist_crypto_srp_calculate_m2(&ctx->A, ctx->m1, ctx->key, calc_m2, ctx->correct_hashing_init); + if (ret != 0) + return ret; + + return memcmp(m2, calc_m2, sizeof(calc_m2)); +} + +struct librist_crypto_srp_client_ctx *librist_crypto_srp_client_ctx_create(bool default_ng, uint8_t *N_bytes, size_t N_len, uint8_t *g_bytes, size_t g_len, uint8_t *s_bytes, size_t s_len, bool correct) { + if (!s_bytes || s_len == 0 || (!default_ng && (!N_bytes || N_len == 0 || !g_bytes || g_len == 0))) + return NULL; + + struct librist_crypto_srp_client_ctx *ctx = calloc(sizeof(*ctx), 1); + if (!ctx) + return NULL; + + ctx->correct_hashing_init = correct; + BIGNUM_INIT(&ctx->N); + BIGNUM_INIT(&ctx->g); + BIGNUM_INIT(&ctx->s); + BIGNUM_INIT(&ctx->a); + BIGNUM_INIT(&ctx->A); + BIGNUM_INIT(&ctx->B); + BIGNUM_INIT(&ctx->k); + + int ret = 0; + BIGNUM_FROM_ARRAY(&ctx->s, s_bytes, s_len); + if (ret != 0) + goto fail; + + if (default_ng) { + const char *N = NULL; + const char *g = NULL; + librist_get_ng_constants(LIBRIST_SRP_NG_DEFAULT, &N, &g); + BIGNUM_FROM_STRING(&ctx->N, N); + if (ret != 0) + goto fail; + + BIGNUM_FROM_STRING(&ctx->g, g); + if (ret != 0) + goto fail; + } else { + BIGNUM_FROM_ARRAY(&ctx->g, g_bytes,g_len); + if (ret != 0) + goto fail; + + BIGNUM_FROM_ARRAY(&ctx->N, N_bytes, N_len); + if (ret != 0) + goto fail; + } + +#if DEBUG_USE_EXAMPLE_CONSTANTS + const char a_hex[] = "138AB4045633AD14961CB1AD0720B1989104151C0708794491113302CCCC27D5"; + BIGNUM_FROM_STRING(&ctx->a, a_hex); +#else + BIGNUM_RANDOM(&ctx->a, &ctx->N); + if (ret != 0) + goto fail; +#endif + + BIGNUM_EXP_MOD(&ctx->A, &ctx->g, &ctx->a, &ctx->N); + if (ret != 0) + goto fail; + +#if DEBUG_EXTRACT_SRP_EXCHANGE + fprintf(stderr, "%s\n", __func__); + BIGNUM_PRINT("N: ", &ctx->N); + BIGNUM_PRINT("g: ", &ctx->g); + BIGNUM_PRINT("s: ", &ctx->s); + BIGNUM_PRINT("a: ", &ctx->a); + BIGNUM_PRINT("A: ", &ctx->A); +#endif + + return ctx; +fail: + librist_crypto_srp_client_ctx_free(ctx); + return NULL; +} + +void librist_crypto_srp_client_ctx_free(struct librist_crypto_srp_client_ctx *ctx) { + if (!ctx) + return; + BIGNUM_FREE(&ctx->N); + BIGNUM_FREE(&ctx->g); + BIGNUM_FREE(&ctx->s); + BIGNUM_FREE(&ctx->a); + BIGNUM_FREE(&ctx->A); + BIGNUM_FREE(&ctx->B); + BIGNUM_FREE(&ctx->k); + + free(ctx); +} + +//Creates a verifier & salt as follows: +//salt 32 byte random +//v: v = g^x +int librist_crypto_srp_create_verifier( + const char *n_hex, const char *g_hex, + const char *username, const char *password, + unsigned char **bytes_s, size_t *len_s, + unsigned char **bytes_v, size_t *len_v, + bool correct) + +{ + if (*bytes_s != NULL || *bytes_v != NULL) + return -1; + + int ret = 0; + BIGNUM s; + BIGNUM v; + BIGNUM x; + BIGNUM n; + BIGNUM g; + + BIGNUM_INIT(&s); + BIGNUM_INIT(&v); + BIGNUM_INIT(&x); + BIGNUM_INIT(&n); + BIGNUM_INIT(&g); + + BIGNUM_FROM_STRING(&n, n_hex); + if (ret != 0) + goto failed; + + BIGNUM_FROM_STRING(&g, g_hex); + if (ret != 0) + goto failed; + + librist_crypto_srp_init_random(); + //Fill the salt +#if DEBUG_USE_EXAMPLE_CONSTANTS + const char salt_hex[] = "72F9D5383B7EB7599FB63028F47475B60A55F313D40E0BE023E026C97C0A2C32"; + BIGNUM_FROM_STRING(&s, salt_hex); +#else +#if HAVE_MBEDTLS + mbedtls_mpi_fill_random(&s, 32, mbedtls_ctr_drbg_random, &ctr_drbg_ctx); +#elif HAVE_NETTLE + nettle_mpz_random_size(&s, NULL, gnutls_random_wrapper, 8 * 32); +#endif + if (ret != 0) + goto failed; +#endif + + // Calculate x + if (librist_crypto_srp_calc_x(&s, username, password, strlen(password), + &x, correct) != 0) goto failed; + + BIGNUM_EXP_MOD(&v, &g, &x, &n); + if (ret != 0) + goto failed; + + BIGNUM_WRITE_BYTES_ALLOC(&s, bytes_s, len_s, failed); + BIGNUM_WRITE_BYTES_ALLOC(&v, bytes_v, len_v, failed); + +#if DEBUG_EXTRACT_SRP_EXCHANGE + fprintf(stderr, "%s\n", __func__); + BIGNUM_PRINT("N: ", &n); + BIGNUM_PRINT("G: ", &g); + BIGNUM_PRINT("s: ", &s); + BIGNUM_PRINT("v: ", &v); + BIGNUM_PRINT("x: ", &x); +#endif + + BIGNUM_FREE(&s); + BIGNUM_FREE(&v); + BIGNUM_FREE(&x); + BIGNUM_FREE(&n); + BIGNUM_FREE(&g); + return 0; + +failed: + BIGNUM_FREE(&s); + BIGNUM_FREE(&v); + BIGNUM_FREE(&x); + BIGNUM_FREE(&n); + BIGNUM_FREE(&g); + + free(*bytes_s); + free(*bytes_v); + + return -1; +} diff --git a/src/crypto/srp.h b/src/crypto/srp.h new file mode 100644 index 0000000000000000000000000000000000000000..58a8159404769daf4f4e6cb5b5bed708f368d343 --- /dev/null +++ b/src/crypto/srp.h @@ -0,0 +1,38 @@ +#ifndef LIBRIST_CRYPTO_SRH_H +#define LIBRIST_CRYPTO_SRH_H + +#include <librist/common.h> +#include "common/attributes.h" + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + +#define SHA256_DIGEST_LENGTH 32 + +struct librist_crypto_srp_authenticator_ctx; +struct librist_crypto_srp_client_ctx; + +//Marked as public because we want to use it in ristsrppassword. NOT (yet) intended for public use, so zero API/ABI guarantees/promises. +RIST_API int librist_crypto_srp_create_verifier(const char *n_hex, const char *g_hex, + const char *username, + const char *password, + unsigned char **bytes_s, size_t *len_s, + unsigned char **bytes_v, size_t *len_v, bool correct); + +RIST_PRIV struct librist_crypto_srp_authenticator_ctx *librist_crypto_srp_authenticator_ctx_create(const char* n_hex, const char *g_hex, const uint8_t *v_bytes, size_t v_len, const uint8_t *s_bytes, size_t s_len, bool correct); +RIST_PRIV void librist_crypto_srp_authenticator_ctx_free(struct librist_crypto_srp_authenticator_ctx *ctx); +RIST_PRIV int librist_crypto_srp_authenticator_write_g_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t *g_buf, size_t g_buf_len); +RIST_PRIV int librist_crypto_srp_authenticator_write_n_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t *n_buf, size_t n_buf_len); +RIST_PRIV int librist_crypto_srp_authenticator_handle_A(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t *A_buf, size_t A_buf_len); +RIST_PRIV int librist_crypto_srp_authenticator_write_B_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t* B_buf, size_t B_buf_len); +RIST_PRIV int librist_crypto_srp_authenticator_verify_m1(struct librist_crypto_srp_authenticator_ctx *ctx,const char *username, uint8_t *client_m1_buf); +RIST_PRIV void librist_crypto_srp_authenticator_write_M2_bytes(struct librist_crypto_srp_authenticator_ctx *ctx, uint8_t* m2_buf); + +RIST_PRIV struct librist_crypto_srp_client_ctx *librist_crypto_srp_client_ctx_create(bool default_ng, uint8_t *N_bytes, size_t N_len, uint8_t *g_bytes, size_t g_len, uint8_t *s_bytes, size_t s_len, bool correct); +RIST_PRIV void librist_crypto_srp_client_ctx_free(struct librist_crypto_srp_client_ctx *ctx); +RIST_PRIV int librist_crypto_srp_client_write_A_bytes(struct librist_crypto_srp_client_ctx *ctx, uint8_t *A_buf, size_t A_buf_len); +RIST_PRIV int librist_crypto_srp_client_handle_B(struct librist_crypto_srp_client_ctx *ctx, uint8_t *B_bytes, size_t B_len, const char *username, const char *password); +RIST_PRIV void librist_crypto_srp_client_write_M1_bytes(struct librist_crypto_srp_client_ctx *ctx, uint8_t M1_buf[SHA256_DIGEST_LENGTH]); +RIST_PRIV int librist_crypto_srp_client_verify_m2(struct librist_crypto_srp_client_ctx *ctx, uint8_t *m2); +#endif /* LIBRIST_CRYPTO_SRH_H */ diff --git a/src/crypto/srp_constants.c b/src/crypto/srp_constants.c new file mode 100644 index 0000000000000000000000000000000000000000..0331f5f848b6b125ccb1235ed92ca695112b9481 --- /dev/null +++ b/src/crypto/srp_constants.c @@ -0,0 +1,124 @@ +#include "srp_constants.h" + +#include <stddef.h> +#include <stdbool.h> +struct NGHex { + const char *n_hex; + const char *g_hex; +}; + +/* All constants here were pulled from Appendix A of RFC 5054 */ +static const struct NGHex global_Ng_constants[] = { + {/* 512 */ + "D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B" + "1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3", + "2" + }, + {/* 768 */ + "B344C7C4F8C495031BB4E04FF8F84EE95008163940B9558276744D91F7CC9F402653BE7147F" + "00F576B93754BCDDF71B636F2099E6FFF90E79575F3D0DE694AFF737D9BE9713CEF8D837ADA" + "6380B1093E94B6A529A8C6C2BE33E0867C60C3262B", + "2" + }, + {/* 1024 */ + "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496" + "EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8E" + "F4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA" + "9AFD5138FE8376435B9FC61D2FC0EB06E3", + "2" + }, + {/* 2048 */ + "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4" + "A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60" + "95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF" + "747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B907" + "8717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB37861" + "60279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DB" + "FBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", + "2" + }, + {/* 4096 */ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" + "FFFFFFFFFFFFFFFF", + "5" + }, + {/* 8192 */ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + "6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA" + "3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C" + "5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886" + "2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6" + "6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5" + "0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268" + "359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6" + "FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", + "13" + }, + {0, 0} /* null sentinel */ +}; + +int librist_get_ng_constants(librist_srp_ng_e ng_pair, const char **n, const char **g) +{ + if (*n != NULL || *g != NULL) { + return -1; + } + int i = 0; + while (true) { + if (global_Ng_constants[i].n_hex == NULL) { + return -1; + } + if (i == (int)ng_pair) { + *n = global_Ng_constants[i].n_hex; + *g = global_Ng_constants[i].g_hex; + return 0; + } + i++; + } + + +} diff --git a/src/crypto/srp_constants.h b/src/crypto/srp_constants.h new file mode 100644 index 0000000000000000000000000000000000000000..ec1e530d4c8b0edbcb8b47649a69083d810f0890 --- /dev/null +++ b/src/crypto/srp_constants.h @@ -0,0 +1,21 @@ +#ifndef LIBRIST_CRYPTO_SRP_CONSTANTS_H +#define LIBRIST_CRYPTO_SRP_CONSTANTS_H + + +#include <librist/common.h> +typedef enum +{ + LIBRIST_SRP_NG_512, + LIBRIST_SRP_NG_768, + LIBRIST_SRP_NG_1024, + LIBRIST_SRP_NG_2048, + LIBRIST_SRP_NG_4096, + LIBRIST_SRP_NG_8192 +} librist_srp_ng_e; + +#define LIBRIST_SRP_NG_DEFAULT LIBRIST_SRP_NG_2048 + +//Marked as public because we want to use it in ristsrppassword. NOT (yet) intended for public use, so zero API/ABI guarantees/promises. +RIST_API int librist_get_ng_constants(librist_srp_ng_e ng_pair, const char **n, const char **g); + +#endif /* LIBRIST_CRYPTO_SRP_CONSTANTS_H */ diff --git a/src/eap.c b/src/eap.c index d1acd5b98d6700c3073208ba54772ba4e346dd95..ad35f83b503cd76cbe2cbcb6621eeee49e001c0a 100644 --- a/src/eap.c +++ b/src/eap.c @@ -6,15 +6,18 @@ */ #include "eap.h" +#include "config.h" #include "endian-shim.h" -#include "srp.h" #include "crypto/crypto-private.h" +#include "crypto/srp.h" +#include "crypto/srp_constants.h" +#include "librist_srp.h" #include "rist-private.h" #include "udp-private.h" #include "log-private.h" -#include <mbedtls/bignum.h> #include <stddef.h> +#include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> @@ -32,34 +35,29 @@ void eap_reset_data(struct eapsrp_ctx *ctx) { if (ctx->role == EAP_ROLE_AUTHENTICATOR) { +#if HAVE_MBEDTLS + free(ctx->authenticator_bytes_salt_old); + free(ctx->authenticator_bytes_verifier_old); + ctx->authenticator_bytes_salt_old = NULL; + ctx->authenticator_bytes_verifier_old = NULL; +#endif free(ctx->authenticator_bytes_salt); free(ctx->authenticator_bytes_verifier); + ctx->authenticator_bytes_salt = NULL; + ctx->authenticator_bytes_verifier = NULL; } - free(ctx->ascii_g); - free(ctx->ascii_n); + librist_crypto_srp_authenticator_ctx_free(ctx->auth_ctx); + ctx->auth_ctx = NULL; + librist_crypto_srp_client_ctx_free(ctx->client_ctx); + ctx->client_ctx = NULL; free(ctx->last_pkt); - free(ctx->salt); - free(ctx->verifier); - if (ctx->srp_user) - srp_user_delete(ctx->srp_user); - if (ctx->srp_session) - srp_session_delete(ctx->srp_session); - if (ctx->srp_verifier) - srp_verifier_delete(ctx->srp_verifier); - ctx->ascii_g = NULL; - ctx->ascii_n = NULL; + ctx->last_pkt = NULL; - ctx->salt = NULL; - ctx->salt_len = 0; - ctx->verifier = NULL; - ctx->srp_user = NULL; - ctx->srp_session = NULL; - ctx->srp_verifier = NULL; - ctx->authenticator_bytes_salt = NULL; - ctx->authenticator_bytes_verifier = NULL; + + ctx->authenticated = false; } -static int send_eapol_pkt(struct eapsrp_ctx *ctx, uint8_t eapoltype, uint8_t eapcode, uint8_t identifier, size_t payload_len, uint8_t buf[]) +static int send_eapol_pkt(struct eapsrp_ctx *ctx, uint8_t eapoltype, uint8_t eapcode, uint8_t identifier, size_t payload_len, uint8_t buf[], uint8_t gre_version) { size_t offset = 0; struct rist_gre_hdr *gre = (struct rist_gre_hdr *)&buf[offset]; @@ -70,6 +68,7 @@ static int send_eapol_pkt(struct eapsrp_ctx *ctx, uint8_t eapoltype, uint8_t eap offset += sizeof(*eap_hdr); memset(gre, 0, sizeof(*gre)); gre->prot_type = htobe16(RIST_GRE_PROTOCOL_TYPE_EAPOL); + gre->flags2 = (gre_version &0x7) << 3; eapol_hdr->eapversion = 2; eapol_hdr->eaptype = eapoltype; eap_hdr->code = eapcode; @@ -109,13 +108,19 @@ static int process_eap_request_identity(struct eapsrp_ctx *ctx, uint8_t identifi offset += strlen(ctx->username); size_t len = offset; len -= EAPOL_EAP_HDRS_OFFSET; - return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, len, eapolpkt); + return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, len, eapolpkt, ctx->use_correct_hashing? 1 :0); } -static int process_eap_request_srp_challenge(struct eapsrp_ctx *ctx, uint8_t identifier, size_t len, uint8_t pkt[]) +static int process_eap_request_srp_challenge(struct eapsrp_ctx *ctx, uint8_t identifier, size_t len, uint8_t pkt[], uint8_t gre_version) { if (len < 6) return EAP_LENERR; + +#if HAVE_MBEDTLS + ctx->use_correct_hashing = (gre_version >= 1); +#elif HAVE_NETTLE + (void)(gre_version); +#endif size_t offset = 0; uint16_t *tmp_swap = (uint16_t *)&pkt[offset]; size_t name_len = be16toh(*tmp_swap); @@ -129,10 +134,12 @@ static int process_eap_request_srp_challenge(struct eapsrp_ctx *ctx, uint8_t ide offset += 2; if (len < (offset + salt_len)) return EAP_LENERR; - if (salt_len > ctx->salt_len) - ctx->salt = realloc(ctx->salt, salt_len); - memcpy(ctx->salt, &pkt[offset], salt_len); - ctx->salt_len = salt_len; + + bool use_default_2048 = true; + uint8_t *salt = &pkt[offset]; + uint8_t *g = NULL; + uint8_t *N = NULL; + size_t N_len = 0; offset += salt_len; tmp_swap = (uint16_t *)&pkt[offset]; size_t generator_len = be16toh(*tmp_swap); @@ -141,74 +148,33 @@ static int process_eap_request_srp_challenge(struct eapsrp_ctx *ctx, uint8_t ide { if (len < (offset + generator_len)) return EAP_LENERR; - mbedtls_mpi tmp; - mbedtls_mpi_init(&tmp); - mbedtls_mpi_read_binary(&tmp, (const unsigned char *)&pkt[offset], generator_len); - char generator[16]; - char *generator_buf = generator; - size_t olen = 0; - int ret = 0; - if ((ret = mbedtls_mpi_write_string(&tmp, 16, generator, 16, &olen)) !=0) - { - if (ret == MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL) - { - generator_buf = malloc(olen); - mbedtls_mpi_write_string(&tmp, 16, generator_buf, olen, &olen); - } else - return ret; - } + + g = &pkt[offset]; offset += generator_len; - size_t remaining_bytes = len - offset; - mbedtls_mpi_read_binary(&tmp, (const unsigned char *)&pkt[offset], remaining_bytes); - olen = 0; - char *n_modulus = NULL; - mbedtls_mpi_write_string(&tmp, 16, n_modulus, 0, &olen); - n_modulus = malloc(olen); - mbedtls_mpi_write_string(&tmp, 16, n_modulus, olen, &olen); - mbedtls_mpi_free(&tmp); - if (ctx->srp_session) - srp_session_delete(ctx->srp_session); - ctx->srp_session = srp_session_new(HASH_ALGO, SRP_NG_CUSTOM, n_modulus, generator_buf); - free(n_modulus); - if (generator_buf != generator) - free(generator_buf); - } else { - if (ctx->srp_session) - srp_session_delete(ctx->srp_session); - ctx->srp_session = srp_session_new(HASH_ALGO, SRP_NG_2048, NULL, NULL); + N = &pkt[offset]; + N_len = len - offset; } - if (ctx->srp_user) - srp_user_delete(ctx->srp_user); - ctx->srp_user = srp_user_new(ctx->srp_session, ctx->username, (const unsigned char*)ctx->password, strlen(ctx->password)); + librist_crypto_srp_client_ctx_free(ctx->client_ctx); + ctx->client_ctx = librist_crypto_srp_client_ctx_create(use_default_2048, N, N_len, g, generator_len, salt, salt_len, ctx->use_correct_hashing); size_t len_A; - char * bytes_A; - char * username; - srp_user_start_authentication(ctx->srp_user, (const char **)&username, (const unsigned char **)&bytes_A, &len_A); - uint8_t *response = malloc(EAPOL_EAP_HDRS_OFFSET + sizeof(struct eap_srp_hdr) + len_A); + uint8_t response[1500] = {0}; struct eap_srp_hdr *hdr = (struct eap_srp_hdr *)&response[EAPOL_EAP_HDRS_OFFSET]; hdr->type = EAP_TYPE_SRP_SHA1; hdr->subtype = EAP_SRP_SUBTYPE_CHALLENGE; - memcpy(&response[EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr)], bytes_A, len_A); - int ret = send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, (len_A + sizeof(*hdr)), response); - free(response); + len_A = librist_crypto_srp_client_write_A_bytes(ctx->client_ctx, &response[EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr)], sizeof(response) -(EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr))); + int ret = send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, (len_A + sizeof(*hdr)), response, ctx->use_correct_hashing? 1 :0); return ret; } static int process_eap_request_srp_server_key(struct eapsrp_ctx *ctx, uint8_t identifier, size_t len, uint8_t pkt[]) { - char *bytes_B = (char *)pkt; - size_t len_B = len; - size_t len_M = 0; - char *bytes_M; - srp_user_process_challenge(ctx->srp_user, (const unsigned char *)ctx->salt, ctx->salt_len,(const unsigned char *) bytes_B, len_B, (const unsigned char**)&bytes_M, &len_M); - if (!bytes_M) + if (librist_crypto_srp_client_handle_B(ctx->client_ctx, pkt, len, ctx->username, ctx->password) != 0) { ctx->authentication_state = EAP_AUTH_STATE_FAILED; //"must disconnect immediately, set tries past limit" ctx->tries = 255; return -255; } - assert(len_M == DIGEST_LENGTH); size_t out_len = sizeof(struct eap_srp_hdr) + 4 + DIGEST_LENGTH; uint8_t response[(EAPOL_EAP_HDRS_OFFSET + sizeof(struct eap_srp_hdr) + 4 + DIGEST_LENGTH)]; size_t offset = EAPOL_EAP_HDRS_OFFSET; @@ -218,8 +184,8 @@ static int process_eap_request_srp_server_key(struct eapsrp_ctx *ctx, uint8_t id offset += 4; hdr->type = EAP_TYPE_SRP_SHA1; hdr->subtype = EAP_SRP_SUBTYPE_SERVER_KEY; - memcpy(&response[offset], bytes_M, len_M); - int ret = send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, out_len, response); + librist_crypto_srp_client_write_M1_bytes(ctx->client_ctx, &response[offset]); + int ret = send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, out_len, response, ctx->use_correct_hashing? 1 :0); return ret; } @@ -227,8 +193,7 @@ static int process_eap_request_srp_server_validator(struct eapsrp_ctx *ctx, uint { if (len < (4 + DIGEST_LENGTH)) return EAP_LENERR; - srp_user_verify_session(ctx->srp_user, &pkt[4]); - if (srp_user_is_authenticated(ctx->srp_user)) + if (librist_crypto_srp_client_verify_m2(ctx->client_ctx, &pkt[4]) == 0) { if (ctx->authentication_state < EAP_AUTH_STATE_SUCCESS) rist_log_priv2(ctx->logging_settings, RIST_LOG_INFO, EAP_LOG_PREFIX"Successfully authenticated\n"); @@ -239,7 +204,7 @@ static int process_eap_request_srp_server_validator(struct eapsrp_ctx *ctx, uint struct eap_srp_hdr *hdr = (struct eap_srp_hdr *)&outpkt[EAPOL_EAP_HDRS_OFFSET]; hdr->type = EAP_TYPE_SRP_SHA1; hdr->subtype = EAP_SRP_SUBTYPE_SERVER_VALIDATOR; - return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, sizeof(*hdr), outpkt); + return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_RESPONSE, identifier, sizeof(*hdr), outpkt, ctx->use_correct_hashing? 1 :0); } //perm failure ctx->authentication_state = EAP_AUTH_STATE_FAILED; @@ -248,7 +213,7 @@ static int process_eap_request_srp_server_validator(struct eapsrp_ctx *ctx, uint return -1; } -static int process_eap_request(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len, uint8_t identifier) +static int process_eap_request(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len, uint8_t identifier, uint8_t gre_version) { uint8_t type = pkt[0]; if (type == EAP_TYPE_IDENTITY) @@ -259,7 +224,7 @@ static int process_eap_request(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len switch (subtype) { case EAP_SRP_SUBTYPE_CHALLENGE: - return process_eap_request_srp_challenge(ctx, identifier, (len -2), &pkt[2]); + return process_eap_request_srp_challenge(ctx, identifier, (len -2), &pkt[2], gre_version); break; case EAP_SRP_SUBTYPE_SERVER_KEY: return process_eap_request_srp_server_key(ctx, identifier, (len -2), &pkt[2]); @@ -279,7 +244,7 @@ static int process_eap_request(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len //EAP RESPONSE HANDLING -static int process_eap_response_identity(struct eapsrp_ctx *ctx, size_t len, uint8_t pkt[]) +static int process_eap_response_identity(struct eapsrp_ctx *ctx, size_t len, uint8_t pkt[], uint8_t gre_version) { if (len > 255) return -1; @@ -292,7 +257,24 @@ static int process_eap_response_identity(struct eapsrp_ctx *ctx, size_t len, uin bool std_2048_ng = false; char *ascii_n = NULL; char *ascii_g = NULL; - ctx->lookup_func(ctx->username, &len_v, &bytes_v, &len_s, &bytes_s, &std_2048_ng, &ascii_n, &ascii_g, ctx->lookup_func_userdata); +#if HAVE_MBEDTLS + int hashversion = gre_version >= 1 ? 1 : 0; +#elif HAVE_NETTLE + (void)gre_version; + int hashversion = 1; +#endif + uint64_t generation = 0; + ctx->lookup_func(ctx->username, &len_v, &bytes_v, &len_s, &bytes_s, &std_2048_ng, &ascii_n, &ascii_g, &hashversion, &generation, ctx->lookup_func_userdata); +#if HAVE_NETTLE + if (hashversion == 0) { + rist_log_priv2(ctx->logging_settings, RIST_LOG_ERROR, EAP_LOG_PREFIX"Lookup from SRP File got hashversion 0 response, Nettle backend does not support this, authentication likely to fail\n"); + } + hashversion = 1; +#endif + ctx->generation = generation; + ctx->use_correct_hashing = (hashversion >= 1); + const char *n_hex = ascii_n; + const char *g_hex = ascii_g; bool found = (len_v != 0 && bytes_v && len_s != 0 && bytes_s); uint8_t outpkt[1500] = { 0 };//TUNE THIS size_t offset = EAPOL_EAP_HDRS_OFFSET; @@ -302,12 +284,16 @@ static int process_eap_response_identity(struct eapsrp_ctx *ctx, size_t len, uin hdr->subtype = EAP_SRP_SUBTYPE_CHALLENGE; if (found) { - ctx->salt = malloc(len_s); - memcpy(ctx->salt, bytes_s, len_s); - ctx->verifier = malloc(len_v); - memcpy(ctx->verifier, bytes_v, len_v); - ctx->salt_len = len_s; - ctx->verifier_len = len_v; + struct librist_crypto_srp_authenticator_ctx *auth_ctx = NULL; + if (std_2048_ng) + librist_get_ng_constants(LIBRIST_SRP_NG_DEFAULT, &n_hex, &g_hex); + + auth_ctx = librist_crypto_srp_authenticator_ctx_create(n_hex, g_hex, (uint8_t*)bytes_v, len_v, (uint8_t*)bytes_s, len_s, ctx->use_correct_hashing); + if (!auth_ctx) { + return -1;//Log some error? + } + librist_crypto_srp_authenticator_ctx_free(ctx->auth_ctx); + ctx->auth_ctx = auth_ctx; memset(&pkt[offset], 0, 2); offset += 2;//we dont send the server name uint16_t *tmp_swap = (uint16_t *)&outpkt[offset]; @@ -317,27 +303,21 @@ static int process_eap_response_identity(struct eapsrp_ctx *ctx, size_t len, uin offset += len_s; if (std_2048_ng) { - if (ctx->srp_session) - srp_session_delete(ctx->srp_session); - ctx->srp_session = srp_session_new(HASH_ALGO, SRP_NG_2048, NULL, NULL); memset(&outpkt[offset], 0, 2); offset += 2; } else { - mbedtls_mpi tmp; - mbedtls_mpi_init(&tmp); - mbedtls_mpi_read_string(&tmp, 16, ascii_g); tmp_swap = (uint16_t *)&outpkt[offset]; - *tmp_swap = htobe16((uint16_t)mbedtls_mpi_size(&tmp)); offset += 2; - mbedtls_mpi_write_binary(&tmp, &outpkt[offset], mbedtls_mpi_size(&tmp)); - offset += mbedtls_mpi_size(&tmp); - mbedtls_mpi_read_string(&tmp, 16, ascii_n); - mbedtls_mpi_write_binary(&tmp, &outpkt[offset], mbedtls_mpi_size(&tmp)); - offset += mbedtls_mpi_size(&tmp); - mbedtls_mpi_free(&tmp); - if (ctx->srp_session) - srp_session_delete(ctx->srp_session); - ctx->srp_session = srp_session_new(HASH_ALGO, SRP_NG_CUSTOM, ascii_n, ascii_g); + int g_size = librist_crypto_srp_authenticator_write_g_bytes(auth_ctx, &outpkt[offset], sizeof(outpkt) -offset); + if (g_size < 0) + return -1; + *tmp_swap = htobe16(g_size); + offset += g_size; + + int n_len = librist_crypto_srp_authenticator_write_n_bytes(auth_ctx, &outpkt[offset], sizeof(outpkt) -offset); + if (n_len < 0) + return -1; + offset += n_len; } } free(bytes_v); @@ -349,36 +329,20 @@ static int process_eap_response_identity(struct eapsrp_ctx *ctx, size_t len, uin ctx->last_identifier++; size_t out_len = offset; out_len -= EAPOL_EAP_HDRS_OFFSET; - return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, out_len, outpkt); + return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, out_len, outpkt, ctx->use_correct_hashing? 1 :0); } static int process_eap_response_client_key(struct eapsrp_ctx *ctx, size_t len, uint8_t pkt[]) { - char *bytes_B; - size_t len_B; - if (ctx->srp_verifier) - srp_verifier_delete(ctx->srp_verifier); - - ctx->srp_verifier = srp_verifier_new(ctx->srp_session, ctx->username, - (const unsigned char*)ctx->salt, ctx->salt_len, - (const unsigned char*)ctx->verifier, ctx->verifier_len, - pkt, len, - (const unsigned char **)&bytes_B, &len_B); - if (!bytes_B || !ctx->srp_verifier) - { - //perm failure set tries to max - ctx->authentication_state = EAP_AUTH_STATE_FAILED; - ctx->tries = 255; - return -255; - } - uint8_t *outpkt = malloc((EAPOL_EAP_HDRS_OFFSET + sizeof(struct eap_srp_hdr) + len_B)); + librist_crypto_srp_authenticator_handle_A(ctx->auth_ctx, pkt, len); + + uint8_t outpkt[1500]; struct eap_srp_hdr *hdr = (struct eap_srp_hdr *)&outpkt[EAPOL_EAP_HDRS_OFFSET]; hdr->type = EAP_TYPE_SRP_SHA1; hdr->subtype = EAP_SRP_SUBTYPE_SERVER_KEY; - memcpy(&outpkt[(EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr))], bytes_B, len_B); + size_t len_B = librist_crypto_srp_authenticator_write_B_bytes(ctx->auth_ctx, &outpkt[(EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr))], sizeof(outpkt) - (EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr))); ctx->last_identifier++; - int ret = send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, (sizeof(struct eap_srp_hdr) + len_B), outpkt); - free(outpkt); + int ret = send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, (sizeof(struct eap_srp_hdr) + len_B), outpkt, ctx->use_correct_hashing? 1 :0); return ret; } @@ -386,14 +350,13 @@ static int process_eap_response_client_validator(struct eapsrp_ctx *ctx, size_t { if (len < (4 + DIGEST_LENGTH)) return EAP_LENERR; - char *bytes_HAMK; - if (!ctx->srp_verifier) { + + if (!ctx->auth_ctx) { ctx->authentication_state = EAP_AUTH_STATE_FAILED; return -254; } - srp_verifier_verify_session(ctx->srp_verifier, &pkt[4], (const unsigned char**)&bytes_HAMK); - if (!bytes_HAMK) - { + + if (librist_crypto_srp_authenticator_verify_m1(ctx->auth_ctx, ctx->username, &pkt[4]) != 0) { rist_log_priv2(ctx->logging_settings, RIST_LOG_WARN, EAP_LOG_PREFIX"Authentication failed for %s@%s\n", ctx->username, ctx->ip_string); ctx->authentication_state = EAP_AUTH_STATE_FAILED; ctx->tries++; @@ -403,22 +366,24 @@ static int process_eap_response_client_validator(struct eapsrp_ctx *ctx, size_t ret = -255; } uint8_t buf[EAPOL_EAP_HDRS_OFFSET]; - send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_FAILURE, ctx->last_identifier, 0, buf); + send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_FAILURE, ctx->last_identifier, 0, buf, ctx->use_correct_hashing? 1 :0); eap_reset_data(ctx); return ret; } + ctx->authenticated = true; + uint8_t outpkt[(EAPOL_EAP_HDRS_OFFSET + sizeof(struct eap_srp_hdr) + 4 + DIGEST_LENGTH)]; struct eap_srp_hdr *hdr = (struct eap_srp_hdr *)&outpkt[EAPOL_EAP_HDRS_OFFSET]; hdr->type = EAP_TYPE_SRP_SHA1; hdr->subtype = EAP_SRP_SUBTYPE_SERVER_VALIDATOR; - memcpy(&outpkt[(EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr) + 4)], bytes_HAMK, DIGEST_LENGTH); + librist_crypto_srp_authenticator_write_M2_bytes(ctx->auth_ctx, &outpkt[(EAPOL_EAP_HDRS_OFFSET + sizeof(*hdr) + 4)]); ctx->last_identifier++; - return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, (sizeof(*hdr) + 4 + DIGEST_LENGTH), outpkt); + return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, (sizeof(*hdr) + 4 + DIGEST_LENGTH), outpkt, ctx->use_correct_hashing? 1 :0); } static int process_eap_response_srp_server_validator(struct eapsrp_ctx *ctx) { - if (srp_verifier_is_authenticated(ctx->srp_verifier)) + if (ctx->authenticated) { if (ctx->authentication_state < EAP_AUTH_STATE_SUCCESS) rist_log_priv2(ctx->logging_settings, RIST_LOG_INFO, EAP_LOG_PREFIX"Successfully authenticated %s@%s\n", ctx->username, ctx->ip_string); @@ -427,13 +392,13 @@ static int process_eap_response_srp_server_validator(struct eapsrp_ctx *ctx) ctx->tries = 0; ctx->last_identifier++; uint8_t buf[EAPOL_EAP_HDRS_OFFSET]; - send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_SUCCESS, ctx->last_identifier, 0, buf); + send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_SUCCESS, ctx->last_identifier, 0, buf, ctx->use_correct_hashing? 1 :0); return 0; } return 0; } -static int process_eap_response(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len) +static int process_eap_response(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len, uint8_t gre_version) { uint8_t type = pkt[0]; ctx->timeout_retries = 0; @@ -441,7 +406,7 @@ static int process_eap_response(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t le ctx->last_pkt_size = 0; ctx->last_pkt = NULL; if (type == EAP_TYPE_IDENTITY) - return process_eap_response_identity(ctx, (len -1), &pkt[1]); + return process_eap_response_identity(ctx, (len -1), &pkt[1], gre_version); if (type == EAP_TYPE_SRP_SHA1) { uint8_t subtype = pkt[1]; @@ -466,7 +431,7 @@ static int process_eap_response(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t le return -1; } -static int process_eap_pkt(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len) +static int process_eap_pkt(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len, uint8_t gre_version) { if (ctx == NULL) return -1; @@ -486,10 +451,10 @@ static int process_eap_pkt(struct eapsrp_ctx *ctx, uint8_t pkt[], size_t len) switch (code) { case EAP_CODE_REQUEST: - return process_eap_request(ctx, &pkt[sizeof(*hdr)], (len - sizeof(*hdr)), identifier); + return process_eap_request(ctx, &pkt[sizeof(*hdr)], (len - sizeof(*hdr)), identifier, gre_version); break; case EAP_CODE_RESPONSE: - return process_eap_response(ctx, &pkt[sizeof(*hdr)], (len - sizeof(*hdr))); + return process_eap_response(ctx, &pkt[sizeof(*hdr)], (len - sizeof(*hdr)), gre_version); break; case EAP_CODE_SUCCESS: //handle eap success @@ -510,7 +475,7 @@ int eap_request_identity(struct eapsrp_ctx *ctx) uint8_t outpkt[EAPOL_EAP_HDRS_OFFSET +1]; outpkt[EAPOL_EAP_HDRS_OFFSET] = EAP_TYPE_IDENTITY; ctx->last_identifier = (uint8_t)(prand_u32() >> 24); - return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, 1, outpkt); + return send_eapol_pkt(ctx, EAPOL_TYPE_EAP, EAP_CODE_REQUEST, ctx->last_identifier, 1, outpkt, ctx->use_correct_hashing? 1 :0); } int eap_start(struct eapsrp_ctx *ctx) @@ -545,18 +510,38 @@ int eap_clone_ctx(struct eapsrp_ctx *in, struct rist_peer *peer) peer->eap_ctx = ctx; ctx->peer = peer; ctx->logging_settings = in->logging_settings; + ctx->use_correct_hashing = true; if (ctx->role == EAP_ROLE_AUTHENTICATOR) { - ctx->authenticator_bytes_salt = malloc(1024); - ctx->authenticator_bytes_verifier = malloc(1024); - ctx->lookup_func = in->lookup_func; + ctx->lookup_func_old = in->lookup_func_old; ctx->lookup_func_userdata = in->lookup_func_userdata; + ctx->lookup_func = in->lookup_func; + ctx->lookup_func_old = in->lookup_func_old; strcpy(ctx->authenticator_username, in->authenticator_username); - if (in->authenticator_len_verifier >0 && in->authenticator_bytes_verifier != NULL) +#if HAVE_MBEDTLS + if (in->authenticator_len_verifier_old >0 && in->authenticator_bytes_verifier_old != NULL) { + ctx->authenticator_bytes_verifier_old = malloc(in->authenticator_len_verifier_old); + memcpy(ctx->authenticator_bytes_verifier_old, in->authenticator_bytes_verifier_old, in->authenticator_len_verifier_old); + ctx->authenticator_len_verifier_old = in->authenticator_len_verifier_old; + } + + if (in->authenticator_len_salt_old > 0 && in->authenticator_bytes_salt_old != NULL) { + ctx->authenticator_bytes_salt_old = malloc(in->authenticator_len_salt_old ); + memcpy(ctx->authenticator_bytes_salt_old, in->authenticator_bytes_salt_old, in->authenticator_len_salt_old); + ctx->authenticator_len_salt_old = in->authenticator_len_salt_old; + } +#endif + if (in->authenticator_len_verifier >0 && in->authenticator_bytes_verifier != NULL) { + ctx->authenticator_bytes_verifier = malloc(in->authenticator_len_verifier); memcpy(ctx->authenticator_bytes_verifier, in->authenticator_bytes_verifier, in->authenticator_len_verifier); - if (in->authenticator_len_salt > 0 && in->authenticator_bytes_salt != NULL) + ctx->authenticator_len_verifier = in->authenticator_len_verifier; + } + + if (in->authenticator_len_salt > 0 && in->authenticator_bytes_salt != NULL) { + ctx->authenticator_bytes_salt= malloc(in->authenticator_len_salt ); memcpy(ctx->authenticator_bytes_salt, in->authenticator_bytes_salt, in->authenticator_len_salt); - ctx->authenticator_len_salt = in->authenticator_len_salt; + ctx->authenticator_len_salt = in->authenticator_len_salt; + } ctx->authenticator_len_verifier = in->authenticator_len_verifier; if (!ctx->last_pkt) eap_request_identity(ctx);//immediately request identity @@ -581,7 +566,7 @@ void eap_delete_ctx(struct eapsrp_ctx **in) *in = NULL; } -int eap_process_eapol(struct eapsrp_ctx* ctx, uint8_t pkt[], size_t len) +int eap_process_eapol(struct eapsrp_ctx* ctx, uint8_t pkt[], size_t len, uint8_t gre_version) { assert(ctx != NULL); struct eapol_hdr *hdr = (struct eapol_hdr *)pkt; @@ -591,7 +576,7 @@ int eap_process_eapol(struct eapsrp_ctx* ctx, uint8_t pkt[], size_t len) switch (hdr->eaptype) { case EAPOL_TYPE_EAP: - return process_eap_pkt(ctx, &pkt[sizeof(*hdr)], body_len); + return process_eap_pkt(ctx, &pkt[sizeof(*hdr)], body_len, gre_version); break; case EAPOL_TYPE_START: if (ctx->role == EAP_ROLE_AUTHENTICATOR && !ctx->last_pkt) @@ -638,6 +623,15 @@ void eap_periodic(struct eapsrp_ctx *ctx) } } else if (ctx->role == EAP_ROLE_AUTHENTICATOR && ctx->authentication_state == EAP_AUTH_STATE_SUCCESS && now > ctx->last_auth_timestamp + reauth_period) { + if (ctx->generation > 0) { + uint64_t generation = ctx->generation; + //If our cached data matches whatever lookup function would return re-auth is pointless. + ctx->lookup_func(ctx->username, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &generation, ctx->lookup_func_userdata); + if (generation == ctx->generation) { + ctx->last_auth_timestamp = now; + return; + } + } ctx->authentication_state = EAP_AUTH_STATE_REAUTH; eap_request_identity(ctx); return; @@ -663,6 +657,8 @@ static void internal_user_verifier_lookup(char * username, bool *use_default_2048_bit_n_modulus, char **n_modulus_ascii, char **generator_ascii, + int *hashversion, + uint64_t *generation, void *user_data) { (void)n_modulus_ascii; @@ -670,21 +666,39 @@ static void internal_user_verifier_lookup(char * username, if (user_data == NULL) return; + if (*generation == 1) + return; + //This is static data so it can be permanently cached + *generation = 1; + struct eapsrp_ctx *ctx = (struct eapsrp_ctx *)user_data; - char *decoded_verifier = malloc(1024); - char *decoded_salt = malloc(1024); + char *decoded_verifier = NULL; + char *decoded_salt = NULL; if (strcmp(username, ctx->authenticator_username) != 0) goto fail_decode; - memcpy(decoded_verifier, ctx->authenticator_bytes_verifier, ctx->authenticator_len_verifier); - memcpy(decoded_salt, ctx->authenticator_bytes_salt, ctx->authenticator_len_salt); - + if (*hashversion == 0 && HAVE_MBEDTLS) { +#if HAVE_MBEDTLS + decoded_verifier = malloc(ctx->authenticator_len_verifier_old); + decoded_salt = malloc(ctx->authenticator_len_salt_old); + memcpy(decoded_verifier, ctx->authenticator_bytes_verifier_old, ctx->authenticator_len_verifier_old); + memcpy(decoded_salt, ctx->authenticator_bytes_salt_old, ctx->authenticator_len_salt_old); + *verifier_len = ctx->authenticator_len_verifier_old; + *salt_len = ctx->authenticator_len_salt_old; +#endif + } else { + decoded_verifier = malloc(ctx->authenticator_len_verifier); + decoded_salt = malloc(ctx->authenticator_len_salt); + memcpy(decoded_verifier, ctx->authenticator_bytes_verifier, ctx->authenticator_len_verifier); + memcpy(decoded_salt, ctx->authenticator_bytes_salt, ctx->authenticator_len_salt); + *verifier_len = ctx->authenticator_len_verifier; + *salt_len = ctx->authenticator_len_salt; + } *verifier = decoded_verifier; - *verifier_len = ctx->authenticator_len_verifier; *salt = decoded_salt; - *salt_len = ctx->authenticator_len_salt; + *use_default_2048_bit_n_modulus = true; goto out; @@ -697,9 +711,24 @@ out: return; } -//PUBLIC -int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_t lookup_func, void *userdata) +static void old_user_verifier_lookup_wrapper(char * username, + size_t *verifier_len, char **verifier, + size_t *salt_len, char **salt, + bool *use_default_2048_bit_n_modulus, + char **n_modulus_ascii, + char **generator_ascii, + int *hashversion, + uint64_t *generation, + void *user_data) { + *hashversion = 0; + *generation = 0; + struct eapsrp_ctx *ctx = (struct eapsrp_ctx *)user_data; + ctx->lookup_func_old(username, verifier_len, verifier, salt_len, salt, use_default_2048_bit_n_modulus, n_modulus_ascii, generator_ascii, user_data); +} + +//PUBLIC +int rist_enable_eap_srp_2(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_2_t lookup_func, void *userdata) { if (!peer) return RIST_ERR_NULL_PEER; struct rist_common_ctx *cctx = get_cctx(peer); @@ -721,13 +750,14 @@ int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char return RIST_ERR_INVALID_STRING_LENGTH; } lookup_func = internal_user_verifier_lookup; - struct SRPSession * session = srp_session_new(SRP_SHA256, SRP_NG_2048, NULL, NULL); + const char *n = NULL; + const char *g = NULL; + assert(librist_get_ng_constants(LIBRIST_SRP_NG_2048, &n, &g) ==0); +#if HAVE_MBEDTLS + assert(librist_crypto_srp_create_verifier(n, g, username, password, &ctx->authenticator_bytes_salt_old, &ctx->authenticator_len_salt_old, &ctx->authenticator_bytes_verifier_old, &ctx->authenticator_len_verifier_old, false) ==0); +#endif + assert(librist_crypto_srp_create_verifier(n, g, username, password, &ctx->authenticator_bytes_salt, &ctx->authenticator_len_salt, &ctx->authenticator_bytes_verifier, &ctx->authenticator_len_verifier, true) ==0); strcpy(ctx->authenticator_username, username); - srp_create_salted_verification_key(session, username, - (const unsigned char *)password, strlen(password), - (const unsigned char **)&ctx->authenticator_bytes_salt, &ctx->authenticator_len_salt, - (const unsigned char **)&ctx->authenticator_bytes_verifier, &ctx->authenticator_len_verifier); - srp_session_delete(session); userdata = (void *)ctx; rist_log_priv2(ctx->logging_settings, RIST_LOG_INFO, EAP_LOG_PREFIX"EAP Authentication enabled, role = authenticator, single user\n"); } @@ -767,6 +797,22 @@ int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char strcpy(ctx->password, password); peer->eap_ctx = ctx; rist_log_priv2(ctx->logging_settings, RIST_LOG_INFO, EAP_LOG_PREFIX"EAP Authentication enabled, role = authenticatee\n"); + ctx->use_correct_hashing = true; eap_start(ctx); return 0; } + +int rist_enable_eap_srp(struct rist_peer *peer, const char *username, const char *password, user_verifier_lookup_t lookup_func, void *userdata) +{ + if (!peer) + return RIST_ERR_NULL_PEER; + + user_verifier_lookup_2_t pass_lookup = lookup_func? old_user_verifier_lookup_wrapper : NULL; + int ret = rist_enable_eap_srp_2(peer, username, password, pass_lookup, NULL); + if (ret == 0) { + peer->eap_ctx->lookup_func_old = lookup_func; + peer->eap_ctx->lookup_func_userdata = peer->eap_ctx; + peer->eap_ctx->lookup_func_userdata_old = userdata; + } + return ret; +} diff --git a/src/eap.h b/src/eap.h index 6d1958cbe78665081a3d7c2f26fb3483f1bb129c..e77469c3454370c58fcb2fbb7576fc460111c3da 100644 --- a/src/eap.h +++ b/src/eap.h @@ -9,8 +9,8 @@ #define _EAP_H_ #include "common/attributes.h" - -#include "srp.h" +#include "config.h" +#include "crypto/srp.h" #include "librist/librist_srp.h" #include <stdint.h> #include <stddef.h> @@ -90,29 +90,32 @@ struct eapsrp_ctx char username[256]; char password[256]; - char *salt; - size_t salt_len; - char *verifier; - size_t verifier_len; - bool default_2048_ng; - char *ascii_n; - char *ascii_g; - - user_verifier_lookup_t lookup_func; + uint64_t generation; + struct librist_crypto_srp_authenticator_ctx *auth_ctx; + struct librist_crypto_srp_client_ctx *client_ctx; + bool authenticated; + user_verifier_lookup_t lookup_func_old; + user_verifier_lookup_2_t lookup_func; + void *lookup_func_userdata_old; void *lookup_func_userdata; - struct SRPSession *srp_session; - struct SRPUser *srp_user; - struct SRPVerifier *srp_verifier; struct rist_peer *peer; char ip_string[46]; struct rist_logging_settings *logging_settings; // authenticator data (single user mode) char authenticator_username[256]; +#if HAVE_MBEDTLS + size_t authenticator_len_verifier_old; + uint8_t *authenticator_bytes_verifier_old; + size_t authenticator_len_salt_old; + uint8_t *authenticator_bytes_salt_old; +#endif size_t authenticator_len_verifier; - char *authenticator_bytes_verifier; + uint8_t *authenticator_bytes_verifier; size_t authenticator_len_salt; - char *authenticator_bytes_salt; + uint8_t *authenticator_bytes_salt; + + bool use_correct_hashing; }; #define EAP_LENERR -1 @@ -121,7 +124,7 @@ struct eapsrp_ctx #define EAP_UNEXPECTEDREQUEST -4 #define EAP_SRP_WRONGSUBTYPE -4 -RIST_PRIV int eap_process_eapol(struct eapsrp_ctx* ctx, uint8_t pkt[], size_t len); +RIST_PRIV int eap_process_eapol(struct eapsrp_ctx* ctx, uint8_t pkt[], size_t len, uint8_t gre_version); RIST_PRIV int eap_request_identity(struct eapsrp_ctx *ctx); RIST_PRIV int eap_start(struct eapsrp_ctx *ctx); RIST_PRIV void eap_periodic(struct eapsrp_ctx *ctx); diff --git a/src/rist-common.c b/src/rist-common.c index 6724b509b542c9b40a9c8e5895f2e649e67550fa..63f95c01eba74a64ee51d68cc84a972a3a47da9f 100755 --- a/src/rist-common.c +++ b/src/rist-common.c @@ -16,7 +16,7 @@ #include "endian-shim.h" #include "time-shim.h" #include <sys/types.h> -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT #include "eap.h" #endif #include "mpegts.h" @@ -2391,7 +2391,7 @@ static void rist_peer_recv(struct evsocket_ctx *evctx, int fd, short revents, vo struct rist_buffer payload = { .data = NULL, .size = 0, .type = 0 }; uint32_t flow_id = 0; uint16_t gre_proto = 0; - + uint8_t rist_gre_version = 1; if (cctx->profile > RIST_PROFILE_SIMPLE) { struct rist_gre_hdr *gre = NULL; @@ -2407,7 +2407,7 @@ static void rist_peer_recv(struct evsocket_ctx *evctx, int fd, short revents, vo uint8_t has_checksum = CHECK_BIT(gre->flags1, 7); uint8_t has_key = CHECK_BIT(gre->flags1, 5); uint8_t has_seq = CHECK_BIT(gre->flags1, 4); - uint8_t rist_gre_version = (gre->flags2 >> 3) & 0x7; + rist_gre_version = (gre->flags2 >> 3) & 0x7; if (recv_bufsize < (sizeof(*gre) + has_checksum*4 + has_key *4 + has_seq *4)) { rist_log_priv(get_cctx(peer), RIST_LOG_ERROR, "Packet too small: %d bytes, ignoring ...\n", recv_bufsize); @@ -2593,7 +2593,7 @@ protocol_bypass: p->event_recv = peer->event_recv; char incoming_ip_string_buffer[INET6_ADDRSTRLEN]; char *incoming_ip_string = get_ip_str(&p->u.address, &incoming_ip_string_buffer[0], INET6_ADDRSTRLEN); - #if HAVE_MBEDTLS + #if HAVE_SRP_SUPPORT eap_clone_ctx(peer->eap_ctx, p); eap_set_ip_string(p->eap_ctx, incoming_ip_string_buffer); #endif @@ -2728,7 +2728,7 @@ protocol_bypass: payload.dst_port = p->local_port; } //rist_log_priv(get_cctx(peer), RIST_LOG_INFO, "Port is %d !!!!!\n", addr4.sin_port); -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT if (payload.type != RIST_PAYLOAD_TYPE_EAPOL && p->eap_ctx && p->eap_ctx->authentication_state < EAP_AUTH_STATE_SUCCESS) { if (now > (p->log_repeat_timer + RIST_LOG_QUIESCE_TIMER)) { @@ -2792,15 +2792,15 @@ protocol_bypass: } break; case RIST_PAYLOAD_TYPE_EAPOL: -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT if (p->eap_ctx == NULL) { rist_log_priv(get_cctx(p), RIST_LOG_ERROR, "EAP authentication requested but credentials have not been configured!\n"); } else { int eapret = 0; if ((eapret = eap_process_eapol(p->eap_ctx, - (void *)(recv_buf + payload_offset), - (recv_bufsize - payload_offset))) < 0) { + (recv_buf + payload_offset), + (recv_bufsize - payload_offset), rist_gre_version)) < 0) { rist_log_priv(get_cctx(p), RIST_LOG_ERROR, "Failed to process EAPOL pkt, return code: %i\n", eapret); if (eapret == 255)//permanent failure, we allow a few retries failed_eap = true; @@ -3069,7 +3069,7 @@ static void sender_peer_events(struct rist_sender *ctx, uint64_t now) rist_peer_rtcp(NULL, peer); } } -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT if (!peer->listening || peer->parent) eap_periodic(peer->eap_ctx); #endif @@ -3424,7 +3424,7 @@ int rist_peer_remove(struct rist_common_ctx *ctx, struct rist_peer *peer, struct } _librist_crypto_psk_rist_key_destroy(&peer->key_rx); _librist_crypto_psk_rist_key_destroy(&peer->key_tx); -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT eap_delete_ctx(&peer->eap_ctx); #endif if (peer->url) @@ -3612,7 +3612,7 @@ void receiver_peer_events(struct rist_receiver *ctx, uint64_t now) rist_peer_rtcp(NULL, p); } } -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT if (!p->listening && p->parent) eap_periodic(p->eap_ctx); #endif diff --git a/src/udp.c b/src/udp.c index 3650eb1dbd103db16c31f48b35387f10ec68d9c9..70852862e2bf7bd98cfcc8f2bfe3b13bb383b8c2 100755 --- a/src/udp.c +++ b/src/udp.c @@ -12,7 +12,7 @@ #include "log-private.h" #include "socket-shim.h" #include "endian-shim.h" -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT #include "eap.h" #endif #include "crypto/psk.h" @@ -944,7 +944,7 @@ peer_select: if (!peer->is_data || peer->parent) continue; -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT if (!peer->listening && !eap_is_authenticated(peer->eap_ctx)) continue; #endif @@ -969,7 +969,7 @@ peer_select: if (peer->listening) { struct rist_peer *child = peer->child; while (child) { -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT if (!eap_is_authenticated(child->eap_ctx)) { //do nothing @@ -1001,7 +1001,7 @@ peer_select: if (peer->listening) { struct rist_peer *child = peer->child; while (child) { -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT if (!eap_is_authenticated(child->eap_ctx)) { //do nothing @@ -1059,7 +1059,7 @@ ssize_t rist_retry_dequeue(struct rist_sender *ctx) // If they request a non-sense seq number, we will catch it when we check the seq number against // the one on that buffer position and it does not match - + size_t idx = rist_sender_index_get(ctx, retry->seq); if (RIST_UNLIKELY(ctx->sender_queue[idx] == NULL)) { rist_log_priv(&ctx->common, RIST_LOG_DEBUG, diff --git a/test/meson.build b/test/meson.build index 9ba1733de7176c258500058ff788cc64fdf73f9d..20a5534e2e1563ae4f36d6557e91cf285284436e 100644 --- a/test/meson.build +++ b/test/meson.build @@ -1,12 +1,4 @@ # librist. Copyright (c) 2020 SipRadius LLC. All right reserved. # SPDX-License-Identifier: BSD-2-Clause -all_test_deps = [] -all_test_dep_libs = [] -project_test_sources = [] - -test_deps = [] - -test_dep_libs = [] - subdir('rist') \ No newline at end of file diff --git a/test/rist/example-test.c b/test/rist/example-test.c deleted file mode 100644 index 31d3955e71877883a97ad0bfaabf6f65af1ac789..0000000000000000000000000000000000000000 --- a/test/rist/example-test.c +++ /dev/null @@ -1,26 +0,0 @@ -/* librist. Copyright © 2020 SipRadius LLC. All right reserved. - * Author: Gijs Peskens <gijs@in2ip.nl> - * Author: Sergio Ammirata, Ph.D. <sergio@ammirata.net> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include <assert.h> -#include "librist.h" -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <stdint.h> -#include <cmocka.h> - -static void basic_test(void** state) { - (void)state; - assert(1 == 1); -} - -int main(void) { - const struct CMUnitTest tests[] = { - cmocka_unit_test(basic_test) - }; - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/test/rist/meson.build b/test/rist/meson.build index 893824b7cb697058ac30585528e32599d40182aa..e49b7be4c2b4eb310b15b4d28ea24b80cc3f2275 100644 --- a/test/rist/meson.build +++ b/test/rist/meson.build @@ -1,27 +1,7 @@ # librist. Copyright (c) 2020 SipRadius LLC. All right reserved. # SPDX-License-Identifier: BSD-2-Clause -risttest_sources = [ - 'example-test.c' -] - -cmocka = meson.get_compiler('c').find_library('cmocka', required: false) -risttest_deps = [ - cmocka -] - -risttest_lib_deps = [ - librist -] -comockatests = cmocka.found() -if cmocka.found() - risttest = executable('risttest', - risttest_sources, - include_directories : inc, - dependencies : [risttest_deps,test_deps], - link_with : [risttest_lib_deps, test_dep_libs]) - -endif +subdir('unit') extra_sources = ['../../contrib/time-shim.c','../../contrib/pthread-shim.c'] @@ -41,10 +21,6 @@ test_send_receive = executable('test_send_receive', ]) -if comockatests - test('rist test', risttest) -endif - ###Simple profile tests #Unicast test('Simple profile unicast', test_send_receive, args: ['0', 'rist://@127.0.0.1:1234', 'rist://127.0.0.1:1234', '0'], suite: ['simple', 'unicast']) @@ -74,7 +50,7 @@ test('Main profile encryption receive server mode, sender client mode unencrypte test('Main profile encryption client mode unencrypted, sender server mode', test_send_receive, args: ['1', 'rist://127.0.0.1:6005', 'rist://@127.0.0.1:6005?secret=12345678&aes-type=128', '0'], should_fail: true) test('Main profile encryption client mode, sender server mode unencrypted', test_send_receive, args: ['1', 'rist://127.0.0.1:6006?secret=12345678&aes-type=128', 'rist://@127.0.0.1:6006', '0'], should_fail: true) #Test SRP Auth -if use_mbedtls +if have_srp test('Main profile encryption receive client mode, sender server mode, SRP auth', test_send_receive, args: ['1', 'rist://127.0.0.1:6008?secret=12345678&aes-type=128&username=testuser&password=testpassword', 'rist://@127.0.0.1:6008?secret=12345678&aes-type=128&username=testuser&password=testpassword', '0'],suite: ['main', 'unicast', 'server', 'encryption', 'srp'], should_fail: false) test('Main profile encryption receive client mode, sender server mode, SRP auth, client no SRP', test_send_receive, args: ['1', 'rist://127.0.0.1:6009?secret=12345678&aes-type=128', 'rist://@127.0.0.1:6009?secret=12345678&aes-type=128&username=testuser&password=testpassword', '0'], suite: ['main', 'unicast', 'server', 'encryption', 'srp'], should_fail: true) test('Main profile encryption receive client mode, sender server mode, SRP auth, server no SRP', test_send_receive, args: ['1', 'rist://127.0.0.1:6010?secret=12345678&aes-type=128&username=testuser&password=testpassword', 'rist://@127.0.0.1:6010?secret=12345678&aes-type=128', '0'], suite: ['main', 'unicast', 'server', 'encryption', 'srp'], should_fail: true) diff --git a/test/rist/test_send_receive.c b/test/rist/test_send_receive.c index ce31bae157e8a040f3e48be8f5a3d34b2735257e..8eb92279dbd4755b287f5c96c3abdaca6bfffefb 100644 --- a/test/rist/test_send_receive.c +++ b/test/rist/test_send_receive.c @@ -56,11 +56,11 @@ struct rist_ctx *setup_rist_receiver(int profile, const char *url) { rist_log(logging_settings_receiver, RIST_LOG_ERROR, "Could not add peer connector to receiver\n"); return NULL; } -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT if (strlen(peer_config->srp_username) > 0 && strlen(peer_config->srp_password) > 0) { int srp_error = - rist_enable_eap_srp(peer, peer_config->srp_username, + rist_enable_eap_srp_2(peer, peer_config->srp_username, peer_config->srp_password, NULL, NULL); if (srp_error) rist_log(logging_settings_receiver, RIST_LOG_WARN, @@ -95,11 +95,11 @@ struct rist_ctx *setup_rist_sender(int profile, const char *url) { return NULL; } -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT if (strlen(peer_config_link->srp_username) > 0 && strlen(peer_config_link->srp_password) > 0) { int srp_error = - rist_enable_eap_srp(peer, peer_config_link->srp_username, + rist_enable_eap_srp_2(peer, peer_config_link->srp_username, peer_config_link->srp_password, NULL, NULL); if (srp_error) rist_log(logging_settings_sender, RIST_LOG_WARN, diff --git a/test/rist/unit/meson.build b/test/rist/unit/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..93cae81c0e44ae1dfe70f5234ca12f0d26897b4f --- /dev/null +++ b/test/rist/unit/meson.build @@ -0,0 +1,14 @@ +cmocka = meson.get_compiler('c').find_library('cmocka', required: false) + +if cmocka.found() + if have_srp + srp_unit = executable('srp_unit', rev_target, + 'srp_examples.c', + '../../../contrib/pthread-shim.c', + include_directories : inc, + dependencies : [threads, cmocka,crypto_deps], + ) + + test('srp_unit_test', srp_unit, suite:['unit']) + endif +endif \ No newline at end of file diff --git a/test/rist/unit/srp_examples.c b/test/rist/unit/srp_examples.c new file mode 100644 index 0000000000000000000000000000000000000000..1c5193d20258c6c58fb4c5a978a8a90c130d6177 --- /dev/null +++ b/test/rist/unit/srp_examples.c @@ -0,0 +1,433 @@ +//This set of unit tests covers the entire SRP flow verified against the example in the VSF document + +#include "config.h" +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <stdint.h> +#include <assert.h> +#include <cmocka.h> +#include <stdio.h> +#include <stdlib.h> +#include "librist/librist_config.h" + +#include "src/crypto/srp.h" +#include "src/crypto/srp_constants.h" +#define DEBUG_USE_EXAMPLE_CONSTANTS 1 + +#if HAVE_MBEDTLS +#define malloc(size) _test_malloc(size, __FILE__, __LINE__) +#define calloc(num, size) _test_calloc(num, size, __FILE__, __LINE__) +#define free(obj) _test_free(obj, __FILE__, __LINE__) +#endif + +#include "src/crypto/srp.c" +#include "src/crypto/srp_constants.c" + +static void hexstr_to_uint(const char *hexstr, uint8_t *buf, size_t buf_len) { + for (size_t i = 0, j = 0; j < buf_len; i += 2, j++) + buf[j] = (hexstr[i] % 32 + 9) % 25 * 16 + (hexstr[i + 1] % 32 + 9) % 25; +} + +static void uint_to_hex(const uint8_t *buf, size_t buf_len, char *outbuf) { + size_t j; + for (j = 0; j < buf_len; j++) { + outbuf[2 * j] = (buf[j] >> 4) + 48; + outbuf[2 * j + 1] = (buf[j] & 15) + 48; + if (outbuf[2 * j] > 57) + outbuf[2 * j] += 7; + if (outbuf[2 * j + 1] > 57) + outbuf[2 * j + 1] += 7; + } + outbuf[2 * j] = '\0'; +} + +struct srp_test_state { + const char *n; + const char *g; + uint8_t *salt; + size_t salt_len; + uint8_t *incorrect_hash_verifier; + uint8_t *correct_hash_verifier; + size_t verifier_len; + struct librist_crypto_srp_authenticator_ctx *wrong_hash_authenticator; + struct librist_crypto_srp_authenticator_ctx *correct_hash_authenticator; + struct librist_crypto_srp_client_ctx *wrong_hash_client; + struct librist_crypto_srp_client_ctx *correct_hash_client; +}; + +static int srp_test_state_setup(void **state) { + *state = calloc(sizeof(struct srp_test_state), 1); + struct srp_test_state *s = *state; + librist_get_ng_constants(LIBRIST_SRP_NG_512, &s->n, &s->g); +#if HAVE_MBEDTLS + librist_crypto_srp_create_verifier(s->n, s->g, "rist", "mainprofile", &s->salt, &s->salt_len, &s->incorrect_hash_verifier, &s->verifier_len, false); + s->wrong_hash_authenticator = librist_crypto_srp_authenticator_ctx_create(s->n, s->g, s->incorrect_hash_verifier, s->verifier_len, s->salt, s->salt_len, false); + size_t v_len = s->verifier_len; + free(s->salt); + s->salt = NULL; +#endif + librist_crypto_srp_create_verifier(s->n, s->g, "rist", "mainprofile", &s->salt, &s->salt_len, &s->correct_hash_verifier, &s->verifier_len, true); +#if HAVE_MBEDTLS + assert(v_len == s->verifier_len); +#endif + s->correct_hash_authenticator = librist_crypto_srp_authenticator_ctx_create(s->n, s->g, s->correct_hash_verifier, s->verifier_len, s->salt, s->salt_len, true); + + + const char N_hex[] = "D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3"; + uint8_t N[(sizeof(N_hex) -1)/2]; + hexstr_to_uint(N_hex, N, sizeof(N)); + uint8_t g[1] = {0x02}; +#if HAVE_MBEDTLS + s->wrong_hash_client = librist_crypto_srp_client_ctx_create(false, N, sizeof(N), g, sizeof(g), s->salt, s->salt_len, false); +#endif + s->correct_hash_client = librist_crypto_srp_client_ctx_create(false, N, sizeof(N), g, sizeof(g), s->salt, s->salt_len, true); + return 0; +} + +static int srp_test_state_teardown(void **state) { + struct srp_test_state *s = *state; + free(s->salt); + free(s->incorrect_hash_verifier); + free(s->correct_hash_verifier); + librist_crypto_srp_authenticator_ctx_free(s->wrong_hash_authenticator); + librist_crypto_srp_authenticator_ctx_free(s->correct_hash_authenticator); + librist_crypto_srp_client_ctx_free(s->wrong_hash_client); + librist_crypto_srp_client_ctx_free(s->correct_hash_client); + free(s); + return 0; +} + +static void test_hash_func(void **state) { + (void)(state); + //expected hash gather via: `echo -n "rist:mainprofile" | sha256sum | awk '{print toupper($1)}'` + const char expected_hash[] = "8427F6E0E69DC9B99DFE1052DDAF7E50D4FEA316C63C6AD23FE197C9C1DA2AF1"; + const char test_string[] = "rist:mainprofile"; + uint8_t hash_data[SHA256_DIGEST_LENGTH]; + assert_int_equal(librist_crypto_srp_hash((const uint8_t *)test_string, sizeof(test_string) -1, hash_data), 0); + char outhash[sizeof(expected_hash)]; + uint_to_hex(hash_data, sizeof(hash_data), outhash); + assert_string_equal(outhash, expected_hash); +} + +static void test_hash_update_func(void **state) { + (void)(state); + const char expected_hash[] = "8427F6E0E69DC9B99DFE1052DDAF7E50D4FEA316C63C6AD23FE197C9C1DA2AF1"; + HASH_CONTEXT ctx; + HASH_CONTEXT_INIT(&ctx, true); + assert_int_equal(librist_crypto_srp_hash_update(&ctx, "rist", strlen("rist")), 0); + assert_int_equal(librist_crypto_srp_hash_update(&ctx, ":", 1), 0); + assert_int_equal(librist_crypto_srp_hash_update(&ctx, "mainprofile", strlen("mainprofile")), 0); + uint8_t hash_data[SHA256_DIGEST_LENGTH]; + assert_int_equal(librist_crypto_srp_hash_final(&ctx, hash_data), 0); + char outhash[sizeof(expected_hash)]; + uint_to_hex(hash_data, sizeof(hash_data), outhash); + assert_string_equal(outhash, expected_hash); +} + +static void test_get_default_ng(void **state) { + (void)(state); + const char *n = NULL; + const char *g = NULL; + assert_int_equal(librist_get_ng_constants(LIBRIST_SRP_NG_DEFAULT, &n, &g), 0); + assert_string_equal(n, + "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4" + "A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60" + "95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF" + "747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B907" + "8717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB37861" + "60279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DB" + "FBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73" + ); + assert_string_equal(g, "2"); + + //This N,g pair is used in the VSF example flow. + n = NULL; + g = NULL; + assert_int_equal(librist_get_ng_constants(LIBRIST_SRP_NG_512, &n, &g), 0); + assert_string_equal(n, "D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3"); + assert_string_equal(g, "2"); +} + +#if HAVE_MBEDTLS +static void test_srp_wrong_hashing_verifier_create(void **state) { + struct srp_test_state *s = *state; + const char sample_salt[] = "72F9D5383B7EB7599FB63028F47475B60A55F313D40E0BE023E026C97C0A2C32"; + const char sample_verifier[] = "557EA208F87A23C28936423EC16ABE6BD959933DFBEFC0B36EBD9335DE3997C97DDFA081D64CFBC6EFBFD5BE19F2ED9F77922FD7E88BBA6C6B310A9018EC4305"; + + uint8_t *salt = NULL; + size_t salt_len = 0; + uint8_t *verifier = NULL; + size_t verifier_len = 0; + assert_int_equal(librist_crypto_srp_create_verifier(s->n, s->g, "rist", "mainprofile", &salt, &salt_len, &verifier, &verifier_len, false), 0); + + assert_int_equal(verifier_len, (sizeof(sample_verifier) -1)/2); + assert_int_equal(salt_len, (sizeof(sample_salt) -1)/2); + + char salt_hex[sizeof(sample_salt)]; + uint_to_hex(salt, salt_len, salt_hex); + assert_string_equal(salt_hex, sample_salt); + + char verifier_hex[sizeof(sample_verifier)]; + uint_to_hex(verifier, verifier_len, verifier_hex); + assert_string_equal(sample_verifier, verifier_hex); + free(verifier); + free(salt); +} + +static void test_srp_wrong_hashing_auth_ctx_create(void **state) { + struct srp_test_state *s = *state; + struct librist_crypto_srp_authenticator_ctx * ctx = librist_crypto_srp_authenticator_ctx_create(s->n, s->g, s->incorrect_hash_verifier, s->verifier_len, s->salt, s->salt_len, false); + assert_non_null(ctx); + + const char well_known_n[] = "D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3"; + uint8_t n[(sizeof(well_known_n) -1)/2]; + uint8_t g[1]; + + assert_int_equal(librist_crypto_srp_authenticator_write_n_bytes(ctx, n, sizeof(n)), sizeof(n)); + assert_int_equal(librist_crypto_srp_authenticator_write_g_bytes(ctx, g, sizeof(g)), sizeof(g)); + + char n_hex[sizeof(well_known_n)]; + char g_hex[sizeof("02")]; + + uint_to_hex(n, sizeof(n), n_hex); + assert_string_equal(n_hex, well_known_n); + + uint_to_hex(g, sizeof(g), g_hex); + assert_string_equal(g_hex, "02"); + + librist_crypto_srp_authenticator_ctx_free(ctx); +} + +static void test_srp_wrong_hashing_auth_handle_A(void **state) { + struct srp_test_state *s = *state; + const char client_A_hex[] = "92C4CEFB95A1AE2E576A252B19273FD4613F44FDA4AC8CC84A089D5740756223943882BAD34CB55F35139CDDB60E0D19ACD2B884CFB27F53C8EA969269ABE014"; + uint8_t client_A[(sizeof(client_A_hex) -1)/2]; + hexstr_to_uint(client_A_hex, client_A, sizeof(client_A)); + assert_int_equal(librist_crypto_srp_authenticator_handle_A(s->wrong_hash_authenticator, client_A, sizeof(client_A)), 0); + + const char expected_B[] = "85CAE0C578E6927B78BEB173FB0F9BFC8ECB4C13542BB8BE3B0F3447B3764A234177E22D180DCAD21F33302248B7452916DC58ABD309C8A77440A228B8516A4E"; + + uint8_t B[(sizeof(expected_B) -1)/2]; + assert_int_equal(librist_crypto_srp_authenticator_write_B_bytes(s->wrong_hash_authenticator, B, sizeof(B)), sizeof(B)); + + char B_hex[sizeof(expected_B)]; + uint_to_hex(B, sizeof(B), B_hex); + assert_string_equal(expected_B, B_hex); +} + +static void test_srp_wrong_hashing_auth_verify_M1(void **state) { + struct srp_test_state *s = *state; + const char client_M1_hex[] = "EBFC2D79BEB3CBF7BA83C27E2B51524F8CD3F3B2C4804815AD2516D465DF80C9"; + uint8_t client_M1[(sizeof(client_M1_hex) -1)/2]; + hexstr_to_uint(client_M1_hex, client_M1, sizeof(client_M1)); + + assert_int_equal(librist_crypto_srp_authenticator_verify_m1(s->wrong_hash_authenticator, "rist", client_M1), 0); + + const char expected_m2[] = "FB14D73B5ACBBA101E5A799F80EBCBB43D83890E23DED979110EEFF109C0441A"; + char m2_hex[sizeof(expected_m2)]; + uint8_t m2[SHA256_DIGEST_LENGTH]; + + librist_crypto_srp_authenticator_write_M2_bytes(s->wrong_hash_authenticator, m2); + + uint_to_hex(m2, sizeof(m2), m2_hex); + + assert_string_equal(m2_hex, expected_m2); +} +#endif + +//Nothing in client creation relies on hashing, hence this test isn't doubled +static void test_srp_client_ctx_create(void **state) { + (void)(state); + const char salt_hex[] = "72F9D5383B7EB7599FB63028F47475B60A55F313D40E0BE023E026C97C0A2C32"; + + uint8_t salt[(sizeof(salt_hex) -1)/2]; + hexstr_to_uint(salt_hex, salt, sizeof(salt)); + + struct librist_crypto_srp_client_ctx *ctx = librist_crypto_srp_client_ctx_create(true, NULL, 0, NULL, 0, salt, sizeof(salt), true); + assert_non_null(ctx); + librist_crypto_srp_client_ctx_free(ctx); + + const char N_hex[] = "D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3"; + uint8_t N[(sizeof(N_hex) -1)/2]; + hexstr_to_uint(N_hex, N, sizeof(N)); + uint8_t g[1] = {0x02}; + ctx = librist_crypto_srp_client_ctx_create(false, N, sizeof(N), g, sizeof(g), salt, sizeof(salt), true); + + const char expected_A[] = "92C4CEFB95A1AE2E576A252B19273FD4613F44FDA4AC8CC84A089D5740756223943882BAD34CB55F35139CDDB60E0D19ACD2B884CFB27F53C8EA969269ABE014"; + uint8_t A[(sizeof(expected_A)-1)/2]; + assert_int_equal(librist_crypto_srp_client_write_A_bytes(ctx, A, sizeof(A)), sizeof(A)); + + char a_hex[sizeof(expected_A)]; + uint_to_hex(A, sizeof(A), a_hex); + assert_string_equal(a_hex, expected_A); + librist_crypto_srp_client_ctx_free(ctx); +} + +#if HAVE_MBEDTLS + +static void test_srp_wrong_hashing_client_handle_B(void **state) { + struct srp_test_state *ctx = *state; + const char server_B[] = "85CAE0C578E6927B78BEB173FB0F9BFC8ECB4C13542BB8BE3B0F3447B3764A234177E22D180DCAD21F33302248B7452916DC58ABD309C8A77440A228B8516A4E"; + uint8_t B[(sizeof(server_B) -1)/2]; + hexstr_to_uint(server_B, B, sizeof(B)); + + assert_int_equal(librist_crypto_srp_client_handle_B(ctx->wrong_hash_client, B, sizeof(B), "rist", "mainprofile"), 0); + + const char expected_M1[] = "EBFC2D79BEB3CBF7BA83C27E2B51524F8CD3F3B2C4804815AD2516D465DF80C9"; + uint8_t m1[SHA256_DIGEST_LENGTH]; + + librist_crypto_srp_client_write_M1_bytes(ctx->wrong_hash_client, m1); + + char m1_hex[sizeof(expected_M1)]; + uint_to_hex(m1, sizeof(m1), m1_hex); + assert_string_equal(m1_hex, expected_M1); +} + +static void test_srp_wrong_hashing_client_verify_M2(void **state) { + struct srp_test_state *ctx = *state; + const char server_M2[] = "FB14D73B5ACBBA101E5A799F80EBCBB43D83890E23DED979110EEFF109C0441A"; + uint8_t M2[(sizeof(server_M2)-1)/2]; + hexstr_to_uint(server_M2, M2, sizeof(M2)); + assert_int_equal(librist_crypto_srp_client_verify_m2(ctx->wrong_hash_client, M2), 0); +} + +#endif + +static void test_srp_correct_hashing_verifier_create(void **state) { + struct srp_test_state *s = *state; + const char sample_salt[] = "72F9D5383B7EB7599FB63028F47475B60A55F313D40E0BE023E026C97C0A2C32"; + const char sample_verifier[] = "2E06FEA163D6E9FF0FA7ED6C59233389D0DBA0C08C0F72F6DAD1E2A3D8B92A772F070439D1C11B87FA990D2DAF04EB830CC77D61ACC4B253297379CD8E6DC3AF"; + + uint8_t *salt = NULL; + size_t salt_len = 0; + uint8_t *verifier = NULL; + size_t verifier_len = 0; + assert_int_equal(librist_crypto_srp_create_verifier(s->n, s->g, "rist", "mainprofile", &salt, &salt_len, &verifier, &verifier_len, true), 0); + + assert_int_equal(verifier_len, (sizeof(sample_verifier) -1)/2); + assert_int_equal(salt_len, (sizeof(sample_salt) -1)/2); + + char salt_hex[sizeof(sample_salt)]; + uint_to_hex(salt, salt_len, salt_hex); + assert_string_equal(salt_hex, sample_salt); + + char verifier_hex[sizeof(sample_verifier)]; + uint_to_hex(verifier, verifier_len, verifier_hex); + assert_string_equal(sample_verifier, verifier_hex); + free(verifier); + free(salt); +} + +static void test_srp_correct_hashing_auth_ctx_create(void **state) { + struct srp_test_state *s = *state; + struct librist_crypto_srp_authenticator_ctx * ctx = librist_crypto_srp_authenticator_ctx_create(s->n, s->g, s->correct_hash_verifier, s->verifier_len, s->salt, s->salt_len, true); + assert_non_null(ctx); + + const char well_known_n[] = "D66AAFE8E245F9AC245A199F62CE61AB8FA90A4D80C71CD2ADFD0B9DA163B29F2A34AFBDB3B1B5D0102559CE63D8B6E86B0AA59C14E79D4AA62D1748E4249DF3"; + uint8_t n[(sizeof(well_known_n) -1)/2]; + uint8_t g[1]; + + assert_int_equal(librist_crypto_srp_authenticator_write_n_bytes(ctx, n, sizeof(n)), sizeof(n)); + assert_int_equal(librist_crypto_srp_authenticator_write_g_bytes(ctx, g, sizeof(g)), sizeof(g)); + + char n_hex[sizeof(well_known_n)]; + char g_hex[sizeof("02")]; + + uint_to_hex(n, sizeof(n), n_hex); + assert_string_equal(n_hex, well_known_n); + + uint_to_hex(g, sizeof(g), g_hex); + assert_string_equal(g_hex, "02"); + + librist_crypto_srp_authenticator_ctx_free(ctx); +} + +static void test_srp_correct_hashing_auth_handle_A(void **state) { + struct srp_test_state *s = *state; + const char client_A_hex[] = "92C4CEFB95A1AE2E576A252B19273FD4613F44FDA4AC8CC84A089D5740756223943882BAD34CB55F35139CDDB60E0D19ACD2B884CFB27F53C8EA969269ABE014"; + uint8_t client_A[(sizeof(client_A_hex) -1)/2]; + hexstr_to_uint(client_A_hex, client_A, sizeof(client_A)); + assert_int_equal(librist_crypto_srp_authenticator_handle_A(s->correct_hash_authenticator, client_A, sizeof(client_A)), 0); + + const char expected_B[] = "858CDC811B5EEAA7F58C12767D309EBD2DF1D46F59EF5686052E6511CF853CA4E66910BDBD28CBEAE2F2DEE7F6BF3756757BD69E88D48C77B5371A82EF52AD84"; + + uint8_t B[(sizeof(expected_B) -1)/2]; + assert_int_equal(librist_crypto_srp_authenticator_write_B_bytes(s->correct_hash_authenticator, B, sizeof(B)), sizeof(B)); + + char B_hex[sizeof(expected_B)]; + uint_to_hex(B, sizeof(B), B_hex); + assert_string_equal(expected_B, B_hex); +} + +static void test_srp_correct_hashing_auth_verify_M1(void **state) { + struct srp_test_state *s = *state; + const char client_M1_hex[] = "E28147C801BAB9C37647C1FF4A29FA720E3F5676434FB85EA9A752CC1F9B1AD4"; + uint8_t client_M1[(sizeof(client_M1_hex) -1)/2]; + hexstr_to_uint(client_M1_hex, client_M1, sizeof(client_M1)); + + assert_int_equal(librist_crypto_srp_authenticator_verify_m1(s->correct_hash_authenticator, "rist", client_M1), 0); + + const char expected_m2[] = "84F19797916FBDCAB1321CA78B575B145B586150248AFAA156361B8BCB139B32"; + char m2_hex[sizeof(expected_m2)]; + uint8_t m2[SHA256_DIGEST_LENGTH]; + + librist_crypto_srp_authenticator_write_M2_bytes(s->correct_hash_authenticator, m2); + + uint_to_hex(m2, sizeof(m2), m2_hex); + + assert_string_equal(m2_hex, expected_m2); +} + +static void test_srp_correct_hashing_client_handle_B(void **state) { + struct srp_test_state *ctx = *state; + const char server_B[] = "858CDC811B5EEAA7F58C12767D309EBD2DF1D46F59EF5686052E6511CF853CA4E66910BDBD28CBEAE2F2DEE7F6BF3756757BD69E88D48C77B5371A82EF52AD84"; + uint8_t B[(sizeof(server_B) -1)/2]; + hexstr_to_uint(server_B, B, sizeof(B)); + + assert_int_equal(librist_crypto_srp_client_handle_B(ctx->correct_hash_client, B, sizeof(B), "rist", "mainprofile"), 0); + + const char expected_M1[] = "E28147C801BAB9C37647C1FF4A29FA720E3F5676434FB85EA9A752CC1F9B1AD4"; + uint8_t m1[SHA256_DIGEST_LENGTH]; + + librist_crypto_srp_client_write_M1_bytes(ctx->correct_hash_client, m1); + + char m1_hex[sizeof(expected_M1)]; + uint_to_hex(m1, sizeof(m1), m1_hex); + assert_string_equal(m1_hex, expected_M1); +} + +static void test_srp_correct_hashing_client_verify_M2(void **state) { + struct srp_test_state *ctx = *state; + const char server_M2[] = "84F19797916FBDCAB1321CA78B575B145B586150248AFAA156361B8BCB139B32"; + uint8_t M2[(sizeof(server_M2)-1)/2]; + hexstr_to_uint(server_M2, M2, sizeof(M2)); + assert_int_equal(librist_crypto_srp_client_verify_m2(ctx->correct_hash_client, M2), 0); +} + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_hash_func), + cmocka_unit_test(test_hash_update_func), + cmocka_unit_test(test_get_default_ng), +#if HAVE_MBEDTLS + cmocka_unit_test(test_srp_wrong_hashing_auth_handle_A), + cmocka_unit_test(test_srp_wrong_hashing_auth_verify_M1), + cmocka_unit_test(test_srp_wrong_hashing_verifier_create), + cmocka_unit_test(test_srp_wrong_hashing_auth_ctx_create), +#endif + cmocka_unit_test(test_srp_correct_hashing_verifier_create), + cmocka_unit_test(test_srp_correct_hashing_auth_ctx_create), + cmocka_unit_test(test_srp_correct_hashing_auth_handle_A), + cmocka_unit_test(test_srp_correct_hashing_auth_verify_M1), + cmocka_unit_test(test_srp_client_ctx_create), +#if HAVE_MBEDTLS + cmocka_unit_test(test_srp_wrong_hashing_client_handle_B), + cmocka_unit_test(test_srp_wrong_hashing_client_verify_M2), +#endif + cmocka_unit_test(test_srp_correct_hashing_client_handle_B), + cmocka_unit_test(test_srp_correct_hashing_client_verify_M2), + }; + + return cmocka_run_group_tests(tests, srp_test_state_setup, srp_test_state_teardown); +} diff --git a/tools/meson.build b/tools/meson.build index dd6a4d2cf74d120f92d4415761c79c2f06d5381b..8e2dc8b76decc58df7253fd9c437d336d4fd91b3 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -17,9 +17,9 @@ if filter_obj endif srp_shared = [] -if use_mbedtls +if have_srp srp_shared += 'srp_shared.c' - tools_dependencies += mbedcrypto_lib + tools_dependencies += crypto_deps endif if compile_prometheus @@ -60,12 +60,12 @@ executable('rist2rist', include_directories: inc, install: should_install) -if use_mbedtls +if mbedcrypto_lib_found or use_nettle executable('ristsrppasswd', - ['ristsrppasswd.c', '../contrib/srp.c', tools_deps], + ['ristsrppasswd.c', tools_deps], dependencies: [ - mbedcrypto_lib, librist_dep, + crypto_deps, ], include_directories: inc, install: should_install) diff --git a/tools/rist2rist.c b/tools/rist2rist.c index ea035791283c333f02ae90b5c2888b592a1cc0b4..0c71d5867591a3fa16f53897fbfc42de94f98b73 100644 --- a/tools/rist2rist.c +++ b/tools/rist2rist.c @@ -11,7 +11,7 @@ #include "librist/version.h" #include "risturlhelp.h" #include "config.h" -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT #include "librist/librist_srp.h" #include "srp_shared.h" #endif @@ -56,7 +56,7 @@ static struct option long_options[] = { { "statsinterval", required_argument, NULL, 'S' }, { "verbose-level", required_argument, NULL, 'v' }, { "remote-logging", required_argument, NULL, 'r' }, -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT { "srpfile", required_argument, NULL, 'F' }, #endif { "help", no_argument, NULL, 'h' }, @@ -72,7 +72,7 @@ const char help_str[] = "Usage: %s [OPTIONS] \nWhere OPTIONS are:\n" " -N | --cname identifier | Manually configured identifier |\n" " -v | --verbose-level value | To disable logging: -1, log levels match syslog levels |\n" " -r | --remote-logging IP:PORT | Send logs and stats to this IP:PORT using udp messages |\n" -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT " -F | --srpfile filepath | When in listening mode, use this file to hold the list |\n" " | of usernames and passwords to validate against. Use the |\n" " | ristsrppasswd tool to create the line entries. |\n" @@ -84,8 +84,8 @@ const char help_str[] = "Usage: %s [OPTIONS] \nWhere OPTIONS are:\n" " --statsinterval 1000 \\\n" " --verbose-level 6 \n"; -#if HAVE_MBEDTLS - FILE *srpfile = NULL; +#if HAVE_SRP_SUPPORT + char *srpfile = NULL; #endif static void usage(char *cmd) @@ -208,17 +208,17 @@ static struct rist_ctx* setup_rist_sender(struct rist_sender_args *setup) { exit(1); } -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT int srp_error = 0; if (strlen(peer_config->srp_username) > 0 && strlen(peer_config->srp_password) > 0) { - srp_error = rist_enable_eap_srp(peer, peer_config->srp_username, peer_config->srp_password, NULL, NULL); + srp_error = rist_enable_eap_srp_2(peer, peer_config->srp_username, peer_config->srp_password, NULL, NULL); if (srp_error) rist_log(&logging_settings, RIST_LOG_WARN, "Error %d trying to enable SRP for peer\n", srp_error); } if (srpfile) { - srp_error = rist_enable_eap_srp(peer, NULL, NULL, user_verifier_lookup, srpfile); + srp_error = rist_enable_eap_srp_2(peer, NULL, NULL, user_verifier_lookup, srpfile); if (srp_error) rist_log(&logging_settings, RIST_LOG_WARN, "Error %d trying to enable SRP global authenticator, file %s\n", srp_error, srpfile); } @@ -246,7 +246,7 @@ static int cb_recv(void *arg, struct rist_data_block *b) rist_sender_flow_id_set(cb_arg->sender_ctx, b->flow_id); } b->virt_src_port = cb_arg->src_port; - b->virt_dst_port = cb_arg->dst_port; + b->virt_dst_port = cb_arg->dst_port; block->flags = RIST_DATA_FLAGS_USE_SEQ;//We only need this flag set, this way we don't have to null it beforehand. int ret = rist_sender_data_write(cb_arg->sender_ctx, b); rist_receiver_data_block_free2(&b); @@ -303,17 +303,17 @@ int main (int argc, char **argv) { case 'i': if (inputurl != NULL) goto usage; - inputurl = strdup(optarg); + inputurl = strdup(optarg); break; case 'o': if (outputurl != NULL) goto usage; - outputurl = strdup(optarg); + outputurl = strdup(optarg); break; case 's': if (client_args.shared_secret != NULL) goto usage; - client_args.shared_secret = strdup(optarg); + client_args.shared_secret = strdup(optarg); break; case 'e': client_args.encryption_type =atoi(optarg); @@ -321,7 +321,7 @@ int main (int argc, char **argv) { case 'N': if (cname != NULL) goto usage; - cname = strdup(optarg); + cname = strdup(optarg); break; case 'v': loglevel = (enum rist_log_level) atoi(optarg); @@ -331,14 +331,15 @@ int main (int argc, char **argv) { goto usage; remote_log_address = strdup(optarg); break; -#if HAVE_MBEDTLS - case 'F': - srpfile = fopen(optarg, "r"); - if (!srpfile) { +#if HAVE_SRP_SUPPORT + case 'F': { + FILE* f = fopen(optarg, "r"); + if (!f) { rist_log(&logging_settings, RIST_LOG_ERROR, "Could not open srp file %s\n", optarg); - exitcode = 1; - goto out; + return 1; } + srpfile = strdup(optarg); + } break; #endif case 'S': @@ -480,7 +481,7 @@ out: free(outputurl); if (remote_log_address) free(remote_log_address); - + return exitcode; diff --git a/tools/ristreceiver.c b/tools/ristreceiver.c index 651fb022e8d97cf5299ee55aff111be8d22620a4..e14dbf9eaa09f2db8e73e6ab3725dba7ef7b3f7e 100644 --- a/tools/ristreceiver.c +++ b/tools/ristreceiver.c @@ -10,7 +10,7 @@ #include "headers.h" #include "librist/version.h" #include "config.h" -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT #include "librist/librist_srp.h" #include "srp_shared.h" #endif @@ -81,7 +81,7 @@ static struct option long_options[] = { { "stats", required_argument, NULL, 'S' }, { "verbose-level", required_argument, NULL, 'v' }, { "remote-logging", required_argument, NULL, 'r' }, -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT { "srpfile", required_argument, NULL, 'F' }, #endif { "help", no_argument, NULL, 'h' }, @@ -117,7 +117,7 @@ const char help_str[] = "Usage: %s [OPTIONS] \nWhere OPTIONS are:\n" " -S | --statsinterval value (ms) | Interval at which stats get printed, 0 to disable |\n" " -v | --verbose-level value | To disable logging: -1, log levels match syslog levels |\n" " -r | --remote-logging IP:PORT | Send logs and stats to this IP:PORT using udp messages |\n" -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT " -F | --srpfile filepath | When in listening mode, use this file to hold the list |\n" " | of usernames and passwords to validate against. Use the |\n" " | ristsrppasswd tool to create the line entries. |\n" @@ -525,8 +525,8 @@ int main(int argc, char *argv[]) int receiver_pipe[2]; #endif -#if HAVE_MBEDTLS - FILE *srpfile = NULL; +#if HAVE_SRP_SUPPORT + char *srpfile = NULL; #endif for (size_t i = 0; i < MAX_OUTPUT_COUNT; i++) @@ -591,13 +591,15 @@ int main(int argc, char *argv[]) case 'r': remote_log_address = strdup(optarg); break; -#if HAVE_MBEDTLS - case 'F': - srpfile = fopen(optarg, "r"); - if (!srpfile) { +#if HAVE_SRP_SUPPORT + case 'F': { + FILE* f = fopen(optarg, "r"); + if (!f) { rist_log(&logging_settings, RIST_LOG_ERROR, "Could not open srp file %s\n", optarg); return 1; } + srpfile = strdup(optarg); + } break; #endif case 'u': @@ -754,18 +756,18 @@ int main(int argc, char *argv[]) rist_log(&logging_settings, RIST_LOG_ERROR, "Could not add peer connector to receiver #%i\n", (int)(i + 1)); exit(1); } -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT int srp_error = 0; if (profile != RIST_PROFILE_SIMPLE) { if (strlen(peer_config->srp_username) > 0 && strlen(peer_config->srp_password) > 0) { - srp_error = rist_enable_eap_srp(peer, peer_config->srp_username, peer_config->srp_password, NULL, NULL); + srp_error = rist_enable_eap_srp_2(peer, peer_config->srp_username, peer_config->srp_password, NULL, NULL); if (srp_error) rist_log(&logging_settings, RIST_LOG_WARN, "Error %d trying to enable SRP for peer\n", srp_error); } if (srpfile) { - srp_error = rist_enable_eap_srp(peer, NULL, NULL, user_verifier_lookup, srpfile); + srp_error = rist_enable_eap_srp_2(peer, NULL, NULL, user_verifier_lookup, srpfile); if (srp_error) rist_log(&logging_settings, RIST_LOG_WARN, "Error %d trying to enable SRP global authenticator, file %s\n", srp_error, srpfile); } diff --git a/tools/ristsender.c b/tools/ristsender.c index afc0c1ad1c09b0e7a0ce4d385311e9874f9ce5b9..335c012f7faded86c8c7a826bd2661d57e8f1bf6 100644 --- a/tools/ristsender.c +++ b/tools/ristsender.c @@ -9,7 +9,7 @@ #include <stdint.h> #include "librist/version.h" #include "config.h" -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT #include "librist/librist_srp.h" #include "srp_shared.h" #endif @@ -123,7 +123,7 @@ static struct option long_options[] = { { "stats", required_argument, NULL, 'S' }, { "verbose-level", required_argument, NULL, 'v' }, { "remote-logging", required_argument, NULL, 'r' }, -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT { "srpfile", required_argument, NULL, 'F' }, #endif { "fast-start", required_argument, NULL, 'f' }, @@ -161,7 +161,7 @@ const char help_str[] = "Usage: %s [OPTIONS] \nWhere OPTIONS are:\n" " -S | --statsinterval value (ms) | Interval at which stats get printed, 0 to disable |\n" " -v | --verbose-level value | To disable logging: -1, log levels match syslog levels |\n" " -r | --remote-logging IP:PORT | Send logs and stats to this IP:PORT using udp messages |\n" -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT " -F | --srpfile filepath | When in listening mode, use this file to hold the list |\n" " | of usernames and passwords to validate against. Use the |\n" " | ristsrppasswd tool to create the line entries. |\n" @@ -211,8 +211,8 @@ static uint64_t risttools_convertRTPtoNTP(uint32_t i_rtp) } */ -#if HAVE_MBEDTLS - FILE *srpfile = NULL; +#if HAVE_SRP_SUPPORT + char *srpfile = NULL; #endif static void input_udp_recv(struct evsocket_ctx *evctx, int fd, short revents, void *arg) @@ -536,18 +536,18 @@ static struct rist_peer* setup_rist_peer(struct rist_ctx_wrap *w, struct rist_se } } #endif -#if HAVE_MBEDTLS +#if HAVE_SRP_SUPPORT int srp_error = 0; if (setup->profile != RIST_PROFILE_SIMPLE) { if (strlen(peer_config_link->srp_username) > 0 && strlen(peer_config_link->srp_password) > 0) { - srp_error = rist_enable_eap_srp(peer, peer_config_link->srp_username, peer_config_link->srp_password, NULL, NULL); + srp_error = rist_enable_eap_srp_2(peer, peer_config_link->srp_username, peer_config_link->srp_password, NULL, NULL); if (srp_error) rist_log(&logging_settings, RIST_LOG_WARN, "Error %d trying to enable SRP for peer\n", srp_error); } if (srpfile) { - srp_error = rist_enable_eap_srp(peer, NULL, NULL, user_verifier_lookup, srpfile); + srp_error = rist_enable_eap_srp_2(peer, NULL, NULL, user_verifier_lookup, srpfile); if (srp_error) rist_log(&logging_settings, RIST_LOG_WARN, "Error %d trying to enable SRP global authenticator, file %s\n", srp_error, srpfile); } @@ -790,13 +790,15 @@ int main(int argc, char *argv[]) case 'r': remote_log_address = strdup(optarg); break; -#if HAVE_MBEDTLS - case 'F': - srpfile = fopen(optarg, "r"); - if (!srpfile) { +#if HAVE_SRP_SUPPORT + case 'F': { + FILE* f = fopen(optarg, "r"); + if (!f) { rist_log(&logging_settings, RIST_LOG_ERROR, "Could not open srp file %s\n", optarg); return 1; } + srpfile = strdup(optarg); + } break; #endif case 'u': diff --git a/tools/ristsrppasswd.c b/tools/ristsrppasswd.c index 9702169db23e3644a5ceb483b08b80a775cca7f1..1ce257cc2d255f767d3d4f9bfaa5117c00a0a438 100644 --- a/tools/ristsrppasswd.c +++ b/tools/ristsrppasswd.c @@ -5,10 +5,43 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include "srp.h" +#include "config.h" +#include "crypto/srp.h" +#include "crypto/srp_constants.h" #include <stdio.h> +#include <stdlib.h> #include <string.h> +#if HAVE_MBEDTLS #include <mbedtls/base64.h> +#elif HAVE_NETTLE +#include <nettle/base64.h> +#endif + +int create_and_print(const char *username, const char *password, const char *n_hex, const char* g_hex, bool correct) { + uint8_t *salt = NULL; + size_t salt_len = 0; + uint8_t *verifier = NULL; + size_t verifier_len = 0; + int ret = librist_crypto_srp_create_verifier(n_hex, g_hex, username, password, &salt, &salt_len, &verifier, &verifier_len, correct); + if (ret != 0) + return ret; + + char salt64[1024] = {0}; + char verifier64[1024] = {0}; +#if HAVE_MBEDTLS + size_t salt_written_len = 0; + mbedtls_base64_encode((unsigned char*)salt64, sizeof(salt64), &salt_written_len, salt, salt_len); + size_t verifier_written_len = 0; + mbedtls_base64_encode((unsigned char*)verifier64, sizeof(verifier64), &verifier_written_len, verifier, verifier_len); +#elif HAVE_NETTLE + nettle_base64_encode_raw(salt64, salt_len, salt); + nettle_base64_encode_raw(verifier64, verifier_len, verifier); +#endif + free(salt); + free(verifier); + printf("%s:%s:%s:3:%d\n", username, verifier64, salt64, correct? 1 :0); + return 0; +} int main(int argc, char *argv[]) { @@ -17,42 +50,14 @@ int main(int argc, char *argv[]) return 1; } - struct SRPSession * session = srp_session_new(SRP_SHA256, SRP_NG_2048, NULL, NULL); const char *username = argv[1]; const char *password = argv[2]; - size_t len_s = 0; - size_t len_v = 0; - char *bytes_s = NULL; - char *bytes_v = NULL; - srp_create_salted_verification_key(session, username, - (const unsigned char *)password, strlen(password), - (const unsigned char **)&bytes_s, &len_s, - (const unsigned char **)&bytes_v, &len_v); - unsigned char verifier[512] = { 0 }; - size_t olen_v = 0; - unsigned char salt[512] = { 0 }; - size_t olen_s = 0; - mbedtls_base64_encode(verifier, 512, &olen_v, (const unsigned char *)bytes_v, len_v); - unsigned char *test = &verifier[0]; - while (*test != '\0') - { - if (*test == '=') - { - *test = '\0'; - break; - } - test++; - } - mbedtls_base64_encode(salt, 512, &olen_s, (const unsigned char *)bytes_s, len_s); - test = &salt[0]; - while (*test != '\0') - { - if (*test == '=') - { - *test = '\0'; - break; - } - test++; - } - printf("%s:%s:%s:3\n", username, verifier, salt); + const char *n_hex = NULL; + const char *g_hex = NULL; + + librist_get_ng_constants(LIBRIST_SRP_NG_DEFAULT, &n_hex, &g_hex); +#if HAVE_MBEDTLS + create_and_print(username, password, n_hex, g_hex, false); +#endif + create_and_print(username, password, n_hex, g_hex, true); } diff --git a/tools/srp_shared.c b/tools/srp_shared.c index cec2108ae6b4aae5ed36077bb8785b95c84bc91d..80d95015e9484feda40399eaaa415f0ac0e9ffe1 100644 --- a/tools/srp_shared.c +++ b/tools/srp_shared.c @@ -5,12 +5,126 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include "config.h" +#include <librist/librist_config.h> +#if HAVE_MBEDTLS #include <mbedtls/base64.h> +#elif HAVE_NETTLE +#include <nettle/base64.h> +#endif #include <stddef.h> #include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <stdint.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#define stat _stat +#endif + +typedef enum { + IN_USERNAME = 0, + IN_VERIFIER, + IN_SALT, + IN_HASH_ALGO, + IN_HASH_VERSION, +} user_verifier_state_e; + +#define READ_VERIFIER_LEN 1025 +#define READ_SALT_LEN 1025 +#define MAX_LINE_LEN (READ_VERIFIER_LEN + READ_SALT_LEN + 1) + +int srp_base64_decode(char *string, size_t string_len, size_t *out_len, uint8_t **out) { + //Add padding if needed + if ((string_len % 4) != 0) + { + size_t needed_padding = 4 - (string_len % 4); + for (size_t i = 0; i < needed_padding; i++) + string[(string_len + i)] = '='; + string_len += needed_padding; + string[string_len] = '\0'; + } +#if HAVE_MBEDTLS + size_t len = 0; + + int ret =mbedtls_base64_decode(NULL, 0, &len, (unsigned char *)string, string_len); + if (ret != 0 && ret != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) + return -1; + + *out = malloc(len); + if (mbedtls_base64_decode(*out, len, out_len, (unsigned char *)string, string_len) != 0) + goto fail_decode; + + return 0; +#elif HAVE_NETTLE + struct base64_decode_ctx ctx; + nettle_base64_decode_init(&ctx); + size_t len = BASE64_ENCODE_LENGTH(string_len); + *out = malloc(len); + if (nettle_base64_decode_update(&ctx, out_len, *out, string_len, string) != 1) + goto fail_decode; + if (nettle_base64_decode_final(&ctx) != 1) + goto fail_decode; + return 0; +#endif + +fail_decode: + free(*out); + *out = NULL; + return -1; +} + +int parse_line(const char *line, size_t line_len, uint8_t **decoded_verifier, size_t *decoded_verifier_len, uint8_t **decoded_salt, size_t *decoded_salt_len) { + char read = '\0'; + user_verifier_state_e state = IN_VERIFIER; + int ret = -1; + size_t read_verifier_len = 0; + char *read_verifier = calloc(READ_VERIFIER_LEN, 1); + size_t read_salt_len = 0; + char *read_salt = calloc(READ_SALT_LEN, 1); + if (!read_salt || !read_verifier) + goto out; + for (size_t i=0; i < line_len; i++) { + read = line[i]; + if (read == ':') + { + if (state >= IN_SALT && read == '\n') + break; + if (state == IN_VERIFIER) + read_verifier[read_verifier_len+1] = '\0'; + else if (state == IN_SALT) + { + read_salt[read_salt_len +1] = '\0'; + } + state++; + } else if (state == IN_VERIFIER) + { + if (read_verifier_len == READ_VERIFIER_LEN) + return -1; + read_verifier[read_verifier_len] = read; + read_verifier_len++; + } else if (state == IN_SALT) + { + if (read_salt_len == READ_SALT_LEN) + return -1; + read_salt[read_salt_len] = read; + read_salt_len++; + } + } + ret = srp_base64_decode(read_verifier, read_verifier_len, decoded_verifier_len, decoded_verifier); + if (ret != 0) + goto out; + ret = srp_base64_decode(read_salt, read_salt_len, decoded_salt_len, decoded_salt); + if (ret != 0) + free(*decoded_verifier); +out: + free(read_verifier); + free(read_salt); + return ret; +} + void user_verifier_lookup(char * username, size_t *verifier_len, char **verifier, @@ -18,110 +132,137 @@ void user_verifier_lookup(char * username, bool *use_default_2048_bit_n_modulus, char **n_modulus_ascii, char **generator_ascii, + int *hashversion, + uint64_t *generation, void *user_data) { +#if HAVE_NETTLE + struct base64_decode_ctx ctx; + nettle_base64_decode_init(&ctx); +#endif (void)n_modulus_ascii; (void)generator_ascii; if (user_data == NULL) return; - FILE *fh = (FILE *)user_data; - size_t username_offset = 0; - size_t read_verifier_len = 0; - char *read_verifier = malloc(1024); - size_t read_salt_len = 0; - char *read_salt = malloc(1024); + char *srpfile = user_data; + + struct stat buf; + if (stat(srpfile, &buf) != 0) + return; + + if (!generation) + return; + *generation = (buf.st_mtim.tv_sec << 32) | buf.st_mtim.tv_nsec; - int reading = 0;//0 = username, 1 = verifier, 2 = salt + if (!verifier || !verifier_len || !salt || !salt_len || !hashversion || !use_default_2048_bit_n_modulus) + return; + + FILE *fh = fopen(srpfile, "r"); + if (!fh) + return; + + size_t username_offset = 0; + + char read_hashver[3] = {0}; + int read_hashver_len = 0; + user_verifier_state_e state = IN_USERNAME; bool skipnextline = false; int read = getc(fh); //expected format: username:verifier:salt:3 + int maxhashversion = *hashversion; + size_t username_len = strlen(username); + char *line_even = malloc(MAX_LINE_LEN); + size_t line_even_len =0; + bool line_one_done = false; + char *line_odd = malloc(MAX_LINE_LEN); + size_t line_odd_len = 0; + + size_t line_len = 0; while (read != EOF) { + char *line = line_one_done? line_odd : line_even; if (skipnextline) { if (read == '\n') skipnextline = false; + } + else if (state >= IN_SALT && read == '\n') { + if (state >= IN_HASH_VERSION) { + state = IN_USERNAME; + username_offset = 0; + *hashversion = atoi(read_hashver); + if (line_one_done) { + line_odd_len = line_len; + } else { + line_even_len = line_len; + line_len = 0; + line_one_done = true; + if (*hashversion < maxhashversion) { + read = getc(fh); + continue; + } + } + } + break; } else if (read == ':') { - if (reading == 0 && username_offset != (strlen(username))) { + if (state == IN_VERIFIER) + line[line_len++] = read; + if (state == IN_USERNAME && username_offset != username_len) { + if (line_one_done) { + break; + } skipnextline = true; username_offset = 0; continue; } - if (reading == 1) - read_verifier[read_verifier_len+1] = '\0'; - else if (reading == 2) - { - read_salt[read_salt_len +1] = '\0'; - break; - } - reading++; + state++; } - else if (reading == 0) + else if (state == IN_USERNAME) { + if (username_offset == username_len) { + username_offset = 0; + skipnextline = true; + continue; + } if (username[username_offset] != read) { username_offset = 0; skipnextline = true; - } - else + } else username_offset++; - } else if (reading == 1) - { - if (read_verifier_len == 1024) - goto out; - read_verifier[read_verifier_len] = read; - read_verifier_len++; - } else if (reading == 2) - { - if (read_salt_len == 1024) - goto out; - read_salt[read_salt_len] = read; - read_salt_len++; + } else if (state >= IN_VERIFIER && state <= IN_SALT) { + if (line_len >= MAX_LINE_LEN) { + if (!line_one_done) + goto out; + break; + } + line[line_len++] = read; + } else if (state == IN_HASH_VERSION && read_hashver_len < 3) { + read_hashver[read_hashver_len] = read; + read_hashver_len++; } read = getc(fh); } - if (reading != 2) + + *hashversion = atoi(read_hashver); + if (state < IN_SALT && !line_one_done) goto out; - //PAD with == - if ((read_verifier_len % 4) != 0) - { - size_t needed_padding = 4 - (read_verifier_len % 4); - for (size_t i = 0; i < needed_padding; i++) - read_verifier[(read_verifier_len + i)] = '='; - read_verifier_len += needed_padding; - read_verifier[read_verifier_len] = '\0'; - } - if ((read_salt_len % 4) != 0) - { - size_t needed_padding = 4 - (read_salt_len % 4); - for (size_t i = 0; i < needed_padding; i++) - read_salt[(read_salt_len + i)] = '='; - read_salt_len += needed_padding; - read_salt[read_salt_len] = '\0'; - } - char *decoded_verifier = malloc(1024); - char *decoded_salt = malloc(1024); - if (mbedtls_base64_decode((unsigned char *)decoded_verifier, 1024, verifier_len, (unsigned char *)read_verifier, read_verifier_len) != 0) - goto fail_decode; - if (mbedtls_base64_decode((unsigned char *)decoded_salt, 1024, salt_len, (unsigned char *)read_salt, read_salt_len) != 0) - goto fail_decode; + char *line = line_even; + line_len = line_even_len; + if (line_one_done && line_odd_len != 0) { + line = line_odd; + line_len = line_odd_len; + } - *verifier = decoded_verifier; - *salt = decoded_salt; + parse_line(line, line_len, (uint8_t**)verifier, verifier_len, (uint8_t **)salt, salt_len); *use_default_2048_bit_n_modulus = true; - goto out; -fail_decode: - *verifier_len = 0; - *salt_len = 0; - free(decoded_verifier); - free(decoded_salt); out: - free(read_verifier); - free(read_salt); - rewind(fh); + free(line_even); + free(line_odd); + fclose(fh); return; } diff --git a/tools/srp_shared.h b/tools/srp_shared.h index a1f08e040958c104c483a97e106783707b139375..9b32a2cd3e4530221d9603043fa2a129bc780f6f 100644 --- a/tools/srp_shared.h +++ b/tools/srp_shared.h @@ -7,11 +7,11 @@ #include <stddef.h> #include <stdbool.h> +#include <stdint.h> -void user_verifier_lookup(char * username, - size_t *verifier_len, char **verifier, - size_t *salt_len, char **salt, - bool *use_default_2048_bit_n_modulus, - char **n_modulus_ascii, - char **generator_ascii, - void *user_data); +void user_verifier_lookup(char *username, size_t *verifier_len, char **verifier, + size_t *salt_len, char **salt, + bool *use_default_2048_bit_n_modulus, + char **n_modulus_ascii, char **generator_ascii, + int *hashversion, uint64_t *generation, + void *user_data);