long Srv_rpc_srp_verifier_verify_session( handle_t hServer, srp_verifier_handle_t hSrp, rpc_p_srp_bytes_container user_M_cont, rpc_p_srp_bytes_container *ret_bytes_HAMK_cont) { long sts = 0; struct SRPVerifier *ver = (struct SRPVerifier *) hSrp; char *bytes_M = NULL; const char *bytes_HAMK = NULL; rpc_p_srp_bytes_container bytes_HAMK_cont = NULL; long bytes_HAMK_len = 0; if (!ver) { sts = rpc_s_invalid_handle; goto error; } /* Oddly enough, the length for user_M isn't used here. */ bytes_M = user_M_cont->bytes_B; srp_verifier_verify_session(ver, bytes_M, &bytes_HAMK); if (!bytes_HAMK) { *ret_bytes_HAMK_cont = NULL; sts = rpc_s_auth_mut_fail; goto error; } bytes_HAMK_len = srp_verifier_get_session_key_length(ver); sts = _srp_bytes_container_allocate(bytes_HAMK, bytes_HAMK_len, &bytes_HAMK_cont); if (sts) { goto error; } *ret_bytes_HAMK_cont = bytes_HAMK_cont; error: if (sts) { _srp_bytes_container_free(bytes_HAMK_cont); } return sts; }
static void msc_server_connection_handle_auth2(msc_server_connection *c, const char *m) { if (!c->srp) return; const unsigned char *hamk = NULL; srp_verifier_verify_session(c->srp, (const unsigned char *)m, &hamk); if (hamk) { if (srp_verifier_is_authenticated(c->srp)) { msc_server_connection_send_auth2(c, (char *)hamk, (256 / 8)); if (c->user) g_string_free(c->user, TRUE); c->user = g_string_new(srp_verifier_get_username(c->srp)); msc_server_log_authenticated(c->server, c); c->bad_logins = 0; } else { ++c->bad_logins; msc_server_log_authentication_failed(c->server, c, srp_verifier_get_username(c->srp)); srp_verifier_delete(c->srp); c->srp = NULL; } } else { ++c->bad_logins; msc_server_log_authentication_failed(c->server, c, srp_verifier_get_username(c->srp)); srp_verifier_delete(c->srp); c->srp = NULL; } }
//***************************************************************************** // bool SERVER_ProcessSRPClientCommand( LONG lCommand, BYTESTREAM_s *pByteStream ) { switch ( lCommand ) { case CLC_SRP_USER_REQUEST_LOGIN: { CLIENT_s *pClient = SERVER_GetClient(SERVER_GetCurrentClient()); pClient->username = NETWORK_ReadString( pByteStream ); pClient->clientSessionID = M_Random.GenRand32(); #if EMULATE_AUTH_SERVER SERVERCOMMANDS_SRPUserStartAuthentication ( SERVER_GetCurrentClient() ); #else // [BB] The client wants to log in, so start negotiating with the auth server. SERVER_AUTH_Negotiate ( pClient->username.GetChars(), pClient->clientSessionID ); #endif } break; case CLC_SRP_USER_START_AUTHENTICATION: { CLIENT_s *pClient = SERVER_GetClient(SERVER_GetCurrentClient()); const int lenA = NETWORK_ReadShort( pByteStream ); if ( lenA > 0 ) { pClient->bytesA.Resize ( lenA ); for ( int i = 0; i < lenA; ++i ) pClient->bytesA[i] = NETWORK_ReadByte( pByteStream ); } else Printf ( "CLC_SRP_USER_START_AUTHENTICATION: Invalid length\n" ); #if EMULATE_AUTH_SERVER const unsigned char * bytesS = NULL; const unsigned char * bytesV = NULL; int lenS = 0; int lenV = 0; const char *password = "******"; srp_create_salted_verification_key( SRP_SHA256, SRP_NG_2048, pClient->username.GetChars(), reinterpret_cast<const unsigned char *>(password), strlen(password), &bytesS, &lenS, &bytesV, &lenV, NULL, NULL ); pClient->salt.Resize ( lenS ); for ( int i = 0; i < lenS; ++i ) pClient->salt[i] = bytesS[i]; const unsigned char * bytesB = NULL; int lenB = 0; if ( g_ver != NULL ) srp_verifier_delete( g_ver ); g_ver = srp_verifier_new( SRP_SHA256, SRP_NG_2048, pClient->username.GetChars(), bytesS, lenS, bytesV, lenV, &(pClient->bytesA[0]), lenA, &bytesB, &lenB, NULL, NULL, 1 ); if ( ( bytesB == NULL ) || ( lenB == 0 ) ) { Printf ( "Verifier SRP-6a safety check violated!\n" ); pClient->bytesB.Clear(); } else { Printf ( "Verifier SRP-6a safety check passed.\n" ); pClient->bytesB.Resize ( lenB ); for ( int i = 0; i < lenB; ++i ) pClient->bytesB[i] = bytesB[i]; SERVERCOMMANDS_SRPUserProcessChallenge ( SERVER_GetCurrentClient() ); } free( (char *)bytesS ); free( (char *)bytesV ); #else SERVER_AUTH_SRPMessage ( SERVER_AUTH_SRP_STEP_ONE, pClient->SRPsessionID, pClient->bytesA ); #endif return ( false ); } break; case CLC_SRP_USER_PROCESS_CHALLENGE: { CLIENT_s *pClient = SERVER_GetClient(SERVER_GetCurrentClient()); const int lenM = NETWORK_ReadShort( pByteStream ); if ( lenM > 0 ) { pClient->bytesM.Resize ( lenM ); for ( int i = 0; i < lenM; ++i ) pClient->bytesM[i] = NETWORK_ReadByte( pByteStream ); } else Printf ( "CLC_SRP_USER_PROCESS_CHALLENGE: Invalid length\n" ); #if EMULATE_AUTH_SERVER unsigned char bytesM[SHA512_DIGEST_LENGTH]; for ( int i = 0; i < lenM; ++i ) bytesM[i] = pClient->bytesM[i]; if ( g_ver == NULL ) Printf ( "Error: Verifier pointer is NULL.\n" ); else { const unsigned char * bytesHAMK = NULL; srp_verifier_verify_session( g_ver, bytesM, &bytesHAMK ); if ( bytesHAMK == NULL ) { SERVER_InitClientSRPData ( SERVER_GetCurrentClient() ); Printf ( "User authentication failed!\n" ); SERVER_PrintfPlayer( PRINT_HIGH, SERVER_GetCurrentClient(), "User authentication failed!\n" ); } else { Printf ( "User authentication successfully.\n" ); // [BB] The user has logged in in successfully. SERVER_GetClient(SERVER_GetCurrentClient())->loggedIn = true; pClient->bytesHAMK.Resize ( srp_verifier_get_session_key_length( g_ver ) ); for ( unsigned int i = 0; i < pClient->bytesHAMK.Size(); ++i ) pClient->bytesHAMK[i] = bytesHAMK[i]; SERVERCOMMANDS_SRPUserVerifySession ( SERVER_GetCurrentClient() ); } } #else if ( pClient->SRPsessionID != -1 ) SERVER_AUTH_SRPMessage ( SERVER_AUTH_SRP_STEP_THREE, pClient->SRPsessionID, pClient->bytesM ); #endif return ( false ); } break; default: Printf ( "Error: Received unknown SRP command '%d' from client %d.\n", static_cast<int>(lCommand), static_cast<int>(SERVER_GetCurrentClient()) ); break; } return ( false ); }
static OM_uint32 _srp_gss_validate_client( OM_uint32 *minor_status, srp_gss_ctx_id_t srp_context_handle, int state, gss_buffer_t input_token, gss_buffer_t output_token) { OM_uint32 maj = 0; OM_uint32 min = 0; int berror = 0; ber_tag_t ber_state = 0; BerElement *ber = NULL; BerElement *ber_resp = NULL; struct berval ber_HAMK = {0}; struct berval *ber_srp_bytes_M = NULL; struct berval ber_ctx = {0}; const unsigned char *bytes_HAMK = NULL; int bytes_HAMK_len = 0; struct berval *flatten = NULL; PVMDIR_SERVER_CONTEXT hServer = NULL; ber_ctx.bv_val = (void *) input_token->value; ber_ctx.bv_len = input_token->length; ber = ber_init(&ber_ctx); if (!ber) { maj = GSS_S_FAILURE; goto error; } srp_debug_printf("_srp_gss_validate_client(): " "state=SRP_AUTH_CLIENT_VALIDATE\n"); /* * ptr points to ASN.1 encoded data which is dependent on the authentication * state. The appropriate decoder format string is applied for each state */ berror = ber_scanf(ber, "t{O}", &ber_state, &ber_srp_bytes_M); if (berror == -1) { maj = GSS_S_FAILURE; min = GSS_S_DEFECTIVE_TOKEN; goto error; } /* * This is mostly impossible, as state IS the "t" field. * More a double check for proper decoding. */ if ((int) ber_state != state || ber_srp_bytes_M->bv_len == 0) { maj = GSS_S_FAILURE; goto error; } srp_print_hex(ber_srp_bytes_M->bv_val, (int) ber_srp_bytes_M->bv_len, "_srp_gss_validate_client(accept_sec_ctx) received bytes_M"); if (srp_context_handle->bUseCSRP) { srp_verifier_verify_session( srp_context_handle->srp_ver, ber_srp_bytes_M->bv_val, &bytes_HAMK); if (!bytes_HAMK) { min = rpc_s_auth_mut_fail; } } else { hServer = srp_context_handle->hServer; min = cli_rpc_srp_verifier_verify_session( hServer->hBinding, srp_context_handle->srp_ver, ber_srp_bytes_M->bv_val, (int) ber_srp_bytes_M->bv_len, &bytes_HAMK, &bytes_HAMK_len); } if (min || !bytes_HAMK) { /* * Bad password will cause this to fail. Do not bail on error here. * Merely generate a NULL HAMK response below, to complete the * SRP protocol exchange with the client. The client tests for an * empty HAMK token, and formulates the proper error. */ srp_debug_printf("_srp_gss_validate_client: " "srp_verifier_verify_session() failed!!!\n"); } /* * ASN.1 encode the bytes_HAMK value, sending it back to the client * for validation. That will complete the authentication process if that * succeeds. */ ber_resp = ber_alloc_t(LBER_USE_DER); if (!ber_resp) { maj = GSS_S_FAILURE; min = ENOMEM; goto error; } if (min == 0) { if (srp_context_handle->bUseCSRP) { bytes_HAMK_len = srp_verifier_get_session_key_length(srp_context_handle->srp_ver); } else { /* * Generate HAMK response. When min is an error code, * an empty HAMK response (zero length) is created. */ min = cli_rpc_srp_verifier_get_session_key_length( hServer->hBinding, srp_context_handle->srp_ver, (long *) &ber_HAMK.bv_len); if (min) { maj = GSS_S_FAILURE; goto error; } } } ber_HAMK.bv_val = (void *) bytes_HAMK; ber_HAMK.bv_len = bytes_HAMK_len; berror = ber_printf(ber_resp, "t{O}", (int) SRP_AUTH_SERVER_VALIDATE, &ber_HAMK); if (berror == -1) { maj = GSS_S_FAILURE; goto error; } berror = ber_flatten(ber_resp, &flatten); if (berror == -1) { maj = GSS_S_FAILURE; goto error; } output_token->value = gssalloc_calloc(1, flatten->bv_len); if (!output_token->value) { maj = GSS_S_FAILURE; goto error; } output_token->length = flatten->bv_len; memcpy(output_token->value, flatten->bv_val, flatten->bv_len); /* * From server's perspective, authentication is done. However, * there is a final output_token to process by gss_init_sec_context(). */ maj = GSS_S_COMPLETE; error: if (ber_srp_bytes_M) { ber_bvfree(ber_srp_bytes_M); } if (!srp_context_handle->bUseCSRP && bytes_HAMK) { free((void *) bytes_HAMK); } ber_bvfree(flatten); ber_free(ber, 1); ber_free(ber_resp, 1); if (maj) { if (min) { *minor_status = min; } } return maj; }