Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0516c61

Browse files
committed
Add new clientcert hba option verify-full
This allows a login to require both that the cn of the certificatematches (like authentication type cert) *and* that anotherauthentication method (such as password or kerberos) succeeds as well.The old value of clientcert=1 maps to the new clientcert=verify-ca,clientcert=0 maps to the new clientcert=no-verify, and the new optionerify-full will add the validation of the CN.Author: Julian Markwort, Marius TimmerReviewed by: Magnus Hagander, Thomas Munro
1 parent6b9e875 commit0516c61

File tree

7 files changed

+156
-45
lines changed

7 files changed

+156
-45
lines changed

‎doc/src/sgml/client-auth.sgml

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -563,10 +563,17 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
563563
<para>
564564
In addition to the method-specific options listed below, there is one
565565
method-independent authentication option <literal>clientcert</literal>, which
566-
can be specified in any <literal>hostssl</literal> record. When set
567-
to <literal>1</literal>, this option requires the client to present a valid
568-
(trusted) SSL certificate, in addition to the other requirements of the
569-
authentication method.
566+
can be specified in any <literal>hostssl</literal> record.
567+
This option can be set to <literal>verify-ca</literal> or
568+
<literal>verify-full</literal>. Both options require the client
569+
to present a valid (trusted) SSL certificate, while
570+
<literal>verify-full</literal> additionally enforces that the
571+
<literal>cn</literal> (Common Name) in the certificate matches
572+
the username or an applicable mapping.
573+
This behavior is similar to the cert authentication method
574+
(see <xref linkend="auth-cert"/> ) but enables pairing
575+
the verification of client certificates with any authentication
576+
method that supports <literal>hostssl</literal> entries.
570577
</para>
571578
</listitem>
572579
</varlistentry>
@@ -1865,11 +1872,11 @@ host ... ldap ldapserver=ldap.example.net ldapbasedn="dc=example, dc=net" ldapse
18651872
<para>
18661873
In a <filename>pg_hba.conf</filename> record specifying certificate
18671874
authentication, the authentication option <literal>clientcert</literal> is
1868-
assumed to be <literal>1</literal>, and it cannot be turned off since a client
1869-
certificate is necessary for this method. What the <literal>cert</literal>
1870-
method adds tothebasic<literal>clientcert</literal>certificate validity test
1871-
is a check that the<literal>cn</literal>attribute matches the database
1872-
user name.
1875+
assumed to be <literal>verify-ca</literal> or <literal>verify-full</literal>,
1876+
and it cannot be turned off since a client certificate is necessary for this
1877+
method. Whatthe <literal>cert</literal>method adds to the basic
1878+
<literal>clientcert</literal>certificate validity test is a check that the
1879+
<literal>cn</literal> attribute matches the databaseuser name.
18731880
</para>
18741881
</sect1>
18751882

‎doc/src/sgml/runtime.sgml

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2316,13 +2316,25 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
23162316
(<acronym>CA</acronym>s) you trust in a file in the data
23172317
directory, set the parameter <xref linkend="guc-ssl-ca-file"/> in
23182318
<filename>postgresql.conf</filename> to the new file name, and add the
2319-
authentication option <literal>clientcert=1</literal> to the appropriate
2319+
authentication option <literal>clientcert=verify-ca</literal> or
2320+
<literal>clientcert=verify-full</literal> to the appropriate
23202321
<literal>hostssl</literal> line(s) in <filename>pg_hba.conf</filename>.
23212322
A certificate will then be requested from the client during SSL
23222323
connection startup. (See <xref linkend="libpq-ssl"/> for a description
2323-
of how to set up certificates on the client.) The server will
2324-
verify that the client's certificate is signed by one of the trusted
2325-
certificate authorities.
2324+
of how to set up certificates on the client.)
2325+
</para>
2326+
2327+
<para>
2328+
For a <literal>hostssl</literal> entry with
2329+
<literal>clientcert=verify-ca</literal>, the server will verify
2330+
that the client's certificate is signed by one of the trusted
2331+
certificate authorities. If <literal>clientcert=verify-full</literal>
2332+
is specified, the server will not only verify the certificate
2333+
chain, but it will also check whether the username or its mapping
2334+
matches the <literal>cn</literal> (Common Name) of the provided certificate.
2335+
Note that certificate chain validation is always ensured when the
2336+
<literal>cert</literal> authentication method is used
2337+
(see <xref linkend="auth-cert"/>).
23262338
</para>
23272339

23282340
<para>
@@ -2341,18 +2353,34 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
23412353
The <literal>clientcert</literal> authentication option is available for
23422354
all authentication methods, but only in <filename>pg_hba.conf</filename> lines
23432355
specified as <literal>hostssl</literal>. When <literal>clientcert</literal> is
2344-
not specified or is set to 0, the server will still verify any presented
2345-
client certificates against its CA file, if one is configured &mdash; but
2346-
it will not insist that a client certificate be presented.
2356+
not specified or is set to <literal>no-verify</literal>, the server will still
2357+
verify any presented client certificates against its CA file, if one is
2358+
configured &mdash; but it will not insist that a client certificate be presented.
2359+
</para>
2360+
2361+
<para>
2362+
There are two approaches to enforce that users provide a certificate during login.
2363+
</para>
2364+
2365+
<para>
2366+
The first approach makes use of the <literal>cert</literal> authentication
2367+
method for <literal>hostssl</literal> entries in <filename>pg_hba.conf</filename>,
2368+
such that the certificate itself is used for authentication while also
2369+
providing ssl connection security. See <xref linkend="auth-cert"/> for details.
2370+
(It is not necessary to specify any <literal>clientcert</literal> options
2371+
explicitly when using the <literal>cert</literal> authentication method.)
2372+
In this case, the <literal>cn</literal> (Common Name) provided in
2373+
the certificate is checked against the user name or an applicable mapping.
23472374
</para>
23482375

23492376
<para>
2350-
If you are setting up client certificates, you may wish to use
2351-
the <literal>cert</literal> authentication method, so that the certificates
2352-
control user authentication as well as providing connection security.
2353-
See <xref linkend="auth-cert"/> for details. (It is not necessary to
2354-
specify <literal>clientcert=1</literal> explicitly when using
2355-
the <literal>cert</literal> authentication method.)
2377+
The second approach combines any authentication method for <literal>hostssl</literal>
2378+
entries with the verification of client certificates by setting the
2379+
<literal>clientcert</literal> authentication option to <literal>verify-ca</literal>
2380+
or <literal>verify-full</literal>. The former option only enforces that
2381+
the certificate is valid, while the latter also ensures that the
2382+
<literal>cn</literal> (Common Name) in the certificate matches
2383+
the user name or an applicable mapping.
23562384
</para>
23572385
</sect2>
23582386

‎src/backend/libpq/auth.c

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ ClientAuthentication(Port *port)
363363
* current connection, so perform any verifications based on the hba
364364
* options field that should be done *before* the authentication here.
365365
*/
366-
if (port->hba->clientcert)
366+
if (port->hba->clientcert!=clientCertOff)
367367
{
368368
/* If we haven't loaded a root certificate store, fail */
369369
if (!secure_loaded_verify_locations())
@@ -581,24 +581,32 @@ ClientAuthentication(Port *port)
581581
status=CheckLDAPAuth(port);
582582
#else
583583
Assert(false);
584-
#endif
585-
break;
586-
587-
caseuaCert:
588-
#ifdefUSE_SSL
589-
status=CheckCertAuth(port);
590-
#else
591-
Assert(false);
592584
#endif
593585
break;
594586
caseuaRADIUS:
595587
status=CheckRADIUSAuth(port);
596588
break;
589+
caseuaCert:
590+
/* uaCert will be treated as if clientcert=verify-full (uaTrust) */
597591
caseuaTrust:
598592
status=STATUS_OK;
599593
break;
600594
}
601595

596+
if ((status==STATUS_OK&&port->hba->clientcert==clientCertFull)
597+
||port->hba->auth_method==uaCert)
598+
{
599+
/*
600+
* Make sure we only check the certificate if we use the cert method
601+
* or verify-full option.
602+
*/
603+
#ifdefUSE_SSL
604+
status=CheckCertAuth(port);
605+
#else
606+
Assert(false);
607+
#endif
608+
}
609+
602610
if (ClientAuthentication_hook)
603611
(*ClientAuthentication_hook) (port,status);
604612

@@ -2788,6 +2796,8 @@ errdetail_for_ldap(LDAP *ldap)
27882796
staticint
27892797
CheckCertAuth(Port*port)
27902798
{
2799+
intstatus_check_usermap=STATUS_ERROR;
2800+
27912801
Assert(port->ssl);
27922802

27932803
/* Make sure we have received a username in the certificate */
@@ -2800,8 +2810,23 @@ CheckCertAuth(Port *port)
28002810
returnSTATUS_ERROR;
28012811
}
28022812

2803-
/* Just pass the certificate CN to the usermap check */
2804-
returncheck_usermap(port->hba->usermap,port->user_name,port->peer_cn, false);
2813+
/* Just pass the certificate cn to the usermap check */
2814+
status_check_usermap=check_usermap(port->hba->usermap,port->user_name,port->peer_cn, false);
2815+
if (status_check_usermap!=STATUS_OK)
2816+
{
2817+
/*
2818+
* If clientcert=verify-full was specified and the authentication
2819+
* method is other than uaCert, log the reason for rejecting the
2820+
* authentication.
2821+
*/
2822+
if (port->hba->clientcert==clientCertFull&&port->hba->auth_method!=uaCert)
2823+
{
2824+
ereport(LOG,
2825+
(errmsg("certificate validation (clientcert=verify-full) failed for user \"%s\": cn mismatch",
2826+
port->user_name)));
2827+
}
2828+
}
2829+
returnstatus_check_usermap;
28052830
}
28062831
#endif
28072832

‎src/backend/libpq/hba.c

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,7 +1609,7 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
16091609
*/
16101610
if (parsedline->auth_method==uaCert)
16111611
{
1612-
parsedline->clientcert=true;
1612+
parsedline->clientcert=clientCertCA;
16131613
}
16141614

16151615
returnparsedline;
@@ -1675,23 +1675,38 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
16751675
*err_msg="clientcert can only be configured for \"hostssl\" rows";
16761676
return false;
16771677
}
1678-
if (strcmp(val,"1")==0)
1678+
if (strcmp(val,"1")==0
1679+
||strcmp(val,"verify-ca")==0)
16791680
{
1680-
hbaline->clientcert=true;
1681+
hbaline->clientcert=clientCertCA;
16811682
}
1682-
else
1683+
elseif (strcmp(val,"verify-full")==0)
1684+
{
1685+
hbaline->clientcert=clientCertFull;
1686+
}
1687+
elseif (strcmp(val,"0")==0
1688+
||strcmp(val,"no-verify")==0)
16831689
{
16841690
if (hbaline->auth_method==uaCert)
16851691
{
16861692
ereport(elevel,
16871693
(errcode(ERRCODE_CONFIG_FILE_ERROR),
1688-
errmsg("clientcert can not be set to0 when using \"cert\" authentication"),
1694+
errmsg("clientcert can not be set to\"no-verify\" when using \"cert\" authentication"),
16891695
errcontext("line %d of configuration file \"%s\"",
16901696
line_num,HbaFileName)));
1691-
*err_msg="clientcert can not be set to0 when using \"cert\" authentication";
1697+
*err_msg="clientcert can not be set to\"no-verify\" when using \"cert\" authentication";
16921698
return false;
16931699
}
1694-
hbaline->clientcert= false;
1700+
hbaline->clientcert=clientCertOff;
1701+
}
1702+
else
1703+
{
1704+
ereport(elevel,
1705+
(errcode(ERRCODE_CONFIG_FILE_ERROR),
1706+
errmsg("invalid value for clientcert: \"%s\"",val),
1707+
errcontext("line %d of configuration file \"%s\"",
1708+
line_num,HbaFileName)));
1709+
return false;
16951710
}
16961711
}
16971712
elseif (strcmp(name,"pamservice")==0)
@@ -2252,9 +2267,9 @@ gethba_options(HbaLine *hba)
22522267
options[noptions++]=
22532268
CStringGetTextDatum(psprintf("map=%s",hba->usermap));
22542269

2255-
if (hba->clientcert)
2270+
if (hba->clientcert!=clientCertOff)
22562271
options[noptions++]=
2257-
CStringGetTextDatum("clientcert=true");
2272+
CStringGetTextDatum(psprintf("clientcert=%s", (hba->clientcert==clientCertCA) ?"verify-ca" :"verify-full"));
22582273

22592274
if (hba->pamservice)
22602275
options[noptions++]=

‎src/include/libpq/hba.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ typedef enum ConnType
5858
ctHostNoSSL
5959
}ConnType;
6060

61+
typedefenumClientCertMode
62+
{
63+
clientCertOff,
64+
clientCertCA,
65+
clientCertFull
66+
}ClientCertMode;
67+
6168
typedefstructHbaLine
6269
{
6370
intlinenumber;
@@ -86,7 +93,7 @@ typedef struct HbaLine
8693
intldapscope;
8794
char*ldapprefix;
8895
char*ldapsuffix;
89-
boolclientcert;
96+
ClientCertModeclientcert;
9097
char*krb_realm;
9198
boolinclude_realm;
9299
boolcompat_realm;

‎src/test/ssl/t/001_ssltests.pl

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
if ($ENV{with_openssl}eq'yes')
1515
{
16-
plantests=>71;
16+
plantests=>75;
1717
}
1818
else
1919
{
@@ -378,6 +378,27 @@
378378
qr/SSL error/,
379379
"certificate authorization fails with revoked client cert");
380380

381+
# Check that connecting with auth-option verify-full in pg_hba:
382+
# works, iff username matches Common Name
383+
# fails, iff username doesn't match Common Name.
384+
$common_connstr =
385+
"sslrootcert=ssl/root+server_ca.crt sslmode=require dbname=verifydb hostaddr=$SERVERHOSTADDR";
386+
387+
test_connect_ok($common_connstr,
388+
"user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
389+
"auth_option clientcert=verify-full succeeds with matching username and Common Name");
390+
391+
test_connect_fails($common_connstr,
392+
"user=anotheruser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
393+
qr/FATAL/,
394+
"auth_option clientcert=verify-full fails with mismatching username and Common Name");
395+
396+
# Check that connecting with auth-optionverify-ca in pg_hba :
397+
# works, when username doesn't match Common Name
398+
test_connect_ok($common_connstr,
399+
"user=yetanotheruser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
400+
"auth_option clientcert=verify-ca succeeds with mismatching username and Common Name");
401+
381402
# intermediate client_ca.crt is provided by client, and isn't in server's ssl_ca_file
382403
switch_server_cert($node,'server-cn-only','root_ca');
383404
$common_connstr =

‎src/test/ssl/t/SSLServer.pm

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,10 @@ sub configure_test_server_for_ssl
103103
# Create test users and databases
104104
$node->psql('postgres',"CREATE USER ssltestuser");
105105
$node->psql('postgres',"CREATE USER anotheruser");
106+
$node->psql('postgres',"CREATE USER yetanotheruser");
106107
$node->psql('postgres',"CREATE DATABASE trustdb");
107108
$node->psql('postgres',"CREATE DATABASE certdb");
109+
$node->psql('postgres',"CREATE DATABASE verifydb");
108110

109111
# Update password of each user as needed.
110112
if (defined($password))
@@ -183,11 +185,17 @@ sub configure_hba_for_ssl
183185
# When connecting to certdb, also check the client certificate.
184186
openmy$hba,'>',"$pgdata/pg_hba.conf";
185187
print$hba
186-
"# TYPE DATABASE USER ADDRESS METHOD\n";
188+
"# TYPE DATABASE USER ADDRESS METHOD OPTIONS\n";
187189
print$hba
188190
"hostssl trustdb all$serverhost/32$authmethod\n";
189191
print$hba
190192
"hostssl trustdb all ::1/128$authmethod\n";
193+
print$hba
194+
"hostssl verifydb ssltestuser$serverhost/32$authmethod clientcert=verify-full\n";
195+
print$hba
196+
"hostssl verifydb anotheruser$serverhost/32$authmethod clientcert=verify-full\n";
197+
print$hba
198+
"hostssl verifydb yetanotheruser$serverhost/32$authmethod clientcert=verify-ca\n";
191199
print$hba
192200
"hostssl certdb all$serverhost/32 cert\n";
193201
print$hba

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp