PostgreSQL Source Code git master
fe-secure-common.h File Reference
#include "libpq-fe.h"
Include dependency graph for fe-secure-common.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

int pq_verify_peer_name_matches_certificate_name (PGconn *conn, const char *namedata, size_t namelen, char **store_name)
 
int pq_verify_peer_name_matches_certificate_ip (PGconn *conn, const unsigned char *ipdata, size_t iplen, char **store_name)
 
bool pq_verify_peer_name_matches_certificate (PGconn *conn)
 

Function Documentation

◆ pq_verify_peer_name_matches_certificate()

bool pq_verify_peer_name_matches_certificate ( PGconn conn)

Definition at line 252 of file fe-secure-common.c.

253{
254 char *host = conn->connhost[conn->whichhost].host;
255 int rc;
256 int names_examined = 0;
257 char *first_name = NULL;
258
259 /*
260 * If told not to verify the peer name, don't do it. Return true
261 * indicating that the verification was successful.
262 */
263 if (strcmp(conn->sslmode, "verify-full") != 0)
264 return true;
265
266 /* Check that we have a hostname to compare with. */
267 if (!(host && host[0] != '\0'))
268 {
269 libpq_append_conn_error(conn, "host name must be specified for a verified SSL connection");
270 return false;
271 }
272
273 rc = pgtls_verify_peer_name_matches_certificate_guts(conn, &names_examined, &first_name);
274
275 if (rc == 0)
276 {
277 /*
278 * No match. Include the name from the server certificate in the error
279 * message, to aid debugging broken configurations. If there are
280 * multiple names, only print the first one to avoid an overly long
281 * error message.
282 */
283 if (names_examined > 1)
284 {
286 libpq_ngettext("server certificate for \"%s\" (and %d other name) does not match host name \"%s\"",
287 "server certificate for \"%s\" (and %d other names) does not match host name \"%s\"",
288 names_examined - 1),
289 first_name, names_examined - 1, host);
291 }
292 else if (names_examined == 1)
293 {
294 libpq_append_conn_error(conn, "server certificate for \"%s\" does not match host name \"%s\"",
295 first_name, host);
296 }
297 else
298 {
299 libpq_append_conn_error(conn, "could not get server's host name from server certificate");
300 }
301 }
302
303 /* clean up */
304 free(first_name);
305
306 return (rc == 1);
307}
void libpq_append_conn_error(PGconn *conn, const char *fmt,...)
Definition: fe-misc.c:1381
int pgtls_verify_peer_name_matches_certificate_guts(PGconn *conn, int *names_examined, char **first_name)
#define free(a)
Definition: header.h:65
#define libpq_ngettext(s, p, n)
Definition: libpq-int.h:924
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
PGconn * conn
Definition: streamutil.c:53
char * host
Definition: libpq-int.h:366
char * sslmode
Definition: libpq-int.h:411
PQExpBufferData errorMessage
Definition: libpq-int.h:660
int whichhost
Definition: libpq-int.h:472
pg_conn_host * connhost
Definition: libpq-int.h:473

References appendPQExpBuffer(), appendPQExpBufferChar(), conn, pg_conn::connhost, pg_conn::errorMessage, free, pg_conn_host::host, libpq_append_conn_error(), libpq_ngettext, pgtls_verify_peer_name_matches_certificate_guts(), pg_conn::sslmode, and pg_conn::whichhost.

Referenced by open_client_SSL().

◆ pq_verify_peer_name_matches_certificate_ip()

int pq_verify_peer_name_matches_certificate_ip ( PGconn conn,
const unsigned char *  ipdata,
size_t  iplen,
char **  store_name 
)

Definition at line 157 of file fe-secure-common.c.

