1 | // |
2 | // X509Certificate.cpp |
3 | // |
4 | // Library: NetSSL_OpenSSL |
5 | // Package: SSLCore |
6 | // Module: X509Certificate |
7 | // |
8 | // Copyright (c) 2006-2017, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Net/X509Certificate.h" |
16 | #include "Poco/Net/SSLException.h" |
17 | #include "Poco/Net/SSLManager.h" |
18 | #include "Poco/Net/DNS.h" |
19 | #include "Poco/TemporaryFile.h" |
20 | #include "Poco/FileStream.h" |
21 | #include "Poco/StreamCopier.h" |
22 | #include "Poco/String.h" |
23 | #include "Poco/RegularExpression.h" |
24 | #include "Poco/DateTimeParser.h" |
25 | #include <openssl/pem.h> |
26 | #include <openssl/x509v3.h> |
27 | #include <openssl/err.h> |
28 | |
29 | |
30 | namespace Poco { |
31 | namespace Net { |
32 | |
33 | |
34 | X509Certificate::X509Certificate(std::istream& istr): |
35 | Poco::Crypto::X509Certificate(istr) |
36 | { |
37 | } |
38 | |
39 | |
40 | X509Certificate::X509Certificate(const std::string& path): |
41 | Poco::Crypto::X509Certificate(path) |
42 | { |
43 | } |
44 | |
45 | |
46 | X509Certificate::X509Certificate(X509* pCert): |
47 | Poco::Crypto::X509Certificate(pCert) |
48 | { |
49 | } |
50 | |
51 | |
52 | X509Certificate::X509Certificate(X509* pCert, bool shared): |
53 | Poco::Crypto::X509Certificate(pCert, shared) |
54 | { |
55 | } |
56 | |
57 | |
58 | X509Certificate::X509Certificate(const Poco::Crypto::X509Certificate& cert): |
59 | Poco::Crypto::X509Certificate(cert) |
60 | { |
61 | } |
62 | |
63 | |
64 | X509Certificate& X509Certificate::operator = (const Poco::Crypto::X509Certificate& cert) |
65 | { |
66 | X509Certificate tmp(cert); |
67 | swap(tmp); |
68 | return *this; |
69 | } |
70 | |
71 | |
72 | X509Certificate::~X509Certificate() |
73 | { |
74 | } |
75 | |
76 | |
77 | bool X509Certificate::verify(const std::string& hostName) const |
78 | { |
79 | return verify(*this, hostName); |
80 | } |
81 | |
82 | |
83 | bool X509Certificate::verify(const Poco::Crypto::X509Certificate& certificate, const std::string& hostName) |
84 | { |
85 | #if OPENSSL_VERSION_NUMBER < 0x10002000L |
86 | std::string commonName; |
87 | std::set<std::string> dnsNames; |
88 | certificate.extractNames(commonName, dnsNames); |
89 | if (!commonName.empty()) dnsNames.insert(commonName); |
90 | bool ok = (dnsNames.find(hostName) != dnsNames.end()); |
91 | if (!ok) |
92 | { |
93 | for (std::set<std::string>::const_iterator it = dnsNames.begin(); !ok && it != dnsNames.end(); ++it) |
94 | { |
95 | try |
96 | { |
97 | // two cases: name contains wildcards or not |
98 | if (containsWildcards(*it)) |
99 | { |
100 | // a compare by IPAddress is not possible with wildcards |
101 | // only allow compare by name |
102 | ok = matchWildcard(*it, hostName); |
103 | } |
104 | else |
105 | { |
106 | // it depends on hostName whether we compare by IP or by alias |
107 | IPAddress ip; |
108 | if (IPAddress::tryParse(hostName, ip)) |
109 | { |
110 | // compare by IP |
111 | const HostEntry& heData = DNS::resolve(*it); |
112 | const HostEntry::AddressList& addr = heData.addresses(); |
113 | HostEntry::AddressList::const_iterator it = addr.begin(); |
114 | HostEntry::AddressList::const_iterator itEnd = addr.end(); |
115 | for (; it != itEnd && !ok; ++it) |
116 | { |
117 | ok = (*it == ip); |
118 | } |
119 | } |
120 | else |
121 | { |
122 | ok = Poco::icompare(*it, hostName) == 0; |
123 | } |
124 | } |
125 | } |
126 | catch (NoAddressFoundException&) |
127 | { |
128 | } |
129 | catch (HostNotFoundException&) |
130 | { |
131 | } |
132 | } |
133 | } |
134 | return ok; |
135 | #else |
136 | if (X509_check_host(const_cast<X509*>(certificate.certificate()), hostName.c_str(), hostName.length(), 0, NULL) == 1) |
137 | { |
138 | return true; |
139 | } |
140 | else |
141 | { |
142 | IPAddress ip; |
143 | if (IPAddress::tryParse(hostName, ip)) |
144 | { |
145 | return (X509_check_ip_asc(const_cast<X509*>(certificate.certificate()), hostName.c_str(), 0) == 1); |
146 | } |
147 | } |
148 | return false; |
149 | #endif |
150 | } |
151 | |
152 | |
153 | bool X509Certificate::containsWildcards(const std::string& commonName) |
154 | { |
155 | return (commonName.find('*') != std::string::npos || commonName.find('?') != std::string::npos); |
156 | } |
157 | |
158 | |
159 | bool X509Certificate::matchWildcard(const std::string& wildcard, const std::string& hostName) |
160 | { |
161 | // fix wildcards |
162 | std::string wildcardExpr("^" ); |
163 | wildcardExpr += Poco::replace(wildcard, "." , "\\." ); |
164 | Poco::replaceInPlace(wildcardExpr, "*" , ".*" ); |
165 | Poco::replaceInPlace(wildcardExpr, "..*" , ".*" ); |
166 | Poco::replaceInPlace(wildcardExpr, "?" , ".?" ); |
167 | Poco::replaceInPlace(wildcardExpr, "..?" , ".?" ); |
168 | wildcardExpr += "$" ; |
169 | |
170 | Poco::RegularExpression expr(wildcardExpr, Poco::RegularExpression::RE_CASELESS); |
171 | return expr.match(hostName); |
172 | } |
173 | |
174 | |
175 | } } // namespace Poco::Net |
176 | |