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

Commiteb7afc1

Browse files
committed
SSL patch that adds support for optional client certificates.
If the user has certificates in $HOME/.postgresql/postgresql.crtand $HOME/.postgresql/postgresql.key exist, they are providedto the server. The certificate used to sign this cert must beknown to the server, in $DataDir/root.crt. If successful, thecert's "common name" is logged.Client certs are not used for authentication, but they could bevia the port->peer (X509 *), port->peer_dn (char *) orport->peer_cn (char *) fields. Or any other function could beused, e.g., many sites like the issuer + serial number hash.Bear Giles
1 parentb8b6691 commiteb7afc1

File tree

3 files changed

+171
-6
lines changed

3 files changed

+171
-6
lines changed

‎src/backend/libpq/be-secure.c

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $Header: /cvsroot/pgsql/src/backend/libpq/be-secure.c,v 1.4 2002/06/14 04:35:02 momjian Exp $
14+
* $Header: /cvsroot/pgsql/src/backend/libpq/be-secure.c,v 1.5 2002/06/14 04:36:58 momjian Exp $
1515
*
1616
* Since the server static private key ($DataDir/server.key)
1717
* will normally be stored unencrypted so that the database
@@ -62,7 +62,7 @@
6262
* [*] private key permissions
6363
*
6464
* milestone 4: provide endpoint authentication (client)
65-
* [] server verifies client certificates
65+
* [*] server verifies client certificates
6666
*
6767
* milestone 5: provide informational callbacks
6868
* [ ] provide informational callbacks
@@ -124,6 +124,7 @@ ssize_t secure_write(Port *, const void *ptr, size_t len);
124124
staticDH*load_dh_file(intkeylength);
125125
staticDH*load_dh_buffer(constchar*,size_t);
126126
staticDH*tmp_dh_cb(SSL*s,intis_export,intkeylength);
127+
staticintverify_cb(int,X509_STORE_CTX*);
127128
staticintinitialize_SSL(void);
128129
staticvoiddestroy_SSL(void);
129130
staticintopen_server_SSL(Port*);
@@ -137,7 +138,7 @@ static const char *SSLerrmessage(void);
137138
*(total in both directions) before we require renegotiation.
138139
*/
139140
#defineRENEGOTIATION_LIMIT(64 * 1024)
140-
141+
#defineCA_PATHNULL
141142
staticSSL_CTX*SSL_context=NULL;
142143
#endif
143144

@@ -521,6 +522,24 @@ tmp_dh_cb (SSL *s, int is_export, int keylength)
521522
returnr;
522523
}
523524

525+
/*
526+
*Certificate verification callback
527+
*
528+
*This callback allows us to log intermediate problems during
529+
*verification, but for now we'll see if the final error message
530+
*contains enough information.
531+
*
532+
*This callback also allows us to override the default acceptance
533+
*criteria (e.g., accepting self-signed or expired certs), but
534+
*for now we accept the default checks.
535+
*/
536+
staticint
537+
verify_cb (intok,X509_STORE_CTX*ctx)
538+
{
539+
returnok;
540+
}
541+
542+
524543
/*
525544
*Initialize global SSL context.
526545
*/
@@ -583,6 +602,17 @@ initialize_SSL (void)
583602
SSL_CTX_set_tmp_dh_callback(SSL_context,tmp_dh_cb);
584603
SSL_CTX_set_options(SSL_context,SSL_OP_SINGLE_DH_USE);
585604

605+
/* accept client certificates, but don't require them. */
606+
snprintf(fnbuf,sizeoffnbuf,"%s/root.crt",DataDir);
607+
if (!SSL_CTX_load_verify_locations(SSL_context,fnbuf,CA_PATH))
608+
{
609+
postmaster_error("could not read root cert file (%s): %s",
610+
fnbuf,SSLerrmessage());
611+
ExitPostmaster(1);
612+
}
613+
SSL_CTX_set_verify(SSL_context,
614+
SSL_VERIFY_PEER |SSL_VERIFY_CLIENT_ONCE,verify_cb);
615+
586616
return0;
587617
}
588618

@@ -615,6 +645,24 @@ open_server_SSL (Port *port)
615645
}
616646
port->count=0;
617647

648+
/* get client certificate, if available. */
649+
port->peer=SSL_get_peer_certificate(port->ssl);
650+
if (port->peer==NULL)
651+
{
652+
strncpy(port->peer_dn,"(anonymous)",sizeof (port->peer_dn));
653+
strncpy(port->peer_cn,"(anonymous)",sizeof (port->peer_cn));
654+
}
655+
else
656+
{
657+
X509_NAME_oneline(X509_get_subject_name(port->peer),
658+
port->peer_dn,sizeof (port->peer_dn));
659+
port->peer_dn[sizeof(port->peer_dn)-1]='\0';
660+
X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer),
661+
NID_commonName,port->peer_cn,sizeof (port->peer_cn));
662+
port->peer_cn[sizeof(port->peer_cn)-1]='\0';
663+
}
664+
elog(DEBUG,"secure connection from '%s'",port->peer_cn);
665+
618666
return0;
619667
}
620668

‎src/include/libpq/libpq-be.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
1212
* Portions Copyright (c) 1994, Regents of the University of California
1313
*
14-
* $Id: libpq-be.h,v 1.30 2002/06/14 04:33:53 momjian Exp $
14+
* $Id: libpq-be.h,v 1.31 2002/06/14 04:36:58 momjian Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -70,6 +70,9 @@ typedef struct Port
7070
*/
7171
#ifdefUSE_SSL
7272
SSL*ssl;
73+
X509*peer;
74+
charpeer_dn[128+1];
75+
charpeer_cn[SM_USER+1];
7376
unsigned longcount;
7477
#endif
7578
}Port;

‎src/interfaces/libpq/fe-secure.c

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-secure.c,v 1.2 2002/06/14 04:31:49 momjian Exp $
14+
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-secure.c,v 1.3 2002/06/14 04:36:58 momjian Exp $
1515
*
1616
* NOTES
1717
* The client *requires* a valid server certificate. Since
@@ -52,6 +52,20 @@
5252
* should normally be stored encrypted. However we still
5353
* support EPH since it's useful for other reasons.
5454
*
55+
* ...
56+
*
57+
* Client certificates are supported, if the server requests
58+
* or requires them. Client certificates can be used for
59+
* authentication, to prevent sessions from being hijacked,
60+
* or to allow "road warriors" to access the database while
61+
* keeping it closed to everyone else.
62+
*
63+
* The user's certificate and private key are located in
64+
* $HOME/.postgresql/postgresql.crt
65+
* and
66+
* $HOME/.postgresql/postgresql.key
67+
* respectively.
68+
*
5569
* OS DEPENDENCIES
5670
* The code currently assumes a POSIX password entry. How should
5771
* Windows and Mac users be handled?
@@ -71,7 +85,7 @@
7185
* [*] emphermal DH keys, default values
7286
*
7387
* milestone 4: provide endpoint authentication (client)
74-
* [] server verifies client certificates
88+
* [*] server verifies client certificates
7589
*
7690
* milestone 5: provide informational callbacks
7791
* [ ] provide informational callbacks
@@ -135,6 +149,7 @@ static int verify_peer(PGconn *);
135149
staticDH*load_dh_file(intkeylength);
136150
staticDH*load_dh_buffer(constchar*,size_t);
137151
staticDH*tmp_dh_cb(SSL*s,intis_export,intkeylength);
152+
staticintclient_cert_cb(SSL*,X509**,EVP_PKEY**);
138153
staticintinitialize_SSL(PGconn*);
139154
staticvoiddestroy_SSL(void);
140155
staticintopen_client_SSL(PGconn*);
@@ -614,6 +629,101 @@ tmp_dh_cb (SSL *s, int is_export, int keylength)
614629
returnr;
615630
}
616631

632+
/*
633+
*Callback used by SSL to load client cert and key.
634+
*This callback is only called when the server wants a
635+
*client cert.
636+
*
637+
*Returns 1 on success, 0 on no data, -1 on error.
638+
*/
639+
staticint
640+
client_cert_cb (SSL*ssl,X509**x509,EVP_PKEY**pkey)
641+
{
642+
structpasswd*pwd;
643+
structstatbuf,buf2;
644+
charfnbuf[2048];
645+
FILE*fp;
646+
PGconn*conn= (PGconn*)SSL_get_app_data(ssl);
647+
int (*cb)()=NULL;/* how to read user password */
648+
649+
if ((pwd=getpwuid(getuid()))==NULL)
650+
{
651+
printfPQExpBuffer(&conn->errorMessage,
652+
libpq_gettext("unable to get user information\n"));
653+
return-1;
654+
}
655+
656+
/* read the user certificate */
657+
snprintf(fnbuf,sizeoffnbuf,"%s/.postgresql/postgresql.crt",
658+
pwd->pw_dir);
659+
if (stat(fnbuf,&buf)==-1)
660+
return0;
661+
if ((fp=fopen(fnbuf,"r"))==NULL)
662+
{
663+
printfPQExpBuffer(&conn->errorMessage,
664+
libpq_gettext("unable to open certificate (%s): %s\n"),
665+
fnbuf,strerror(errno));
666+
return-1;
667+
}
668+
if (PEM_read_X509(fp,x509,NULL,NULL)==NULL)
669+
{
670+
printfPQExpBuffer(&conn->errorMessage,
671+
libpq_gettext("unable to read certificate (%s): %s\n"),
672+
fnbuf,SSLerrmessage());
673+
fclose(fp);
674+
return-1;
675+
}
676+
fclose(fp);
677+
678+
/* read the user key */
679+
snprintf(fnbuf,sizeoffnbuf,"%s/.postgresql/postgresql.key",
680+
pwd->pw_dir);
681+
if (stat(fnbuf,&buf)==-1)
682+
{
683+
printfPQExpBuffer(&conn->errorMessage,
684+
libpq_gettext("certificate present, but not private key (%s)\n"),
685+
fnbuf);
686+
X509_free(*x509);
687+
return0;
688+
}
689+
if (!S_ISREG(buf.st_mode)|| (buf.st_mode&0077)||
690+
buf.st_uid!=getuid())
691+
{
692+
printfPQExpBuffer(&conn->errorMessage,
693+
libpq_gettext("private key has bad permissions (%s)\n"),fnbuf);
694+
X509_free(*x509);
695+
return-1;
696+
}
697+
if ((fp=fopen(fnbuf,"r"))==NULL)
698+
{
699+
printfPQExpBuffer(&conn->errorMessage,
700+
libpq_gettext("unable to open private key file (%s): %s\n"),
701+
fnbuf,strerror(errno));
702+
X509_free(*x509);
703+
return-1;
704+
}
705+
if (fstat(fileno(fp),&buf2)==-1||
706+
buf.st_dev!=buf2.st_dev||buf.st_ino!=buf2.st_ino)
707+
{
708+
printfPQExpBuffer(&conn->errorMessage,
709+
libpq_gettext("private key changed under us (%s)\n"),fnbuf);
710+
X509_free(*x509);
711+
return-1;
712+
}
713+
if (PEM_read_PrivateKey(fp,pkey,cb,NULL)==NULL)
714+
{
715+
printfPQExpBuffer(&conn->errorMessage,
716+
libpq_gettext("unable to read private key (%s): %s\n"),
717+
fnbuf,SSLerrmessage());
718+
X509_free(*x509);
719+
fclose(fp);
720+
return-1;
721+
}
722+
fclose(fp);
723+
724+
return1;
725+
}
726+
617727
/*
618728
*Initialize global SSL context.
619729
*/
@@ -666,6 +776,9 @@ initialize_SSL (PGconn *conn)
666776
SSL_CTX_set_tmp_dh_callback(SSL_context,tmp_dh_cb);
667777
SSL_CTX_set_options(SSL_context,SSL_OP_SINGLE_DH_USE);
668778

779+
/* set up mechanism to provide client certificate, if available */
780+
SSL_CTX_set_client_cert_cb(SSL_context,client_cert_cb);
781+
669782
return0;
670783
}
671784

@@ -691,6 +804,7 @@ open_client_SSL (PGconn *conn)
691804
intr;
692805

693806
if (!(conn->ssl=SSL_new(SSL_context))||
807+
!SSL_set_app_data(conn->ssl,conn)||
694808
!SSL_set_fd(conn->ssl,conn->sock)||
695809
SSL_connect(conn->ssl) <=0)
696810
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp