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