summaryrefslogtreecommitdiffstats
path: root/src/test/ssl/t/003_sslinfo.pl
blob: 87fb18a31e00f1cb2d7fb778dad383e415ea3a0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# Copyright (c) 2021-2022, PostgreSQL Global Development Group

use strict;
use warnings;
use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;

use File::Copy;

use FindBin;
use lib $FindBin::RealBin;

use SSL::Server;

if ($ENV{with_ssl} ne 'openssl')
{
	plan skip_all => 'OpenSSL not supported by this build';
}

#### Some configuration
my $ssl_server = SSL::Server->new();

sub sslkey
{
	return $ssl_server->sslkey(@_);
}

sub switch_server_cert
{
	$ssl_server->switch_server_cert(@_);
}

# This is the hostname used to connect to the server. This cannot be a
# hostname, because the server certificate is always for the domain
# postgresql-ssl-regression.test.
my $SERVERHOSTADDR = '127.0.0.1';
# This is the pattern to use in pg_hba.conf to match incoming connections.
my $SERVERHOSTCIDR = '127.0.0.1/32';

# Allocation of base connection string shared among multiple tests.
my $common_connstr;

#### Set up the server.

note "setting up data directory";
my $node = PostgreSQL::Test::Cluster->new('primary');
$node->init;

# PGHOST is enforced here to set up the node, subsequent connections
# will use a dedicated connection string.
$ENV{PGHOST} = $node->host;
$ENV{PGPORT} = $node->port;
$node->start;

$ssl_server->configure_test_server_for_ssl($node, $SERVERHOSTADDR,
	$SERVERHOSTCIDR, 'trust', extensions => [qw(sslinfo)]);

# We aren't using any CRL's in this suite so we can keep using server-revoked
# as server certificate for simple client.crt connection much like how the
# 001 test does.
switch_server_cert($node, certfile => 'server-revoked');

# Set of default settings for SSL parameters in connection string.  This
# makes the tests protected against any defaults the environment may have
# in ~/.postgresql/.
my $default_ssl_connstr =
  "sslkey=invalid sslcert=invalid sslrootcert=invalid sslcrl=invalid sslcrldir=invalid";

$common_connstr =
  "$default_ssl_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require dbname=certdb hostaddr=$SERVERHOSTADDR host=localhost "
  . "user=ssltestuser sslcert=ssl/client_ext.crt "
  . sslkey('client_ext.key');

# Make sure we can connect even though previous test suites have established this
$node->connect_ok(
	$common_connstr,
	"certificate authorization succeeds with correct client cert in PEM format",
);

my $result;

$result = $node->safe_psql(
	"certdb",
	"SELECT ssl_is_used();",
	connstr => $common_connstr);
is($result, 't', "ssl_is_used() for TLS connection");

$result = $node->safe_psql(
	"certdb",
	"SELECT ssl_version();",
	connstr => $common_connstr
	  . " ssl_min_protocol_version=TLSv1.2 "
	  . "ssl_max_protocol_version=TLSv1.2");
is($result, 'TLSv1.2', "ssl_version() correctly returning TLS protocol");

$result = $node->safe_psql(
	"certdb",
	"SELECT ssl_cipher() = cipher FROM pg_stat_ssl WHERE pid = pg_backend_pid();",
	connstr => $common_connstr);
is($result, 't', "ssl_cipher() compared with pg_stat_ssl");

$result = $node->safe_psql(
	"certdb",
	"SELECT ssl_client_cert_present();",
	connstr => $common_connstr);
is($result, 't', "ssl_client_cert_present() for connection with cert");

$result = $node->safe_psql(
	"trustdb",
	"SELECT ssl_client_cert_present();",
	connstr =>
	  "$default_ssl_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require "
	  . "dbname=trustdb hostaddr=$SERVERHOSTADDR user=ssltestuser host=localhost"
);
is($result, 'f', "ssl_client_cert_present() for connection without cert");

$result = $node->safe_psql(
	"certdb",
	"SELECT ssl_client_serial() = client_serial FROM pg_stat_ssl WHERE pid = pg_backend_pid();",
	connstr => $common_connstr);
is($result, 't', "ssl_client_serial() compared with pg_stat_ssl");

# Must not use safe_psql since we expect an error here
$result = $node->psql(
	"certdb",
	"SELECT ssl_client_dn_field('invalid');",
	connstr => $common_connstr);
is($result, '3', "ssl_client_dn_field() for an invalid field");

$result = $node->safe_psql(
	"trustdb",
	"SELECT ssl_client_dn_field('commonName');",
	connstr =>
	  "$default_ssl_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require "
	  . "dbname=trustdb hostaddr=$SERVERHOSTADDR user=ssltestuser host=localhost"
);
is($result, '', "ssl_client_dn_field() for connection without cert");

$result = $node->safe_psql(
	"certdb",
	"SELECT '/CN=' || ssl_client_dn_field('commonName') = client_dn FROM pg_stat_ssl WHERE pid = pg_backend_pid();",
	connstr => $common_connstr);
is($result, 't', "ssl_client_dn_field() for commonName");

$result = $node->safe_psql(
	"certdb",
	"SELECT ssl_issuer_dn() = issuer_dn FROM pg_stat_ssl WHERE pid = pg_backend_pid();",
	connstr => $common_connstr);
is($result, 't', "ssl_issuer_dn() for connection with cert");

$result = $node->safe_psql(
	"certdb",
	"SELECT '/CN=' || ssl_issuer_field('commonName') = issuer_dn FROM pg_stat_ssl WHERE pid = pg_backend_pid();",
	connstr => $common_connstr);
is($result, 't', "ssl_issuer_field() for commonName");

$result = $node->safe_psql(
	"certdb",
	"SELECT value, critical FROM ssl_extension_info() WHERE name = 'basicConstraints';",
	connstr => $common_connstr);
is($result, 'CA:FALSE|t', 'extract extension from cert');

done_testing();