/// <summary> /// Read auth_verifier from binary reader. /// </summary> /// <param name="binaryReader">binary reader</param> /// <param name="authLength">auth_length</param> /// <returns>auth_varifier</returns> internal static auth_verifier_co_t?AuthVerifierFromBytes( BinaryReader binaryReader, ushort authLength) { if (authLength == 0) { return(null); } long currentPosition = binaryReader.BaseStream.Position; int fragLength = (int)binaryReader.BaseStream.Length; int authVerifierStartPos = fragLength - authLength - AUTH_VERIFIER_SIZE; binaryReader.BaseStream.Position = authVerifierStartPos; auth_verifier_co_t authVerifier = new auth_verifier_co_t(); authVerifier.auth_type = binaryReader.ReadByte(); authVerifier.auth_level = binaryReader.ReadByte(); authVerifier.auth_pad_length = binaryReader.ReadByte(); authVerifier.auth_reserved = binaryReader.ReadByte(); authVerifier.auth_context_id = binaryReader.ReadUInt32(); authVerifier.auth_value = binaryReader.ReadBytes(authLength); binaryReader.BaseStream.Position = authVerifierStartPos - authVerifier.auth_pad_length; authVerifier.auth_pad = binaryReader.ReadBytes(authVerifier.auth_pad_length); binaryReader.BaseStream.Position = currentPosition; return(authVerifier); }
/// <summary> /// Append verification_trailer to stub. /// </summary> /// <param name="verificationTrailer">verification_trailer</param> /// <exception cref="ArgumentNullException">Thrown when verificationTrailer is null.</exception> public void AppendVerificationTrailerToStub(verification_trailer_t verificationTrailer) { if (verificationTrailer == null) { throw new ArgumentNullException("verificationTrailer"); } if (stub == null) { stub = new byte[0]; } stub = RpceUtility.AppendVerificationTrailerToStub(stub, verificationTrailer); if (auth_verifier != null) { auth_verifier_co_t authVerifier = auth_verifier.Value; authVerifier.auth_pad_length = (byte)( RpceUtility.Align(stub.Length, RpceUtility.STUB_PAD_LENGTH) - stub.Length); authVerifier.auth_pad = new byte[authVerifier.auth_pad_length]; auth_verifier = authVerifier; } SetLength(); }
/// <summary> /// Encrypt stub and initial auth_token. /// </summary> public override void InitializeAuthenticationToken() { if (context.AuthenticationType == RpceAuthenticationType.RPC_C_AUTHN_NONE || context.AuthenticationLevel == RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_NONE) { // AUTHN_NONE and AUTHN_LEVEL_NONE, do nothing. return; } FieldInfo fieldInfo = this.GetType().GetField("auth_verifier"); if (fieldInfo == null) { // PDU has no auth_verifier field, do nothing. return; } auth_verifier_co_t?authVerifier = (auth_verifier_co_t?)fieldInfo.GetValue(this); if (authVerifier == null) { // PDU has no auth_verifier, do nothing. return; } if (PTYPE == RpcePacketType.Bind || PTYPE == RpcePacketType.AlterContext || PTYPE == RpcePacketType.Auth3) { //Bind PDU, First call to GSS_Init_sec_context, as specified in [RFC2743] section 2.2.1. //alter_context, rpc_auth_3, Second and subsequent calls to GSS_Init_sec_context, //as specified in [RFC2743] section 2.2.1. auth_verifier_co_t newAuthVerifier = authVerifier.Value; newAuthVerifier.auth_value = context.SecurityContext.Token; authVerifier = newAuthVerifier; } else if (PTYPE == RpcePacketType.BindAck || PTYPE == RpcePacketType.AlterContextResp) { auth_verifier_co_t newAuthVerifier = authVerifier.Value; newAuthVerifier.auth_value = context.SecurityContext.Token; authVerifier = newAuthVerifier; } else if (context.AuthenticationLevel != RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_DEFAULT && context.AuthenticationLevel != RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_CONNECT) { auth_verifier_co_t newAuthVerifier = authVerifier.Value; EncryptAndSign(ref newAuthVerifier); authVerifier = newAuthVerifier; } // set it back to PDU. fieldInfo.SetValue(this, authVerifier); }
/// <summary> /// Encrypt and sign to get auth_token. /// </summary> /// <param name="authVerifier">auth_verifier, not null.</param> private void EncryptAndSign(ref auth_verifier_co_t authVerifier) { //Request, Response, Fault //Get stub, pad the length to a multiple of 4 bytes. byte[] stub = GetStub(); if (stub == null) { stub = new byte[0]; SetStub(stub); } //Get SecurityBuffers. int stubSecBufIndex; int tokenSecBufIndex; SecurityBufferType readonlyFlag; List<SecurityBuffer> securityBufferList = new List<SecurityBuffer>(); if (context.SupportsHeaderSign) { readonlyFlag = SecurityBufferType.ReadOnlyWithChecksum; } else { readonlyFlag = SecurityBufferType.ReadOnly; } int headerSize = GetSize(); byte[] buf = new byte[ headerSize + stub.Length + RpceUtility.AuthVerifierGetSize(authVerifier)]; using (BinaryWriter binaryWriter = new BinaryWriter(new MemoryStream(buf))) { ToBytes(binaryWriter); } securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Data | readonlyFlag, ArrayUtility.SubArray(buf, 0, headerSize))); stubSecBufIndex = securityBufferList.Count; securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Data, ArrayUtility.ConcatenateArrays(stub, authVerifier.auth_pad))); securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Data | readonlyFlag, ArrayUtility.SubArray( buf, headerSize + stub.Length + authVerifier.auth_pad_length, RpceUtility.AUTH_VERIFIER_SIZE))); //8 == length of auth_verifier tokenSecBufIndex = securityBufferList.Count; securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Token, authVerifier.auth_value)); SecurityBuffer[] securityBuffers = securityBufferList.ToArray(); //encrypt and sign switch (context.AuthenticationLevel) { case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_CALL: //Same as RPC_C_AUTHN_LEVEL_PKT case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT: //the field "checksum" is the checksum value returned //by the underlying security service in response to //an integrity protection call context.SecurityContext.Sign(securityBuffers); authVerifier.auth_value = securityBuffers[tokenSecBufIndex].Buffer; break; case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_INTEGRITY: //the field "checksum" is the checksum value returned //by the underlying security service in response to //an integrity protection call context.SecurityContext.Sign(securityBuffers); authVerifier.auth_value = securityBuffers[tokenSecBufIndex].Buffer; break; case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_PRIVACY: //This level of service provides strong integrity protection for the //entire PDU, plus privacy protection for the body data only. //Therefore, only the bodies of the request, response and fault PDUs //are encrypted. context.SecurityContext.Encrypt(securityBuffers); authVerifier.auth_pad = ArrayUtility.SubArray(securityBuffers[stubSecBufIndex].Buffer, stub.Length); authVerifier.auth_value = securityBuffers[tokenSecBufIndex].Buffer; stub = ArrayUtility.SubArray(securityBuffers[stubSecBufIndex].Buffer, 0, stub.Length); SetStub(stub); break; //default do nothing. } //A client or a server that (during composing of a PDU) has allocated more space for //the authentication token than the security provider fills in SHOULD<36> fill in //the rest of the allocated space with zero octets. These zero octets are still //considered to belong to the authentication token part of the PDU. int padLength = (int)auth_length - authVerifier.auth_value.Length; if (padLength < 0) { throw new InvalidOperationException("Length of calculated auth_value is incorrect."); } else if (padLength > 0) { authVerifier.auth_value = ArrayUtility.ConcatenateArrays(authVerifier.auth_value, new byte[padLength]); } }
/// <summary> /// Decrypt and verify auth_token. /// </summary> /// <param name="authVerifier">auth_verifier, not null.</param> /// <returns>true if verify success; otherwise, false.</returns> private bool DecryptAndVerify(ref auth_verifier_co_t authVerifier) { bool result; //Just get the stub, no padding. byte[] stub = GetStub(); if (stub == null) { stub = new byte[0]; SetStub(stub); } //Get SecurityBuffers. int stubSecBufIndex; SecurityBufferType readonlyFlag; List<SecurityBuffer> securityBufferList = new List<SecurityBuffer>(); if (context.SupportsHeaderSign) { readonlyFlag = SecurityBufferType.ReadOnlyWithChecksum; } else { readonlyFlag = SecurityBufferType.ReadOnly; } int headerSize = GetSize(); securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Data | readonlyFlag, ArrayUtility.SubArray(PacketBytes, 0, headerSize))); stubSecBufIndex = securityBufferList.Count; securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Data, ArrayUtility.SubArray( PacketBytes, headerSize, stub.Length + authVerifier.auth_pad_length))); securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Data | readonlyFlag, ArrayUtility.SubArray( PacketBytes, headerSize + stub.Length + authVerifier.auth_pad_length, RpceUtility.AUTH_VERIFIER_SIZE))); securityBufferList.Add( new SecurityBuffer(SecurityBufferType.Token, authVerifier.auth_value)); SecurityBuffer[] securityBuffers = securityBufferList.ToArray(); //decrypt and validate switch (context.AuthenticationLevel) { case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_CALL: //Same as RPC_C_AUTHN_LEVEL_PKT case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT: //the field "checksum" is the checksum value returned //by the underlying security service in response to //an integrity protection call result = context.SecurityContext.Verify(securityBuffers); break; case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_INTEGRITY: //the field "checksum" is the checksum value returned //by the underlying security service in response to //an integrity protection call result = context.SecurityContext.Verify(securityBuffers); break; case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_PRIVACY: //This level of service provides strong integrity protection for the //entire PDU, plus privacy protection for the body data only. //Therefore, only the bodies of the request, response and fault PDUs //are encrypted. result = context.SecurityContext.Decrypt(securityBuffers); authVerifier.auth_pad = ArrayUtility.SubArray( securityBuffers[stubSecBufIndex].Buffer, stub.Length); stub = ArrayUtility.SubArray( securityBuffers[stubSecBufIndex].Buffer, 0, stub.Length); SetStub(stub); break; default: //do nothing. result = false; break; } return result; }
/// <summary> /// Create an instance of auth_verifier_co_t. /// </summary> /// <param name="packetType">PTYPE</param> /// <param name="stubLength">stub length</param> /// <param name="securityContext">security context</param> /// <param name="type">auth_type</param> /// <param name="level">auth_level</param> /// <param name="contextId">auth_context_id</param> /// <returns>an auth_verifier_co_t instance.</returns> internal static auth_verifier_co_t?AuthVerifierCreateInstance( RpcePacketType packetType, int stubLength, SecurityContext securityContext, RpceAuthenticationType type, RpceAuthenticationLevel level, uint contextId) { if (type == RpceAuthenticationType.RPC_C_AUTHN_NONE || level == RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_NONE) { return(null); } if (level <= RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_CONNECT) { if (packetType != RpcePacketType.Bind && packetType != RpcePacketType.BindAck && packetType != RpcePacketType.BindNak && packetType != RpcePacketType.AlterContext && packetType != RpcePacketType.AlterContextResp && packetType != RpcePacketType.Auth3) { return(null); } } //The authentication verifier is never present in bind_nak and shutdown PDUs if (packetType == RpcePacketType.BindNak || packetType == RpcePacketType.Shutdown) { return(null); } auth_verifier_co_t authVerifier = new auth_verifier_co_t(); //The sec_trailer structure MUST be 4-byte aligned with respect //to the beginning of the PDU. Padding octets MUST be used to //align the sec_trailer structure if its natural beginning is not //already 4-byte aligned. authVerifier.auth_pad_length = (byte)(Align(stubLength, STUB_PAD_LENGTH) - stubLength); authVerifier.auth_pad = new byte[authVerifier.auth_pad_length]; authVerifier.auth_type = (byte)type; authVerifier.auth_level = (byte)level; authVerifier.auth_reserved = 0; authVerifier.auth_context_id = contextId; if (securityContext != null) { if (packetType == RpcePacketType.Bind || packetType == RpcePacketType.BindAck || packetType == RpcePacketType.AlterContext || packetType == RpcePacketType.AlterContextResp || packetType == RpcePacketType.Auth3) { authVerifier.auth_value = securityContext.Token; } else if (level == RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_PRIVACY) { int authValueSize = Align( (int)securityContext.ContextSizes.SecurityTrailerSize, STUB_PAD_LENGTH); authVerifier.auth_value = new byte[authValueSize]; } else { // level == RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_INTEGRITY || // level == RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT || // level == RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_CALL int authValueSize = Align( (int)securityContext.ContextSizes.MaxSignatureSize, STUB_PAD_LENGTH); authVerifier.auth_value = new byte[authValueSize]; } } return(authVerifier); }
/// <summary> /// Encrypt and sign to get auth_token. /// </summary> /// <param name="authVerifier">auth_verifier, not null.</param> private void EncryptAndSign(ref auth_verifier_co_t authVerifier) { //Request, Response, Fault //Get stub, pad the length to a multiple of 4 bytes. byte[] stub = GetStub(); if (stub == null) { stub = new byte[0]; SetStub(stub); } //Get SecurityBuffers. int stubSecBufIndex; int tokenSecBufIndex; SecurityBufferType readonlyFlag; List <SecurityBuffer> securityBufferList = new List <SecurityBuffer>(); if (context.SupportsHeaderSign) { readonlyFlag = SecurityBufferType.ReadOnlyWithChecksum; } else { readonlyFlag = SecurityBufferType.ReadOnly; } int headerSize = GetSize(); byte[] buf = new byte[ headerSize + stub.Length + RpceUtility.AuthVerifierGetSize(authVerifier)]; using (BinaryWriter binaryWriter = new BinaryWriter(new MemoryStream(buf))) { ToBytes(binaryWriter); } securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Data | readonlyFlag, ArrayUtility.SubArray(buf, 0, headerSize))); stubSecBufIndex = securityBufferList.Count; securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Data, ArrayUtility.ConcatenateArrays(stub, authVerifier.auth_pad))); securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Data | readonlyFlag, ArrayUtility.SubArray( buf, headerSize + stub.Length + authVerifier.auth_pad_length, RpceUtility.AUTH_VERIFIER_SIZE))); //8 == length of auth_verifier tokenSecBufIndex = securityBufferList.Count; securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Token, authVerifier.auth_value)); SecurityBuffer[] securityBuffers = securityBufferList.ToArray(); //encrypt and sign switch (context.AuthenticationLevel) { case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_CALL: //Same as RPC_C_AUTHN_LEVEL_PKT case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT: //the field "checksum" is the checksum value returned //by the underlying security service in response to //an integrity protection call context.SecurityContext.Sign(securityBuffers); authVerifier.auth_value = securityBuffers[tokenSecBufIndex].Buffer; break; case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_INTEGRITY: //the field "checksum" is the checksum value returned //by the underlying security service in response to //an integrity protection call context.SecurityContext.Sign(securityBuffers); authVerifier.auth_value = securityBuffers[tokenSecBufIndex].Buffer; break; case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_PRIVACY: //This level of service provides strong integrity protection for the //entire PDU, plus privacy protection for the body data only. //Therefore, only the bodies of the request, response and fault PDUs //are encrypted. context.SecurityContext.Encrypt(securityBuffers); authVerifier.auth_pad = ArrayUtility.SubArray(securityBuffers[stubSecBufIndex].Buffer, stub.Length); authVerifier.auth_value = securityBuffers[tokenSecBufIndex].Buffer; stub = ArrayUtility.SubArray(securityBuffers[stubSecBufIndex].Buffer, 0, stub.Length); SetStub(stub); break; //default do nothing. } //A client or a server that (during composing of a PDU) has allocated more space for //the authentication token than the security provider fills in SHOULD<36> fill in //the rest of the allocated space with zero octets. These zero octets are still //considered to belong to the authentication token part of the PDU. int padLength = (int)auth_length - authVerifier.auth_value.Length; if (padLength < 0) { throw new InvalidOperationException("Length of calculated auth_value is incorrect."); } else if (padLength > 0) { authVerifier.auth_value = ArrayUtility.ConcatenateArrays(authVerifier.auth_value, new byte[padLength]); } }
/// <summary> /// Decrypt and verify auth_token. /// </summary> /// <param name="authVerifier">auth_verifier, not null.</param> /// <returns>true if verify success; otherwise, false.</returns> private bool DecryptAndVerify(ref auth_verifier_co_t authVerifier) { bool result; //Just get the stub, no padding. byte[] stub = GetStub(); if (stub == null) { stub = new byte[0]; SetStub(stub); } //Get SecurityBuffers. int stubSecBufIndex; SecurityBufferType readonlyFlag; List <SecurityBuffer> securityBufferList = new List <SecurityBuffer>(); if (context.SupportsHeaderSign) { readonlyFlag = SecurityBufferType.ReadOnlyWithChecksum; } else { readonlyFlag = SecurityBufferType.ReadOnly; } int headerSize = GetSize(); securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Data | readonlyFlag, ArrayUtility.SubArray(PacketBytes, 0, headerSize))); stubSecBufIndex = securityBufferList.Count; securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Data, ArrayUtility.SubArray( PacketBytes, headerSize, stub.Length + authVerifier.auth_pad_length))); securityBufferList.Add( new SecurityBuffer( SecurityBufferType.Data | readonlyFlag, ArrayUtility.SubArray( PacketBytes, headerSize + stub.Length + authVerifier.auth_pad_length, RpceUtility.AUTH_VERIFIER_SIZE))); securityBufferList.Add( new SecurityBuffer(SecurityBufferType.Token, authVerifier.auth_value)); SecurityBuffer[] securityBuffers = securityBufferList.ToArray(); //decrypt and validate switch (context.AuthenticationLevel) { case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_CALL: //Same as RPC_C_AUTHN_LEVEL_PKT case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT: //the field "checksum" is the checksum value returned //by the underlying security service in response to //an integrity protection call result = context.SecurityContext.Verify(securityBuffers); break; case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_INTEGRITY: //the field "checksum" is the checksum value returned //by the underlying security service in response to //an integrity protection call result = context.SecurityContext.Verify(securityBuffers); break; case RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_PKT_PRIVACY: //This level of service provides strong integrity protection for the //entire PDU, plus privacy protection for the body data only. //Therefore, only the bodies of the request, response and fault PDUs //are encrypted. result = context.SecurityContext.Decrypt(securityBuffers); authVerifier.auth_pad = ArrayUtility.SubArray( securityBuffers[stubSecBufIndex].Buffer, stub.Length); stub = ArrayUtility.SubArray( securityBuffers[stubSecBufIndex].Buffer, 0, stub.Length); SetStub(stub); break; default: //do nothing. result = false; break; } return(result); }
/// <summary> /// Decrypt stub and validate auth_token. /// </summary> public override bool ValidateAuthenticationToken() { FieldInfo fieldInfo = this.GetType().GetField("auth_verifier"); if (fieldInfo == null) { // PDU has no auth_verifier field, do nothing. return(true); } auth_verifier_co_t?authVerifier = (auth_verifier_co_t?)fieldInfo.GetValue(this); if (authVerifier == null) { // PDU has no auth_verifier, do nothing. return(true); } if (authVerifier.Value.auth_type != (byte)context.AuthenticationType || authVerifier.Value.auth_level != (byte)context.AuthenticationLevel || authVerifier.Value.auth_context_id != context.AuthenticationContextId) { //SecurityProvider in context is not the right SSPI to decrypt and validate the PDU. return(false); } bool result = true; if (PTYPE == RpcePacketType.Bind || PTYPE == RpcePacketType.AlterContext || PTYPE == RpcePacketType.Auth3) { ServerSecurityContext serverSspi = context.SecurityContext as ServerSecurityContext; if (serverSspi != null) { // Accept or Initialize should throw exception when token is incorrect. serverSspi.Accept(authVerifier.Value.auth_value); securityContextNeedContinueProcessing = serverSspi.NeedContinueProcessing; } } else if (PTYPE == RpcePacketType.BindAck || PTYPE == RpcePacketType.AlterContextResp) { ClientSecurityContext clientSspi = context.SecurityContext as ClientSecurityContext; if (clientSspi != null) { //BindAck only received on client. clientSspi.Initialize(authVerifier.Value.auth_value); securityContextNeedContinueProcessing = clientSspi.NeedContinueProcessing; } } else if (context.AuthenticationLevel != RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_DEFAULT && context.AuthenticationLevel != RpceAuthenticationLevel.RPC_C_AUTHN_LEVEL_CONNECT) { auth_verifier_co_t newAuthVerifier = authVerifier.Value; result = DecryptAndVerify(ref newAuthVerifier); authVerifier = newAuthVerifier; } return(result); }