]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/asio/ssl/impl/rfc2818_verification.ipp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / asio / ssl / impl / rfc2818_verification.ipp
CommitLineData
7c673cae
FG
1//
2// ssl/impl/rfc2818_verification.ipp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
92f5a8d4 5// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7c673cae
FG
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP
12#define BOOST_ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19
b32b8144
FG
20#include <cctype>
21#include <cstring>
22#include <boost/asio/ip/address.hpp>
23#include <boost/asio/ssl/rfc2818_verification.hpp>
24#include <boost/asio/ssl/detail/openssl_types.hpp>
7c673cae
FG
25
26#include <boost/asio/detail/push_options.hpp>
27
28namespace boost {
29namespace asio {
30namespace ssl {
31
7c673cae
FG
32bool rfc2818_verification::operator()(
33 bool preverified, verify_context& ctx) const
34{
35 using namespace std; // For memcmp.
36
37 // Don't bother looking at certificates that have failed pre-verification.
38 if (!preverified)
39 return false;
40
41 // We're only interested in checking the certificate at the end of the chain.
42 int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());
43 if (depth > 0)
44 return true;
45
46 // Try converting the host name to an address. If it is an address then we
47 // need to look for an IP address in the certificate rather than a host name.
48 boost::system::error_code ec;
b32b8144 49 ip::address address = ip::make_address(host_, ec);
7c673cae
FG
50 bool is_address = !ec;
51
52 X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
53
54 // Go through the alternate names in the certificate looking for matching DNS
55 // or IP address entries.
56 GENERAL_NAMES* gens = static_cast<GENERAL_NAMES*>(
57 X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0));
58 for (int i = 0; i < sk_GENERAL_NAME_num(gens); ++i)
59 {
60 GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i);
61 if (gen->type == GEN_DNS && !is_address)
62 {
63 ASN1_IA5STRING* domain = gen->d.dNSName;
64 if (domain->type == V_ASN1_IA5STRING && domain->data && domain->length)
65 {
66 const char* pattern = reinterpret_cast<const char*>(domain->data);
67 std::size_t pattern_length = domain->length;
68 if (match_pattern(pattern, pattern_length, host_.c_str()))
69 {
70 GENERAL_NAMES_free(gens);
71 return true;
72 }
73 }
74 }
75 else if (gen->type == GEN_IPADD && is_address)
76 {
77 ASN1_OCTET_STRING* ip_address = gen->d.iPAddress;
78 if (ip_address->type == V_ASN1_OCTET_STRING && ip_address->data)
79 {
80 if (address.is_v4() && ip_address->length == 4)
81 {
82 ip::address_v4::bytes_type bytes = address.to_v4().to_bytes();
83 if (memcmp(bytes.data(), ip_address->data, 4) == 0)
84 {
85 GENERAL_NAMES_free(gens);
86 return true;
87 }
88 }
89 else if (address.is_v6() && ip_address->length == 16)
90 {
91 ip::address_v6::bytes_type bytes = address.to_v6().to_bytes();
92 if (memcmp(bytes.data(), ip_address->data, 16) == 0)
93 {
94 GENERAL_NAMES_free(gens);
95 return true;
96 }
97 }
98 }
99 }
100 }
101 GENERAL_NAMES_free(gens);
102
103 // No match in the alternate names, so try the common names. We should only
104 // use the "most specific" common name, which is the last one in the list.
105 X509_NAME* name = X509_get_subject_name(cert);
106 int i = -1;
107 ASN1_STRING* common_name = 0;
108 while ((i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0)
109 {
110 X509_NAME_ENTRY* name_entry = X509_NAME_get_entry(name, i);
111 common_name = X509_NAME_ENTRY_get_data(name_entry);
112 }
113 if (common_name && common_name->data && common_name->length)
114 {
115 const char* pattern = reinterpret_cast<const char*>(common_name->data);
116 std::size_t pattern_length = common_name->length;
117 if (match_pattern(pattern, pattern_length, host_.c_str()))
118 return true;
119 }
120
121 return false;
122}
123
124bool rfc2818_verification::match_pattern(const char* pattern,
125 std::size_t pattern_length, const char* host)
126{
127 using namespace std; // For tolower.
128
129 const char* p = pattern;
130 const char* p_end = p + pattern_length;
131 const char* h = host;
132
133 while (p != p_end && *h)
134 {
135 if (*p == '*')
136 {
137 ++p;
138 while (*h && *h != '.')
139 if (match_pattern(p, p_end - p, h++))
140 return true;
141 }
142 else if (tolower(*p) == tolower(*h))
143 {
144 ++p;
145 ++h;
146 }
147 else
148 {
149 return false;
150 }
151 }
152
153 return p == p_end && !*h;
154}
155
7c673cae
FG
156} // namespace ssl
157} // namespace asio
158} // namespace boost
159
160#include <boost/asio/detail/pop_options.hpp>
161
162#endif // BOOST_ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP