PostgreSQL Source Code  git master
fe-secure-common.c File Reference
#include "postgres_fe.h"
#include "fe-secure-common.h"
#include "libpq-int.h"
#include "pqexpbuffer.h"
Include dependency graph for fe-secure-common.c:

Go to the source code of this file.

Functions

static bool wildcard_certificate_match (const char *pattern, const char *string)
 
int pq_verify_peer_name_matches_certificate_name (PGconn *conn, const char *namedata, size_t namelen, 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 153 of file fe-secure-common.c.

References pg_conn::connhost, pg_conn::errorMessage, free, pg_conn_host::host, libpq_gettext, libpq_ngettext, pgtls_verify_peer_name_matches_certificate_guts(), printfPQExpBuffer(), pg_conn::sslmode, and pg_conn::whichhost.

Referenced by open_client_SSL().

154 {
155  char *host = conn->connhost[conn->whichhost].host;
156  int rc;
157  int names_examined = 0;
158  char *first_name = NULL;
159 
160  /*
161  * If told not to verify the peer name, don't do it. Return true
162  * indicating that the verification was successful.
163  */
164  if (strcmp(conn->sslmode, "verify-full") != 0)
165  return true;
166 
167  /* Check that we have a hostname to compare with. */
168  if (!(host && host[0] != '\0'))
169  {
171  libpq_gettext("host name must be specified for a verified SSL connection\n"));
172  return false;
173  }
174 
175  rc = pgtls_verify_peer_name_matches_certificate_guts(conn, &names_examined, &first_name);
176 
177  if (rc == 0)
178  {
179  /*
180  * No match. Include the name from the server certificate in the error
181  * message, to aid debugging broken configurations. If there are
182  * multiple names, only print the first one to avoid an overly long
183  * error message.
184  */
185  if (names_examined > 1)
186  {
188  libpq_ngettext("server certificate for \"%s\" (and %d other name) does not match host name \"%s\"\n",
189  "server certificate for \"%s\" (and %d other names) does not match host name \"%s\"\n",
190  names_examined - 1),
191  first_name, names_examined - 1, host);
192  }
193  else if (names_examined == 1)
194  {
196  libpq_gettext("server certificate for \"%s\" does not match host name \"%s\"\n"),
197  first_name, host);
198  }
199  else
200  {
202  libpq_gettext("could not get server's host name from server certificate\n"));
203  }
204  }
205 
206  /* clean up */
207  if (first_name)
208  free(first_name);
209 
210  return (rc == 1);
211 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
int pgtls_verify_peer_name_matches_certificate_guts(PGconn *conn, int *names_examined, char **first_name)
char * host
Definition: libpq-int.h:312
pg_conn_host * connhost
Definition: libpq-int.h:403
#define libpq_ngettext(s, p, n)
Definition: libpq-int.h:793
char * sslmode
Definition: libpq-int.h:358
PQExpBufferData errorMessage
Definition: libpq-int.h:511
#define free(a)
Definition: header.h:65
int whichhost
Definition: libpq-int.h:402
#define libpq_gettext(x)
Definition: libpq-int.h:792

◆ 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 85 of file fe-secure-common.c.

References pg_conn::connhost, pg_conn::errorMessage, free, pg_conn_host::host, libpq_gettext, malloc, name, pg_strcasecmp(), printfPQExpBuffer(), pg_conn::whichhost, and wildcard_certificate_match().

Referenced by openssl_verify_peer_name_matches_certificate_name().

88 {
89  char *name;
90  int result;
91  char *host = conn->connhost[conn->whichhost].host;
92 
93  *store_name = NULL;
94 
95  if (!(host && host[0] != '\0'))
96  {
98  libpq_gettext("host name must be specified\n"));
99  return -1;
100  }
101 
102  /*
103  * There is no guarantee the string returned from the certificate is
104  * NULL-terminated, so make a copy that is.
105  */
106  name = malloc(namelen + 1);
107  if (name == NULL)
108  {
110  libpq_gettext("out of memory\n"));
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);
124  libpq_gettext("SSL certificate's name contains embedded null\n"));
125  return -1;
126  }
127 
128  if (pg_strcasecmp(name, host) == 0)
129  {
130  /* Exact name match */
131  result = 1;
132  }
133  else if (wildcard_certificate_match(name, host))
134  {
135  /* Matched wildcard name */
136  result = 1;
137  }
138  else
139  {
140  result = 0;
141  }
142 
143  *store_name = name;
144  return result;
145 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
char * host
Definition: libpq-int.h:312
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define malloc(a)
Definition: header.h:50
pg_conn_host * connhost
Definition: libpq-int.h:403
static bool wildcard_certificate_match(const char *pattern, const char *string)
PQExpBufferData errorMessage
Definition: libpq-int.h:511
#define free(a)
Definition: header.h:65
const char * name
Definition: encode.c:521
int whichhost
Definition: libpq-int.h:402
#define libpq_gettext(x)
Definition: libpq-int.h:792

◆ wildcard_certificate_match()

static bool wildcard_certificate_match ( const char *  pattern,
const char *  string 
)
static

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

References pg_strcasecmp().

Referenced by pq_verify_peer_name_matches_certificate_name().

44 {
45  int lenpat = strlen(pattern);
46  int lenstr = strlen(string);
47 
48  /* If we don't start with a wildcard, it's not a match (rule 1 & 2) */
49  if (lenpat < 3 ||
50  pattern[0] != '*' ||
51  pattern[1] != '.')
52  return false;
53 
54  /* If pattern is longer than the string, we can never match */
55  if (lenpat > lenstr)
56  return false;
57 
58  /*
59  * If string does not end in pattern (minus the wildcard), we don't match
60  */
61  if (pg_strcasecmp(pattern + 1, string + lenstr - lenpat + 1) != 0)
62  return false;
63 
64  /*
65  * If there is a dot left of where the pattern started to match, we don't
66  * match (rule 3)
67  */
68  if (strchr(string, '.') < string + lenstr - lenpat)
69  return false;
70 
71  /* String ended with pattern, and didn't have a dot before, so we match */
72  return true;
73 }
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36