1 //
2 // X509Certificate.cpp
3 //
4 // Library: NetSSL_OpenSSL
5 // Package: SSLCore
6 // Module: X509Certificate
7 //
8 // Copyright (c) 2006-2009, 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
X509Certificate(std::istream & istr)34 X509Certificate::X509Certificate(std::istream& istr):
35 Poco::Crypto::X509Certificate(istr)
36 {
37 }
38
39
X509Certificate(const std::string & path)40 X509Certificate::X509Certificate(const std::string& path):
41 Poco::Crypto::X509Certificate(path)
42 {
43 }
44
45
X509Certificate(X509 * pCert)46 X509Certificate::X509Certificate(X509* pCert):
47 Poco::Crypto::X509Certificate(pCert)
48 {
49 }
50
51
X509Certificate(X509 * pCert,bool shared)52 X509Certificate::X509Certificate(X509* pCert, bool shared):
53 Poco::Crypto::X509Certificate(pCert, shared)
54 {
55 }
56
57
X509Certificate(const Poco::Crypto::X509Certificate & cert)58 X509Certificate::X509Certificate(const Poco::Crypto::X509Certificate& cert):
59 Poco::Crypto::X509Certificate(cert)
60 {
61 }
62
63
X509Certificate(const X509Certificate & cert)64 X509Certificate::X509Certificate(const X509Certificate& cert):
65 Poco::Crypto::X509Certificate(cert)
66 {
67 }
68
69
X509Certificate(X509Certificate && cert)70 X509Certificate::X509Certificate(X509Certificate&& cert) noexcept:
71 Poco::Crypto::X509Certificate(std::move(cert))
72 {
73 }
74
75
operator =(const Poco::Crypto::X509Certificate & cert)76 X509Certificate& X509Certificate::operator = (const Poco::Crypto::X509Certificate& cert)
77 {
78 X509Certificate tmp(cert);
79 swap(tmp);
80 return *this;
81 }
82
83
operator =(const X509Certificate & cert)84 X509Certificate& X509Certificate::operator = (const X509Certificate& cert)
85 {
86 X509Certificate tmp(cert);
87 swap(tmp);
88 return *this;
89 }
90
91
operator =(X509Certificate && cert)92 X509Certificate& X509Certificate::operator = (X509Certificate&& cert) noexcept
93 {
94 Poco::Crypto::X509Certificate::operator = (std::move(cert));
95 return *this;
96 }
97
98
~X509Certificate()99 X509Certificate::~X509Certificate()
100 {
101 }
102
103
verify(const std::string & hostName) const104 bool X509Certificate::verify(const std::string& hostName) const
105 {
106 return verify(*this, hostName);
107 }
108
109
verify(const Poco::Crypto::X509Certificate & certificate,const std::string & hostName)110 bool X509Certificate::verify(const Poco::Crypto::X509Certificate& certificate, const std::string& hostName)
111 {
112 #if OPENSSL_VERSION_NUMBER < 0x10002000L
113 std::string commonName;
114 std::set<std::string> dnsNames;
115 certificate.extractNames(commonName, dnsNames);
116 if (!commonName.empty()) dnsNames.insert(commonName);
117 bool ok = (dnsNames.find(hostName) != dnsNames.end());
118 if (!ok)
119 {
120 for (std::set<std::string>::const_iterator it = dnsNames.begin(); !ok && it != dnsNames.end(); ++it)
121 {
122 try
123 {
124 // two cases: name contains wildcards or not
125 if (containsWildcards(*it))
126 {
127 // a compare by IPAddress is not possible with wildcards
128 // only allow compare by name
129 ok = matchWildcard(*it, hostName);
130 }
131 else
132 {
133 // it depends on hostName whether we compare by IP or by alias
134 IPAddress ip;
135 if (IPAddress::tryParse(hostName, ip))
136 {
137 // compare by IP
138 const HostEntry& heData = DNS::resolve(*it);
139 const HostEntry::AddressList& addr = heData.addresses();
140 HostEntry::AddressList::const_iterator it = addr.begin();
141 HostEntry::AddressList::const_iterator itEnd = addr.end();
142 for (; it != itEnd && !ok; ++it)
143 {
144 ok = (*it == ip);
145 }
146 }
147 else
148 {
149 ok = Poco::icompare(*it, hostName) == 0;
150 }
151 }
152 }
153 catch (NoAddressFoundException&)
154 {
155 }
156 catch (HostNotFoundException&)
157 {
158 }
159 }
160 }
161 return ok;
162 #else
163 if (X509_check_host(const_cast<X509*>(certificate.certificate()), hostName.c_str(), hostName.length(), 0, NULL) == 1)
164 {
165 return true;
166 }
167 else
168 {
169 IPAddress ip;
170 if (IPAddress::tryParse(hostName, ip))
171 {
172 return (X509_check_ip_asc(const_cast<X509*>(certificate.certificate()), hostName.c_str(), 0) == 1);
173 }
174 }
175 return false;
176 #endif
177 }
178
179
containsWildcards(const std::string & commonName)180 bool X509Certificate::containsWildcards(const std::string& commonName)
181 {
182 return (commonName.find('*') != std::string::npos || commonName.find('?') != std::string::npos);
183 }
184
185
matchWildcard(const std::string & wildcard,const std::string & hostName)186 bool X509Certificate::matchWildcard(const std::string& wildcard, const std::string& hostName)
187 {
188 // fix wildcards
189 std::string wildcardExpr("^");
190 wildcardExpr += Poco::replace(wildcard, ".", "\\.");
191 Poco::replaceInPlace(wildcardExpr, "*", ".*");
192 Poco::replaceInPlace(wildcardExpr, "..*", ".*");
193 Poco::replaceInPlace(wildcardExpr, "?", ".?");
194 Poco::replaceInPlace(wildcardExpr, "..?", ".?");
195 wildcardExpr += "$";
196
197 Poco::RegularExpression expr(wildcardExpr, Poco::RegularExpression::RE_CASELESS);
198 return expr.match(hostName);
199 }
200
201
202 } } // namespace Poco::Net
203