// Copyright 2017 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/ntlm/ntlm_buffer_writer.h" #include #include #include "base/check_op.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" namespace net::ntlm { NtlmBufferWriter::NtlmBufferWriter(size_t buffer_len) : buffer_(buffer_len, 0) {} NtlmBufferWriter::~NtlmBufferWriter() = default; bool NtlmBufferWriter::CanWrite(size_t len) const { if (len == 0) return true; if (!GetBufferPtr()) return false; DCHECK_LE(GetCursor(), GetLength()); return (len <= GetLength()) && (GetCursor() <= GetLength() - len); } bool NtlmBufferWriter::WriteUInt16(uint16_t value) { return WriteUInt(value); } bool NtlmBufferWriter::WriteUInt32(uint32_t value) { return WriteUInt(value); } bool NtlmBufferWriter::WriteUInt64(uint64_t value) { return WriteUInt(value); } bool NtlmBufferWriter::WriteFlags(NegotiateFlags flags) { return WriteUInt32(static_cast(flags)); } bool NtlmBufferWriter::WriteBytes(base::span bytes) { if (bytes.size() == 0) return true; if (!CanWrite(bytes.size())) return false; memcpy(GetBufferPtrAtCursor(), bytes.data(), bytes.size()); AdvanceCursor(bytes.size()); return true; } bool NtlmBufferWriter::WriteZeros(size_t count) { if (count == 0) return true; if (!CanWrite(count)) return false; memset(GetBufferPtrAtCursor(), 0, count); AdvanceCursor(count); return true; } bool NtlmBufferWriter::WriteSecurityBuffer(SecurityBuffer sec_buf) { return WriteUInt16(sec_buf.length) && WriteUInt16(sec_buf.length) && WriteUInt32(sec_buf.offset); } bool NtlmBufferWriter::WriteAvPairHeader(TargetInfoAvId avid, uint16_t avlen) { if (!CanWrite(kAvPairHeaderLen)) return false; bool result = WriteUInt16(static_cast(avid)) && WriteUInt16(avlen); DCHECK(result); return result; } bool NtlmBufferWriter::WriteAvPairTerminator() { return WriteAvPairHeader(TargetInfoAvId::kEol, 0); } bool NtlmBufferWriter::WriteAvPair(const AvPair& pair) { if (!WriteAvPairHeader(pair)) return false; if (pair.avid == TargetInfoAvId::kFlags) { if (pair.avlen != sizeof(uint32_t)) return false; return WriteUInt32(static_cast(pair.flags)); } else { return WriteBytes(pair.buffer); } } bool NtlmBufferWriter::WriteUtf8String(const std::string& str) { return WriteBytes(base::as_bytes(base::make_span(str))); } bool NtlmBufferWriter::WriteUtf16AsUtf8String(const std::u16string& str) { std::string utf8 = base::UTF16ToUTF8(str); return WriteUtf8String(utf8); } bool NtlmBufferWriter::WriteUtf8AsUtf16String(const std::string& str) { std::u16string unicode = base::UTF8ToUTF16(str); return WriteUtf16String(unicode); } bool NtlmBufferWriter::WriteUtf16String(const std::u16string& str) { if (str.size() > std::numeric_limits::max() / 2) return false; size_t num_bytes = str.size() * 2; if (num_bytes == 0) return true; if (!CanWrite(num_bytes)) return false; #if defined(ARCH_CPU_BIG_ENDIAN) uint8_t* ptr = reinterpret_cast(GetBufferPtrAtCursor()); for (int i = 0; i < num_bytes; i += 2) { ptr[i] = str[i / 2] & 0xff; ptr[i + 1] = str[i / 2] >> 8; } #else memcpy(reinterpret_cast(GetBufferPtrAtCursor()), str.c_str(), num_bytes); #endif AdvanceCursor(num_bytes); return true; } bool NtlmBufferWriter::WriteSignature() { return WriteBytes(kSignature); } bool NtlmBufferWriter::WriteMessageType(MessageType message_type) { return WriteUInt32(static_cast(message_type)); } bool NtlmBufferWriter::WriteMessageHeader(MessageType message_type) { return WriteSignature() && WriteMessageType(message_type); } template bool NtlmBufferWriter::WriteUInt(T value) { size_t int_size = sizeof(T); if (!CanWrite(int_size)) return false; for (size_t i = 0; i < int_size; i++) { GetBufferPtrAtCursor()[i] = static_cast(value & 0xff); value >>= 8; } AdvanceCursor(int_size); return true; } void NtlmBufferWriter::SetCursor(size_t cursor) { DCHECK(GetBufferPtr() && cursor <= GetLength()); cursor_ = cursor; } } // namespace net::ntlm