161{
162 char *addrstr;
163 int match = 0;
164 char *host = conn->connhost[conn->whichhost].host;
165 int family;
166 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
167 char sebuf[PG_STRERROR_R_BUFLEN];
168
169 *store_name = NULL;
170
171 if (!(host && host[0] != '\0'))
172 {
173 libpq_append_conn_error(conn, "host name must be specified");
174 return -1;
175 }
176
177 /*
178 * The data from the certificate is in network byte order. Convert our
179 * host string to network-ordered bytes as well, for comparison. (The host
180 * string isn't guaranteed to actually be an IP address, so if this
181 * conversion fails we need to consider it a mismatch rather than an
182 * error.)
183 */
184 if (iplen == 4)
185 {
186 /* IPv4 */
187 struct in_addr addr;
188
189 family = AF_INET;
190
191 /*
192 * The use of inet_aton() is deliberate; we accept alternative IPv4
193 * address notations that are accepted by inet_aton() but not
194 * inet_pton() as server addresses.
195 */
196 if (inet_aton(host, &addr))
197 {
198 if (memcmp(ipdata, &addr.s_addr, iplen) == 0)
199 match = 1;
200 }
201 }
202
203 /*
204 * If they don't have inet_pton(), skip this. Then, an IPv6 address in a
205 * certificate will cause an error.
206 */
207#ifdef HAVE_INET_PTON
208 else if (iplen == 16)
209 {
210 /* IPv6 */
211 struct in6_addr addr;
212
213 family = AF_INET6;
214
215 if (inet_pton(AF_INET6, host, &addr) == 1)
216 {
217 if (memcmp(ipdata, &addr.s6_addr, iplen) == 0)
218 match = 1;
219 }
220 }
221#endif
222 else
223 {
224 /*
225 * Not IPv4 or IPv6. We could ignore the field, but leniency seems
226 * wrong given the subject matter.
227 */
228 libpq_append_conn_error(conn, "certificate contains IP address with invalid length %zu",
229 iplen);
230 return -1;
231 }
232
233 /* Generate a human-readable representation of the certificate's IP. */
234 addrstr = pg_inet_net_ntop(family, ipdata, 8 * iplen, tmp, sizeof(tmp));
235 if (!addrstr)
236 {
237 libpq_append_conn_error(conn, "could not convert certificate's IP address to string: %s",
238 strerror_r(errno, sebuf, sizeof(sebuf)));
239 return -1;
240 }
241
242 *store_name = strdup(addrstr);
243 return match;
244}
#define PG_STRERROR_R_BUFLEN
Definition: port.h:257
char * pg_inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
Definition: inet_net_ntop.c:77
int inet_aton(const char *cp, struct in_addr *addr)
Definition: inet_aton.c:56
#define strerror_r
Definition: port.h:256

References conn, pg_conn::connhost, pg_conn_host::host, inet_aton(), libpq_append_conn_error(), pg_inet_net_ntop(), PG_STRERROR_R_BUFLEN, strerror_r, and pg_conn::whichhost.

Referenced by openssl_verify_peer_name_matches_certificate_ip().

◆ pq_verify_peer_name_matches_certificate_name()

int pq_verify_peer_name_matches_certificate_name ( PGconn conn,
const char *  namedata,
size_t  namelen,
char **  store_name 
)

Definition at line 87 of file fe-secure-common.c.

90{
91 char *name;
92 int result;
93 char *host = conn->connhost[conn->whichhost].host;
94
95 *store_name = NULL;
96
97 if (!(host && host[0] != '\0'))
98 {
99 libpq_append_conn_error(conn, "host name must be specified");
100 return -1;
101 }
102
103 /*
104 * There is no guarantee the string returned from the certificate is
105 * NULL-terminated, so make a copy that is.
106 */
107 name = malloc(namelen + 1);
108 if (name == NULL)
109 {
110 libpq_append_conn_error(conn, "out of memory");
111 return -1;
112 }
113 memcpy(name, namedata, namelen);
114 name[namelen] = '\0';
115
116 /*
117 * Reject embedded NULLs in certificate common or alternative name to
118 * prevent attacks like CVE-2009-4034.
119 */
120 if (namelen != strlen(name))
121 {
122 free(name);
123 libpq_append_conn_error(conn, "SSL certificate's name contains embedded null");
124 return -1;
125 }
126
127 if (pg_strcasecmp(name, host) == 0)
128 {
129 /* Exact name match */
130 result = 1;
131 }
132 else if (wildcard_certificate_match(name, host))
133 {
134 /* Matched wildcard name */
135 result = 1;
136 }
137 else
138 {
139 result = 0;
140 }
141
142 *store_name = name;
143 return result;
144}
static bool wildcard_certificate_match(const char *pattern, const char *string)
#define malloc(a)
Definition: header.h:50
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
const char * name

References conn, pg_conn::connhost, free, pg_conn_host::host, libpq_append_conn_error(), malloc, name, pg_strcasecmp(), pg_conn::whichhost, and wildcard_certificate_match().

Referenced by openssl_verify_peer_name_matches_certificate_name().