1111 *
1212 *
1313 * 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 $
1515 *
1616 * NOTES
1717 * [ Most of these notes are wrong/obsolete, but perhaps not all ]
143143#endif
144144
145145#ifdef NOT_USED
146- static int verify_peer (PGconn * );
146+ static int verify_peer_name_matches_certificate (PGconn * );
147147#endif
148148static int verify_cb (int ok ,X509_STORE_CTX * ctx );
149149static int client_cert_cb (SSL * ,X509 * * ,EVP_PKEY * * );
@@ -498,18 +498,18 @@ verify_cb(int ok, X509_STORE_CTX *ctx)
498498 *Verify that common name resolves to peer.
499499 */
500500static int
501- verify_peer (PGconn * conn )
501+ verify_peer_name_matches_certificate (PGconn * conn )
502502{
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 ;
506506ACCEPT_TYPE_ARG3 len ;
507507char * * s ;
508508unsigned long l ;
509509
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 )
513513{
514514char sebuf [256 ];
515515
@@ -519,10 +519,14 @@ verify_peer(PGconn *conn)
519519return -1 ;
520520}
521521
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+ }
525528
529+ /* Get the IP addresses of the certificate's common name (CN) */
526530{
527531struct hostent hpstr ;
528532char buf [BUFSIZ ];
@@ -534,65 +538,29 @@ verify_peer(PGconn *conn)
534538 * convert the pqGethostbyname() function call to use getaddrinfo().
535539 */
536540pqGethostbyname (conn -> peer_cn ,& hpstr ,buf ,sizeof (buf ),
537- & h ,& herrno );
541+ & cn_hostentry ,& herrno );
538542}
539543
540- /*what do weknow about the peer's common name ? */
541- if (h == NULL )
544+ /*Did weget an IP address ? */
545+ if (cn_hostentry == NULL )
542546{
543547printfPQExpBuffer (& conn -> errorMessage ,
544548libpq_gettext ("could not get information about host \"%s\": %s\n" ),
545549conn -> peer_cn ,hstrerror (h_errno ));
546550return -1 ;
547551}
548552
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 ))
574556return 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- }
595557
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 );
596564return -1 ;
597565}
598566#endif /* NOT_USED */
@@ -1049,25 +1017,10 @@ open_client_SSL(PGconn *conn)
10491017}
10501018}
10511019
1052- /* check the certificate chain of the server */
1053-
1054- #ifdef NOT_USED
1055- /* CLIENT CERTIFICATES NOT REQUIRED bjm 2002-09-26 */
1056-
10571020/*
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.
10601023 */
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
10711024
10721025/* pull out server distinguished and common names */
10731026conn -> peer = SSL_get_peer_certificate (conn -> ssl );
@@ -1091,17 +1044,8 @@ open_client_SSL(PGconn *conn)
10911044NID_commonName ,conn -> peer_cn ,SM_USER );
10921045conn -> peer_cn [SM_USER ]= '\0' ;
10931046
1094- /* verify that the common name resolves to peer */
1095-
10961047#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 )
11051049{
11061050close_SSL (conn );
11071051return PGRES_POLLING_FAILED ;