Bug: chromium:1322914 Change-Id: Ic9b93a733290c40ac7c64e67d1e4f611f2f8b46c Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/62966 Auto-Submit: Bob Beck <bbe@google.com> Reviewed-by: Adam Langley <agl@google.com> Commit-Queue: Bob Beck <bbe@google.com>chromium-stable
parent
fa343af32b
commit
8e7025e3df
13 changed files with 358 additions and 370 deletions
@ -1,171 +0,0 @@ |
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "ip_address.h" |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <climits> |
||||
|
||||
#include <openssl/base.h> |
||||
|
||||
namespace bssl { |
||||
|
||||
namespace fillins { |
||||
|
||||
IPAddress::IPAddress() {} |
||||
|
||||
IPAddress::IPAddress(const uint8_t *address, size_t address_len) |
||||
: addr_(reinterpret_cast<const char *>(address), address_len) {} |
||||
|
||||
IPAddress::IPAddress(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) { |
||||
addr_.reserve(4); |
||||
addr_.push_back(b0); |
||||
addr_.push_back(b1); |
||||
addr_.push_back(b2); |
||||
addr_.push_back(b3); |
||||
} |
||||
|
||||
IPAddress::IPAddress(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, |
||||
uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8, uint8_t b9, |
||||
uint8_t b10, uint8_t b11, uint8_t b12, uint8_t b13, |
||||
uint8_t b14, uint8_t b15) { |
||||
addr_.reserve(16); |
||||
addr_.push_back(b0); |
||||
addr_.push_back(b1); |
||||
addr_.push_back(b2); |
||||
addr_.push_back(b3); |
||||
addr_.push_back(b4); |
||||
addr_.push_back(b5); |
||||
addr_.push_back(b6); |
||||
addr_.push_back(b7); |
||||
addr_.push_back(b8); |
||||
addr_.push_back(b9); |
||||
addr_.push_back(b10); |
||||
addr_.push_back(b11); |
||||
addr_.push_back(b12); |
||||
addr_.push_back(b13); |
||||
addr_.push_back(b14); |
||||
addr_.push_back(b15); |
||||
} |
||||
|
||||
// static
|
||||
IPAddress IPAddress::AllZeros(size_t num_zero_bytes) { |
||||
BSSL_CHECK(num_zero_bytes <= 16u); |
||||
IPAddress result; |
||||
result.addr_.reserve(num_zero_bytes); |
||||
for (size_t i = 0; i < num_zero_bytes; ++i) { |
||||
result.addr_.push_back(0u); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
// static
|
||||
IPAddress IPAddress::IPv4AllZeros() { return AllZeros(kIPv4AddressSize); } |
||||
|
||||
bool IPAddress::IsIPv4() const { return addr_.size() == kIPv4AddressSize; } |
||||
|
||||
bool IPAddress::IsIPv6() const { return addr_.size() == kIPv6AddressSize; } |
||||
|
||||
bool IPAddress::IsValid() const { return IsIPv4() || IsIPv6(); } |
||||
|
||||
const uint8_t *IPAddress::data() const { |
||||
return reinterpret_cast<const uint8_t *>(addr_.data()); |
||||
} |
||||
|
||||
size_t IPAddress::size() const { return addr_.size(); } |
||||
|
||||
const IPAddressBytes &IPAddress::bytes() const { return addr_; } |
||||
|
||||
static IPAddress ConvertIPv4ToIPv4MappedIPv6(const IPAddress &address) { |
||||
BSSL_CHECK(address.IsIPv4()); |
||||
// IPv4-mapped addresses are formed by:
|
||||
// <80 bits of zeros> + <16 bits of ones> + <32-bit IPv4 address>.
|
||||
uint8_t bytes[16]; |
||||
memset(bytes, 0, 10); |
||||
memset(bytes + 10, 0xff, 2); |
||||
memcpy(bytes + 12, address.data(), address.size()); |
||||
return IPAddress(bytes, sizeof(bytes)); |
||||
} |
||||
|
||||
// Note that this function assumes:
|
||||
// * |ip_address| is at least |prefix_length_in_bits| (bits) long;
|
||||
// * |ip_prefix| is at least |prefix_length_in_bits| (bits) long.
|
||||
static bool IPAddressPrefixCheck(const uint8_t *ip_address, |
||||
const uint8_t *ip_prefix, |
||||
size_t prefix_length_in_bits) { |
||||
// Compare all the bytes that fall entirely within the prefix.
|
||||
size_t num_entire_bytes_in_prefix = prefix_length_in_bits / 8; |
||||
for (size_t i = 0; i < num_entire_bytes_in_prefix; ++i) { |
||||
if (ip_address[i] != ip_prefix[i]) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
// In case the prefix was not a multiple of 8, there will be 1 byte
|
||||
// which is only partially masked.
|
||||
size_t remaining_bits = prefix_length_in_bits % 8; |
||||
if (remaining_bits != 0) { |
||||
uint8_t mask = 0xFF << (8 - remaining_bits); |
||||
size_t i = num_entire_bytes_in_prefix; |
||||
if ((ip_address[i] & mask) != (ip_prefix[i] & mask)) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool IPAddressMatchesPrefix(const IPAddress &ip_address, |
||||
const IPAddress &ip_prefix, |
||||
size_t prefix_length_in_bits) { |
||||
// Both the input IP address and the prefix IP address should be either IPv4
|
||||
// or IPv6.
|
||||
BSSL_CHECK(ip_address.IsValid()); |
||||
BSSL_CHECK(ip_prefix.IsValid()); |
||||
|
||||
BSSL_CHECK(prefix_length_in_bits <= ip_prefix.size() * 8); |
||||
|
||||
// In case we have an IPv6 / IPv4 mismatch, convert the IPv4 addresses to
|
||||
// IPv6 addresses in order to do the comparison.
|
||||
if (ip_address.size() != ip_prefix.size()) { |
||||
if (ip_address.IsIPv4()) { |
||||
return IPAddressMatchesPrefix(ConvertIPv4ToIPv4MappedIPv6(ip_address), |
||||
ip_prefix, prefix_length_in_bits); |
||||
} |
||||
return IPAddressMatchesPrefix(ip_address, |
||||
ConvertIPv4ToIPv4MappedIPv6(ip_prefix), |
||||
96 + prefix_length_in_bits); |
||||
} |
||||
|
||||
return IPAddressPrefixCheck(ip_address.data(), ip_prefix.data(), |
||||
prefix_length_in_bits); |
||||
} |
||||
|
||||
static unsigned CommonPrefixLength(const IPAddress &a1, const IPAddress &a2) { |
||||
BSSL_CHECK(a1.size() == a2.size()); |
||||
for (size_t i = 0; i < a1.size(); ++i) { |
||||
uint8_t diff = a1.bytes()[i] ^ a2.bytes()[i]; |
||||
if (!diff) |
||||
continue; |
||||
for (unsigned j = 0; j < CHAR_BIT; ++j) { |
||||
if (diff & (1 << (CHAR_BIT - 1))) |
||||
return i * CHAR_BIT + j; |
||||
diff <<= 1; |
||||
} |
||||
abort(); |
||||
} |
||||
return a1.size() * CHAR_BIT; |
||||
} |
||||
|
||||
unsigned MaskPrefixLength(const IPAddress &mask) { |
||||
uint8_t all_ones[16]; |
||||
const size_t mask_len = std::min(mask.size(), sizeof(all_ones)); |
||||
memset(all_ones, 0xff, mask_len); |
||||
return CommonPrefixLength(mask, IPAddress(all_ones, mask_len)); |
||||
} |
||||
|
||||
} // namespace fillins
|
||||
|
||||
} // namespace bssl
|
@ -1,62 +0,0 @@ |
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BSSL_FILLINS_IP_ADDRESS |
||||
#define BSSL_FILLINS_IP_ADDRESS |
||||
|
||||
#include <openssl/base.h> |
||||
|
||||
#include <stddef.h> |
||||
#include <stdint.h> |
||||
|
||||
#include <string> |
||||
|
||||
namespace bssl { |
||||
|
||||
namespace fillins { |
||||
|
||||
typedef std::string IPAddressBytes; |
||||
|
||||
class OPENSSL_EXPORT IPAddress { |
||||
public: |
||||
enum : size_t { kIPv4AddressSize = 4, kIPv6AddressSize = 16 }; |
||||
|
||||
IPAddress(); |
||||
IPAddress(const uint8_t *address, size_t address_len); |
||||
IPAddress(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3); |
||||
IPAddress(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, |
||||
uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, |
||||
uint8_t b8, uint8_t b9, uint8_t b10, uint8_t b11, |
||||
uint8_t b12, uint8_t b13, uint8_t b14, uint8_t b15); |
||||
|
||||
static IPAddress IPv4AllZeros(); |
||||
|
||||
bool IsIPv4() const; |
||||
bool IsIPv6() const; |
||||
bool IsValid() const; |
||||
|
||||
const uint8_t *data() const; |
||||
size_t size() const; |
||||
const IPAddressBytes &bytes() const; |
||||
|
||||
bool operator==(const IPAddress &other) const { |
||||
return addr_ == other.addr_; |
||||
} |
||||
|
||||
private: |
||||
static IPAddress AllZeros(size_t num_zero_bytes); |
||||
std::string addr_; |
||||
}; |
||||
|
||||
OPENSSL_EXPORT bool IPAddressMatchesPrefix(const IPAddress &ip_address, |
||||
const IPAddress &ip_prefix, |
||||
size_t prefix_length_in_bits); |
||||
|
||||
OPENSSL_EXPORT unsigned MaskPrefixLength(const IPAddress &mask); |
||||
|
||||
} // namespace fillins
|
||||
|
||||
} // namespace bssl
|
||||
|
||||
#endif // BSSL_FILLINS_IP_ADDRESS
|
@ -0,0 +1,50 @@ |
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "ip_util.h" |
||||
|
||||
namespace bssl { |
||||
|
||||
bool IsValidNetmask(der::Input mask) { |
||||
if (mask.Length() != kIPv4AddressSize && mask.Length() != kIPv6AddressSize) { |
||||
return false; |
||||
} |
||||
|
||||
for (size_t i = 0; i < mask.Length(); i++) { |
||||
uint8_t b = mask[i]; |
||||
if (b != 0xff) { |
||||
// b must be all ones followed by all zeros, so ~b must be all zeros
|
||||
// followed by all ones.
|
||||
uint8_t inv = ~b; |
||||
if ((inv & (inv + 1)) != 0) { |
||||
return false; |
||||
} |
||||
// The remaining bytes must be all zeros.
|
||||
for (size_t j = i + 1; j < mask.Length(); j++) { |
||||
if (mask[j] != 0) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool IPAddressMatchesWithNetmask(der::Input addr1, |
||||
der::Input addr2, |
||||
der::Input mask) { |
||||
if (addr1.Length() != addr2.Length() || addr1.Length() != mask.Length()) { |
||||
return false; |
||||
} |
||||
for (size_t i = 0; i < addr1.Length(); i++) { |
||||
if ((addr1[i] & mask[i]) != (addr2[i] & mask[i])) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
} // namespace net
|
@ -0,0 +1,29 @@ |
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BSSL_PKI_IP_UTIL_H_ |
||||
#define BSSL_PKI_IP_UTIL_H_ |
||||
|
||||
#include "fillins/openssl_util.h" |
||||
|
||||
#include "input.h" |
||||
|
||||
namespace bssl { |
||||
|
||||
inline constexpr size_t kIPv4AddressSize = 4; |
||||
inline constexpr size_t kIPv6AddressSize = 16; |
||||
|
||||
// Returns whether `mask` is a valid netmask. I.e., whether it the length of an
|
||||
// IPv4 or IPv6 address, and is some number of ones, followed by some number of
|
||||
// zeros.
|
||||
OPENSSL_EXPORT bool IsValidNetmask(der::Input mask); |
||||
|
||||
// Returns whether `addr1` and `addr2` are equal under the netmask `mask`.
|
||||
OPENSSL_EXPORT bool IPAddressMatchesWithNetmask(der::Input addr1, |
||||
der::Input addr2, |
||||
der::Input mask); |
||||
|
||||
} // namespace net
|
||||
|
||||
#endif // BSSL_PKI_IP_UTIL_H_
|
@ -0,0 +1,107 @@ |
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "ip_util.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include "input.h" |
||||
#include <gtest/gtest.h> |
||||
|
||||
namespace bssl { |
||||
|
||||
TEST(IPUtilTest, IsValidNetmask) { |
||||
uint8_t kWrongSize[3] = {0xff, 0xff, 0xff}; |
||||
EXPECT_FALSE(IsValidNetmask(der::Input(kWrongSize))); |
||||
|
||||
// All zeros is a valid netmask.
|
||||
uint8_t kZeroIPv4[4] = {0}; |
||||
EXPECT_TRUE(IsValidNetmask(der::Input(kZeroIPv4))); |
||||
uint8_t kZeroIPv6[16] = {0}; |
||||
EXPECT_TRUE(IsValidNetmask(der::Input(kZeroIPv6))); |
||||
|
||||
// Test all valid non-zero IPv4 netmasks.
|
||||
for (int i = 0; i < 4; i++) { |
||||
uint8_t addr[4] = {0}; |
||||
memset(addr, 0xff, i); |
||||
for (int shift = 0; shift < 8; shift++) { |
||||
addr[i] = 0xff << shift; |
||||
EXPECT_TRUE(IsValidNetmask(der::Input(addr))); |
||||
} |
||||
} |
||||
|
||||
// Test all valid non-zero IPv6 netmasks.
|
||||
for (int i = 0; i < 16; i++) { |
||||
uint8_t addr[16] = {0}; |
||||
memset(addr, 0xff, i); |
||||
for (int shift = 0; shift < 8; shift++) { |
||||
addr[i] = 0xff << shift; |
||||
EXPECT_TRUE(IsValidNetmask(der::Input(addr))); |
||||
} |
||||
} |
||||
|
||||
// Error within a byte.
|
||||
uint8_t kInvalidIPv4[4] = {0xff, 0xff, 0x81, 0x00}; |
||||
EXPECT_FALSE(IsValidNetmask(der::Input(kInvalidIPv4))); |
||||
uint8_t kInvalidIPv6[16] = {0xff, 0xff, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
||||
EXPECT_FALSE(IsValidNetmask(der::Input(kInvalidIPv6))); |
||||
|
||||
// Error at the end.
|
||||
uint8_t kInvalidIPv4_2[4] = {0xff, 0xff, 0x80, 0x01}; |
||||
EXPECT_FALSE(IsValidNetmask(der::Input(kInvalidIPv4_2))); |
||||
uint8_t kInvalidIPv6_2[16] = {0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; |
||||
EXPECT_FALSE(IsValidNetmask(der::Input(kInvalidIPv6_2))); |
||||
|
||||
// Leading zero.
|
||||
uint8_t kInvalidIPv4_3[4] = {0x00, 0xff, 0x80, 0x00}; |
||||
EXPECT_FALSE(IsValidNetmask(der::Input(kInvalidIPv4_3))); |
||||
uint8_t kInvalidIPv6_3[16] = {0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; |
||||
EXPECT_FALSE(IsValidNetmask(der::Input(kInvalidIPv6_3))); |
||||
} |
||||
|
||||
TEST(IPUtilTest, IPAddressMatchesWithNetmask) { |
||||
// Under a zero mask, any two addresses are equal.
|
||||
{ |
||||
uint8_t kMask[4] = {0}; |
||||
uint8_t kAddr1[4] = {1, 2, 3, 4}; |
||||
uint8_t kAddr2[4] = {255, 254, 253, 252}; |
||||
EXPECT_TRUE(IPAddressMatchesWithNetmask( |
||||
der::Input(kAddr1), der::Input(kAddr1), der::Input(kMask))); |
||||
EXPECT_TRUE(IPAddressMatchesWithNetmask( |
||||
der::Input(kAddr1), der::Input(kAddr2), der::Input(kMask))); |
||||
} |
||||
|
||||
// Under an all ones mask, all bits of the address are checked.
|
||||
{ |
||||
uint8_t kMask[4] = {0xff, 0xff, 0xff, 0xff}; |
||||
uint8_t kAddr1[4] = {1, 2, 3, 4}; |
||||
uint8_t kAddr2[4] = {255, 254, 253, 252}; |
||||
uint8_t kAddr3[4] = {1, 2, 3, 5}; |
||||
EXPECT_TRUE(IPAddressMatchesWithNetmask( |
||||
der::Input(kAddr1), der::Input(kAddr1), der::Input(kMask))); |
||||
EXPECT_FALSE(IPAddressMatchesWithNetmask( |
||||
der::Input(kAddr1), der::Input(kAddr2), der::Input(kMask))); |
||||
EXPECT_FALSE(IPAddressMatchesWithNetmask( |
||||
der::Input(kAddr1), der::Input(kAddr3), der::Input(kMask))); |
||||
} |
||||
|
||||
// In general, only masked bits are considered.
|
||||
{ |
||||
uint8_t kMask[4] = {0xff, 0xff, 0x80, 0x00}; |
||||
uint8_t kAddr1[4] = {1, 2, 3, 4}; |
||||
uint8_t kAddr2[4] = {1, 2, 0x7f, 0xff}; |
||||
uint8_t kAddr3[4] = {2, 2, 3, 4}; |
||||
EXPECT_TRUE(IPAddressMatchesWithNetmask( |
||||
der::Input(kAddr1), der::Input(kAddr1), der::Input(kMask))); |
||||
EXPECT_TRUE(IPAddressMatchesWithNetmask( |
||||
der::Input(kAddr1), der::Input(kAddr2), der::Input(kMask))); |
||||
EXPECT_FALSE(IPAddressMatchesWithNetmask( |
||||
der::Input(kAddr1), der::Input(kAddr3), der::Input(kMask))); |
||||
} |
||||
} |
||||
|
||||
} // namespace net
|
Loading…
Reference in new issue