protected override TSyncChallengeResult Challenge( ref SASLChallengeArguments args, SASLCredentialsSCRAMForClient credentials ) { var prevState = this._state; var challengeResult = SASLChallengeResult.MoreToCome; var writeOffset = args.WriteOffset; Int32 errorCode; Int32 nextState; if (credentials == null) { errorCode = SCRAMCommon.ERROR_CLIENT_SUPPLIED_WITH_INVALID_CREDENTIALS; nextState = -1; } else { switch (prevState) { case STATE_INITIAL: errorCode = this.PerformInitial(ref args, credentials, ref writeOffset); nextState = STATE_FINAL; break; case STATE_FINAL: // Read server response and write our response errorCode = this.PerformFinal(ref args, credentials, ref writeOffset); nextState = STATE_VALIDATE; break; case STATE_VALIDATE: errorCode = this.PerformValidate(ref args, credentials); nextState = STATE_COMPLETED; challengeResult = SASLChallengeResult.Completed; break; default: nextState = -1; errorCode = SCRAMCommon.ERROR_INVALID_STATE; break; } } TSyncChallengeResult retVal; if (errorCode != 0 || nextState < 0 || Interlocked.CompareExchange(ref this._state, nextState, prevState) != prevState) { retVal = new TSyncChallengeResult(errorCode == 0 ? SCRAMCommon.ERROR_CONCURRENT_ACCESS : errorCode); } else { retVal = new TSyncChallengeResult((writeOffset - args.WriteOffset, challengeResult)); } return(retVal); }
private Int32 PerformInitial( ref SASLChallengeArguments args, SASLCredentialsSCRAMForClient credentials, ref Int32 writeOffset ) { var encoding = args.Encoding; var array = args.WriteArray; // Write "n,,n=<username>,r=<client nonce> // Write "n,,n=" array.CurrentMaxCapacity = encoding.Encoding.GetByteCount(SCRAMCommon.CLIENT_FIRST_PREFIX_1 + SCRAMCommon.CLIENT_FIRST_PREFIX_2); encoding.WriteString(array.Array, ref writeOffset, SCRAMCommon.CLIENT_FIRST_PREFIX_1); var messageStart = writeOffset; encoding.WriteString(array.Array, ref writeOffset, SCRAMCommon.CLIENT_FIRST_PREFIX_2); // Write processed and escaped username SASLUtility.WriteString( credentials.Username, encoding, array, ref writeOffset, normalizer: (name, nameIdx) => { // Escape the ',' and '=' characters, since they are reserved. switch (name[nameIdx]) { case ',': return(SCRAMCommon.COMMA_ESCAPE); case '=': return(SCRAMCommon.EQUALS_ESCAPE); default: return(default); }