|
11 | 11 | *
|
12 | 12 | *
|
13 | 13 | * IDENTIFICATION
|
14 |
| - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.106 2008/10/24 12:29:11 mha Exp $ |
| 14 | + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.107 2008/11/13 09:45:25 mha Exp $ |
15 | 15 | *
|
16 | 16 | * NOTES
|
17 | 17 | *
|
|
87 | 87 | #define ERR_pop_to_mark() ((void) 0)
|
88 | 88 | #endif
|
89 | 89 |
|
90 |
| -#ifdef NOT_USED |
91 |
| -static int verify_peer_name_matches_certificate(PGconn *); |
92 |
| -#endif |
| 90 | +static bool verify_peer_name_matches_certificate(PGconn *); |
93 | 91 | static int verify_cb(int ok, X509_STORE_CTX *ctx);
|
94 | 92 | static int client_cert_cb(SSL *, X509 **, EVP_PKEY **);
|
95 | 93 | static int init_ssl_system(PGconn *conn);
|
@@ -438,77 +436,44 @@ verify_cb(int ok, X509_STORE_CTX *ctx)
|
438 | 436 | return ok;
|
439 | 437 | }
|
440 | 438 |
|
441 |
| -#ifdef NOT_USED |
442 | 439 | /*
|
443 | 440 | * Verify that common name resolves to peer.
|
444 | 441 | */
|
445 |
| -static int |
| 442 | +static bool |
446 | 443 | verify_peer_name_matches_certificate(PGconn *conn)
|
447 | 444 | {
|
448 |
| - struct hostent *cn_hostentry = NULL; |
449 |
| - struct sockaddr server_addr; |
450 |
| - struct sockaddr_in *sin (struct sockaddr_in *) &server_addr; |
451 |
| - ACCEPT_TYPE_ARG3 len; |
452 |
| - char **s; |
453 |
| - unsigned long l; |
454 |
| - |
455 |
| - /* Get the address on the other side of the socket. */ |
456 |
| - len = sizeof(server_addr); |
457 |
| - if (getpeername(conn->sock, &server_addr, &len) == -1) |
458 |
| - { |
459 |
| - char sebuf[256]; |
460 |
| - |
461 |
| - printfPQExpBuffer(&conn->errorMessage, |
462 |
| - libpq_gettext("error querying socket: %s\n"), |
463 |
| - SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); |
464 |
| - return -1; |
465 |
| - } |
| 445 | + /* |
| 446 | + * If told not to verify the peer name, don't do it. Return |
| 447 | + * 0 indicating that the verification was successful. |
| 448 | + */ |
| 449 | + if(strcmp(conn->sslverify, "cn") != 0) |
| 450 | + return true; |
466 | 451 |
|
467 |
| - if (server_addr.sa_family != AF_INET) |
| 452 | + if (conn->pghostaddr) |
468 | 453 | {
|
469 | 454 | printfPQExpBuffer(&conn->errorMessage,
|
470 |
| - libpq_gettext("unsupported protocol\n")); |
471 |
| - return -1; |
| 455 | + libpq_gettext("verified SSL connections are only supported when connecting to a hostname")); |
| 456 | + return false; |
472 | 457 | }
|
473 |
| - |
474 |
| - /* Get the IP addresses of the certificate's common name (CN) */ |
| 458 | + else |
475 | 459 | {
|
476 |
| - struct hostent hpstr; |
477 |
| - char buf[BUFSIZ]; |
478 |
| - int herrno = 0; |
479 |
| - |
480 | 460 | /*
|
481 |
| - * Currently, pqGethostbyname() is used only on platforms that don't |
482 |
| - * have getaddrinfo(). If you enable this function, you should |
483 |
| - * convert the pqGethostbyname() function call to use getaddrinfo(). |
| 461 | + * Connect by hostname. |
| 462 | + * |
| 463 | + * XXX: Should support alternate names here |
| 464 | + * XXX: Should support wildcard certificates here |
484 | 465 | */
|
485 |
| - pqGethostbyname(conn->peer_cn, &hpstr, buf, sizeof(buf), |
486 |
| - &cn_hostentry, &herrno); |
487 |
| - } |
488 |
| - |
489 |
| - /* Did we get an IP address? */ |
490 |
| - if (cn_hostentry == NULL) |
491 |
| - { |
492 |
| - printfPQExpBuffer(&conn->errorMessage, |
493 |
| - libpq_gettext("could not get information about host \"%s\": %s\n"), |
494 |
| - conn->peer_cn, hstrerror(h_errno)); |
495 |
| - return -1; |
| 466 | + if (pg_strcasecmp(conn->peer_cn, conn->pghost) != 0) |
| 467 | + { |
| 468 | + printfPQExpBuffer(&conn->errorMessage, |
| 469 | + libpq_gettext("server common name '%s' does not match hostname '%s'"), |
| 470 | + conn->peer_cn, conn->pghost); |
| 471 | + return false; |
| 472 | + } |
| 473 | + else |
| 474 | + return true; |
496 | 475 | }
|
497 |
| - |
498 |
| - /* Does one of the CN's IP addresses match the server's IP address? */ |
499 |
| - for (s = cn_hostentry->h_addr_list; *s != NULL; s++) |
500 |
| - if (!memcmp(&sin->sin_addr.s_addr, *s, cn_hostentry->h_length)) |
501 |
| - return 0; |
502 |
| - |
503 |
| - l = ntohl(sin->sin_addr.s_addr); |
504 |
| - printfPQExpBuffer(&conn->errorMessage, |
505 |
| - libpq_gettext( |
506 |
| - "server common name \"%s\" does not resolve to %ld.%ld.%ld.%ld\n"), |
507 |
| - conn->peer_cn, (l >> 24) % 0x100, (l >> 16) % 0x100, |
508 |
| - (l >> 8) % 0x100, l % 0x100); |
509 |
| - return -1; |
510 | 476 | }
|
511 |
| -#endif /* NOT_USED */ |
512 | 477 |
|
513 | 478 | /*
|
514 | 479 | * Callback used by SSL to load client cert and key.
|
@@ -846,6 +811,12 @@ initialize_SSL(PGconn *conn)
|
846 | 811 | if (init_ssl_system(conn))
|
847 | 812 | return -1;
|
848 | 813 |
|
| 814 | + /* |
| 815 | + * If sslverify is set to anything other than "none", perform certificate |
| 816 | + * verification. If set to "cn" we will also do further verifications after |
| 817 | + * the connection has been completed. |
| 818 | + */ |
| 819 | + |
849 | 820 | /* Set up to verify server cert, if root.crt is present */
|
850 | 821 | if (pqGetHomeDirectory(homedir, sizeof(homedir)))
|
851 | 822 | {
|
@@ -889,6 +860,24 @@ initialize_SSL(PGconn *conn)
|
889 | 860 |
|
890 | 861 | SSL_CTX_set_verify(SSL_context, SSL_VERIFY_PEER, verify_cb);
|
891 | 862 | }
|
| 863 | + else |
| 864 | + { |
| 865 | + if (strcmp(conn->sslverify, "none") != 0) |
| 866 | + { |
| 867 | + printfPQExpBuffer(&conn->errorMessage, |
| 868 | + libpq_gettext("root certificate file (%s) not found"), fnbuf); |
| 869 | + return -1; |
| 870 | + } |
| 871 | + } |
| 872 | + } |
| 873 | + else |
| 874 | + { |
| 875 | + if (strcmp(conn->sslverify, "none") != 0) |
| 876 | + { |
| 877 | + printfPQExpBuffer(&conn->errorMessage, |
| 878 | + libpq_gettext("cannot find home directory to locate root certificate file")); |
| 879 | + return -1; |
| 880 | + } |
892 | 881 | }
|
893 | 882 |
|
894 | 883 | /* set up mechanism to provide client certificate, if available */
|
@@ -1004,13 +993,11 @@ open_client_SSL(PGconn *conn)
|
1004 | 993 | NID_commonName, conn->peer_cn, SM_USER);
|
1005 | 994 | conn->peer_cn[SM_USER] = '\0';
|
1006 | 995 |
|
1007 |
| -#ifdef NOT_USED |
1008 |
| - if (verify_peer_name_matches_certificate(conn) == -1) |
| 996 | + if (!verify_peer_name_matches_certificate(conn)) |
1009 | 997 | {
|
1010 | 998 | close_SSL(conn);
|
1011 | 999 | return PGRES_POLLING_FAILED;
|
1012 | 1000 | }
|
1013 |
| -#endif |
1014 | 1001 |
|
1015 | 1002 | /* SSL handshake is complete */
|
1016 | 1003 | return PGRES_POLLING_OK;
|
|
0 commit comments