11
11
*
12
12
*
13
13
* IDENTIFICATION
14
- * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.102 2008/01/29 02 :03:39 tgl Exp $
14
+ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.103 2008/02/16 21 :03:30 momjian Exp $
15
15
*
16
16
* NOTES
17
17
* [ Most of these notes are wrong/obsolete, but perhaps not all ]
143
143
#endif
144
144
145
145
#ifdef NOT_USED
146
- static int verify_peer (PGconn * );
146
+ static int verify_peer_name_matches_certificate (PGconn * );
147
147
#endif
148
148
static int verify_cb (int ok , X509_STORE_CTX * ctx );
149
149
static int client_cert_cb (SSL * , X509 * * , EVP_PKEY * * );
@@ -498,18 +498,18 @@ verify_cb(int ok, X509_STORE_CTX *ctx)
498
498
* Verify that common name resolves to peer.
499
499
*/
500
500
static int
501
- verify_peer (PGconn * conn )
501
+ verify_peer_name_matches_certificate (PGconn * conn )
502
502
{
503
- struct hostent * h = NULL ;
504
- struct sockaddr addr ;
505
- struct sockaddr_in * sin ;
503
+ struct hostent * cn_hostentry = NULL ;
504
+ struct sockaddr server_addr ;
505
+ struct sockaddr_in * sin ( struct sockaddr_in * ) & server_addr ;
506
506
ACCEPT_TYPE_ARG3 len ;
507
507
char * * s ;
508
508
unsigned long l ;
509
509
510
- /* get the address on the other side of the socket */
511
- len = sizeof (addr );
512
- if (getpeername (conn -> sock , & addr , & len ) == -1 )
510
+ /* Get the address on the other side of the socket. */
511
+ len = sizeof (server_addr );
512
+ if (getpeername (conn -> sock , & server_addr , & len ) == -1 )
513
513
{
514
514
char sebuf [256 ];
515
515
@@ -519,10 +519,14 @@ verify_peer(PGconn *conn)
519
519
return -1 ;
520
520
}
521
521
522
- /* weird, but legal case */
523
- if (addr .sa_family == AF_UNIX )
524
- return 0 ;
522
+ if (server_addr .sa_family != AF_INET )
523
+ {
524
+ printfPQExpBuffer (& conn -> errorMessage ,
525
+ libpq_gettext ("unsupported protocol\n" ));
526
+ return -1 ;
527
+ }
525
528
529
+ /* Get the IP addresses of the certificate's common name (CN) */
526
530
{
527
531
struct hostent hpstr ;
528
532
char buf [BUFSIZ ];
@@ -534,65 +538,29 @@ verify_peer(PGconn *conn)
534
538
* convert the pqGethostbyname() function call to use getaddrinfo().
535
539
*/
536
540
pqGethostbyname (conn -> peer_cn , & hpstr , buf , sizeof (buf ),
537
- & h , & herrno );
541
+ & cn_hostentry , & herrno );
538
542
}
539
543
540
- /* what do we know about the peer's common name ? */
541
- if (h == NULL )
544
+ /* Did we get an IP address ? */
545
+ if (cn_hostentry == NULL )
542
546
{
543
547
printfPQExpBuffer (& conn -> errorMessage ,
544
548
libpq_gettext ("could not get information about host \"%s\": %s\n" ),
545
549
conn -> peer_cn , hstrerror (h_errno ));
546
550
return -1 ;
547
551
}
548
552
549
- /* does the address match? */
550
- switch (addr .sa_family )
551
- {
552
- case AF_INET :
553
- sin = (struct sockaddr_in * ) & addr ;
554
- for (s = h -> h_addr_list ; * s != NULL ; s ++ )
555
- {
556
- if (!memcmp (& sin -> sin_addr .s_addr , * s , h -> h_length ))
557
- return 0 ;
558
- }
559
- break ;
560
-
561
- default :
562
- printfPQExpBuffer (& conn -> errorMessage ,
563
- libpq_gettext ("unsupported protocol\n" ));
564
- return -1 ;
565
- }
566
-
567
- /*
568
- * the prior test should be definitive, but in practice it sometimes
569
- * fails. So we also check the aliases.
570
- */
571
- for (s = h -> h_aliases ; * s != NULL ; s ++ )
572
- {
573
- if (pg_strcasecmp (conn -> peer_cn , * s ) == 0 )
553
+ /* Does one of the CN's IP addresses match the server's IP address? */
554
+ for (s = cn_hostentry -> h_addr_list ; * s != NULL ; s ++ )
555
+ if (!memcmp (& sin -> sin_addr .s_addr , * s , cn_hostentry -> h_length ))
574
556
return 0 ;
575
- }
576
-
577
- /* generate protocol-aware error message */
578
- switch (addr .sa_family )
579
- {
580
- case AF_INET :
581
- sin = (struct sockaddr_in * ) & addr ;
582
- l = ntohl (sin -> sin_addr .s_addr );
583
- printfPQExpBuffer (& conn -> errorMessage ,
584
- libpq_gettext (
585
- "server common name \"%s\" does not resolve to %ld.%ld.%ld.%ld\n" ),
586
- conn -> peer_cn , (l >> 24 ) % 0x100 , (l >> 16 ) % 0x100 ,
587
- (l >> 8 ) % 0x100 , l % 0x100 );
588
- break ;
589
- default :
590
- printfPQExpBuffer (& conn -> errorMessage ,
591
- libpq_gettext (
592
- "server common name \"%s\" does not resolve to peer address\n" ),
593
- conn -> peer_cn );
594
- }
595
557
558
+ l = ntohl (sin -> sin_addr .s_addr );
559
+ printfPQExpBuffer (& conn -> errorMessage ,
560
+ libpq_gettext (
561
+ "server common name \"%s\" does not resolve to %ld.%ld.%ld.%ld\n" ),
562
+ conn -> peer_cn , (l >> 24 ) % 0x100 , (l >> 16 ) % 0x100 ,
563
+ (l >> 8 ) % 0x100 , l % 0x100 );
596
564
return -1 ;
597
565
}
598
566
#endif /* NOT_USED */
@@ -1049,25 +1017,10 @@ open_client_SSL(PGconn *conn)
1049
1017
}
1050
1018
}
1051
1019
1052
- /* check the certificate chain of the server */
1053
-
1054
- #ifdef NOT_USED
1055
- /* CLIENT CERTIFICATES NOT REQUIRED bjm 2002-09-26 */
1056
-
1057
1020
/*
1058
- * this eliminates simple man-in- the-middle attacks and simple
1059
- * impersonations
1021
+ * We already checked the server certificate in initialize_SSL()
1022
+ * using SSL_CTX_set_verify() if root.crt exists.
1060
1023
*/
1061
- r = SSL_get_verify_result (conn -> ssl );
1062
- if (r != X509_V_OK )
1063
- {
1064
- printfPQExpBuffer (& conn -> errorMessage ,
1065
- libpq_gettext ("certificate could not be validated: %s\n" ),
1066
- X509_verify_cert_error_string (r ));
1067
- close_SSL (conn );
1068
- return PGRES_POLLING_FAILED ;
1069
- }
1070
- #endif
1071
1024
1072
1025
/* pull out server distinguished and common names */
1073
1026
conn -> peer = SSL_get_peer_certificate (conn -> ssl );
@@ -1091,17 +1044,8 @@ open_client_SSL(PGconn *conn)
1091
1044
NID_commonName , conn -> peer_cn , SM_USER );
1092
1045
conn -> peer_cn [SM_USER ] = '\0' ;
1093
1046
1094
- /* verify that the common name resolves to peer */
1095
-
1096
1047
#ifdef NOT_USED
1097
- /* CLIENT CERTIFICATES NOT REQUIRED bjm 2002-09-26 */
1098
-
1099
- /*
1100
- * this is necessary to eliminate man-in-the-middle attacks and
1101
- * impersonations where the attacker somehow learned the server's private
1102
- * key
1103
- */
1104
- if (verify_peer (conn ) == -1 )
1048
+ if (verify_peer_name_matches_certificate (conn ) == -1 )
1105
1049
{
1106
1050
close_SSL (conn );
1107
1051
return PGRES_POLLING_FAILED ;
0 commit comments