diff options
author | Jack Lloyd <[email protected]> | 2017-04-27 11:20:19 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-04-27 11:20:19 -0400 |
commit | 14ee7e88c2041c26c6d8fa7e0cae6a200b6f9799 (patch) | |
tree | 4cc4ca4dbb3cb3bcf76a229f535a3b17488b7ead /src/lib | |
parent | 8bfb889c27cf461f5575624d19a0ad39ef8d2e4e (diff) | |
parent | 289cc25709b081cd112d47db66c4f2fbf4609583 (diff) |
Merge GH #1017 Complete wildcard handling for X.509 certificates
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/utils/parsing.cpp | 88 |
1 files changed, 84 insertions, 4 deletions
diff --git a/src/lib/utils/parsing.cpp b/src/lib/utils/parsing.cpp index cd0c2409e..7583767f0 100644 --- a/src/lib/utils/parsing.cpp +++ b/src/lib/utils/parsing.cpp @@ -2,6 +2,7 @@ * Various string utils and parsing functions * (C) 1999-2007,2013,2014,2015 Jack Lloyd * (C) 2015 Simon Warta (Kullo GmbH) +* (C) 2017 René Korthaus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -12,6 +13,7 @@ #include <botan/loadstor.h> #include <limits> #include <set> +#include <algorithm> namespace Botan { @@ -337,22 +339,100 @@ std::string replace_char(const std::string& str, char from_char, char to_char) bool host_wildcard_match(const std::string& issued, const std::string& host) { if(issued == host) + { return true; + } - if(issued.size() > 2 && issued[0] == '*' && issued[1] == '.') + if(std::count(issued.begin(), issued.end(), '*') > 1) + { + return false; + } + + // first try to match the base, then the left-most label + // which can contain exactly one wildcard at any position + if(issued.size() > 2) { size_t host_i = host.find('.'); if(host_i == std::string::npos || host_i == host.size() - 1) + { return false; + } + + size_t issued_i = issued.find('.'); + if(issued_i == std::string::npos || issued_i == issued.size() - 1) + { + return false; + } const std::string host_base = host.substr(host_i + 1); - const std::string issued_base = issued.substr(2); + const std::string issued_base = issued.substr(issued_i + 1); + + // if anything but the left-most label doesn't equal, + // we are already out here + if(host_base != issued_base) + { + return false; + } + + // compare the left-most labels + std::string host_prefix = host.substr(0, host_i); + + if(host_prefix.empty()) + { + return false; + } + + const std::string issued_prefix = issued.substr(0, issued_i); + + // if split_on would work on strings with less than 2 items, + // the if/else block would not be necessary + if(issued_prefix == "*") + { + return true; + } + + std::vector<std::string> p; - if(host_base == issued_base) + if(issued_prefix[0] == '*') + { + p = std::vector<std::string>{"", issued_prefix.substr(1, issued_prefix.size())}; + } + else if(issued_prefix[issued_prefix.size()-1] == '*') + { + p = std::vector<std::string>{issued_prefix.substr(0, issued_prefix.size() - 1), ""}; + } + else + { + p = split_on(issued_prefix, '*'); + } + + if(p.size() != 2) + { + return false; + } + + // match anything before and after the wildcard character + const std::string first = p[0]; + const std::string last = p[1]; + + if(host_prefix.substr(0, first.size()) == first) + { + host_prefix.erase(0, first.size()); + } + + // nothing to match anymore + if(last.empty()) + { return true; } + if(host_prefix.size() >= last.size() && + host_prefix.substr(host_prefix.size() - last.size(), last.size()) == last) + { + return true; + } + } + return false; } - } |