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
30namespace Poco {
31namespace Net {
32
33
34X509Certificate::X509Certificate(std::istream& istr):
35 Poco::Crypto::X509Certificate(istr)
36{
37}
38
39
40X509Certificate::X509Certificate(const std::string& path):
41 Poco::Crypto::X509Certificate(path)
42{
43}
44
45
46X509Certificate::X509Certificate(X509* pCert):
47 Poco::Crypto::X509Certificate(pCert)
48{
49}
50
51
52X509Certificate::X509Certificate(X509* pCert, bool shared):
53 Poco::Crypto::X509Certificate(pCert, shared)
54{
55}
56
57
58X509Certificate::X509Certificate(const Poco::Crypto::X509Certificate& cert):
59 Poco::Crypto::X509Certificate(cert)
60{
61}
62
63
64X509Certificate& X509Certificate::operator = (const Poco::Crypto::X509Certificate& cert)
65{
66 X509Certificate tmp(cert);
67 swap(tmp);
68 return *this;
69}
70
71
72X509Certificate::~X509Certificate()
73{
74}
75
76
77bool X509Certificate::verify(const std::string& hostName) const
78{
79 return verify(*this, hostName);
80}
81
82
83bool 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
153bool X509Certificate::containsWildcards(const std::string& commonName)
154{
155 return (commonName.find('*') != std::string::npos || commonName.find('?') != std::string::npos);
156}
157
158
159bool 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