We have been confused by the behavior of intermediate certificates in
Postgres for many years.  Some people put the intermediate certificates
only on the server and they were supplied to the client, while other
people couldn't get that to work.  In our documentation we recommended
storing intermediate certificates on the client and server.

As part of research for my security talks:

        https://momjian.us/main/presentations/security.html

I asked Stephen Frost and David Steele for details on the arcane art of
SSL certificate creation.  They showed me scripts they use and explained
that they properly pass intermediate certificates to clients.  The trick
was to use the v3_ca extension when creating root and intermediate
certificates.

My talk documents this behavior.  In this talk:

        https://momjian.us/main/writings/pgsql/tls.pdf

slide 47 and 49 use -extensions v3_ca.  Slides 73 and 74 show that the
intermediate is not needed on the client if it is created with v3_ca and
exist on the server.  Slide 75 shows that the server certificate must be
first in server.crt.

I have created the attached doc patch to add this information to our
docs.  I would like to backpatch this since what we have now, while it
works, is inaccurate.

-- 
  Bruce Momjian  <br...@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

+ As you are, so once was I.  As I am, so you will be. +
+                      Ancient Roman grave inscription +
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
new file mode 100644
index 4e46451..801b033
*** a/doc/src/sgml/libpq.sgml
--- b/doc/src/sgml/libpq.sgml
*************** ldap://ldap.acme.com/cn=dbserver,cn=host
*** 7601,7613 ****
    </para>
  
    <para>
!    To allow server certificate verification, the certificate(s) of one or more
!    trusted <acronym>CA</acronym>s must be
!    placed in the file <filename>~/.postgresql/root.crt</filename> in the user's home
!    directory. If intermediate <acronym>CA</acronym>s appear in
!    <filename>root.crt</filename>, the file must also contain certificate
!    chains to their root <acronym>CA</acronym>s. (On Microsoft Windows the file is named
!    <filename>%APPDATA%\postgresql\root.crt</filename>.)
    </para>
  
    <para>
--- 7601,7613 ----
    </para>
  
    <para>
!    To allow server certificate verification, one or more root certificates
!    must be placed in the file <filename>~/.postgresql/root.crt</filename>
!    in the user's home directory.  (On Microsoft Windows the file is named
!    <filename>%APPDATA%\postgresql\root.crt</filename>.)  Intermediate
!    certificates should also be added to the file if they are needed to link
!    the certificate chain sent by the server to the root certificates
!    stored on the client.
    </para>
  
    <para>
*************** ldap://ldap.acme.com/cn=dbserver,cn=host
*** 7660,7682 ****
    </para>
  
    <para>
!    In some cases, the client certificate might be signed by an
!    <quote>intermediate</quote> certificate authority, rather than one that is
!    directly trusted by the server.  To use such a certificate, append the
!    certificate of the signing authority to the <filename>postgresql.crt</filename>
!    file, then its parent authority's certificate, and so on up to a certificate
!    authority, <quote>root</quote> or <quote>intermediate</quote>, that is trusted by
!    the server, i.e. signed by a certificate in the server's root CA file
!    (<xref linkend="guc-ssl-ca-file"/>).
!   </para>
! 
!   <para>
!    Note that the client's <filename>~/.postgresql/root.crt</filename> lists the top-level CAs
!    that are considered trusted for signing server certificates.  In principle it need
!    not list the CA that signed the client's certificate, though in most cases
!    that CA would also be trusted for server certificates.
    </para>
- 
   </sect2>
  
   <sect2 id="libpq-ssl-protection">
--- 7660,7672 ----
    </para>
  
    <para>
!    The first certificate in <filename>postgresql.crt</filename> must be the
!    clients's certificate because it must match the client's private key.
!    The certificates of <quote>intermediate</quote> certificate authorities
!    can be optionally appended to the file.  Doing this avoids requiring
!    the intermediate certificates to be stored on the server (<xref
!    linkend="guc-ssl-ca-file"/>).
    </para>
   </sect2>
  
   <sect2 id="libpq-ssl-protection">
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
new file mode 100644
index a2ebd3e..6352d53
*** a/doc/src/sgml/runtime.sgml
--- b/doc/src/sgml/runtime.sgml
*************** pg_dumpall -p 5432 | psql -d postgres -p
*** 2247,2286 ****
    </para>
  
    <para>
!    In some cases, the server certificate might be signed by an
!    <quote>intermediate</quote> certificate authority, rather than one that is
!    directly trusted by clients.  To use such a certificate, append the
!    certificate of the signing authority to the <filename>server.crt</filename> file,
!    then its parent authority's certificate, and so on up to a certificate
!    authority, <quote>root</quote> or <quote>intermediate</quote>, that is trusted by
!    clients, i.e. signed by a certificate in the clients'
!    <filename>root.crt</filename> files.
    </para>
  
    <sect2 id="ssl-client-certificates">
     <title>Using Client Certificates</title>
  
    <para>
!    To require the client to supply a trusted certificate, place
!    certificates of the certificate authorities (<acronym>CA</acronym>s)
!    you trust in a file named <filename>root.crt</filename> in the data
     directory, set the parameter <xref linkend="guc-ssl-ca-file"/> in
!    <filename>postgresql.conf</filename> to <literal>root.crt</literal>,
!    and add the authentication option <literal>clientcert=1</literal> to the
!    appropriate <literal>hostssl</literal> line(s) in <filename>pg_hba.conf</filename>.
!    A certificate will then be requested from the client during
!    SSL connection startup.  (See <xref linkend="libpq-ssl"/> for a
!    description of how to set up certificates on the client.)  The server will
     verify that the client's certificate is signed by one of the trusted
     certificate authorities.
    </para>
  
    <para>
!    If intermediate <acronym>CA</acronym>s appear in
!    <filename>root.crt</filename>, the file must also contain certificate
!    chains to their root <acronym>CA</acronym>s.  Certificate Revocation List
!    (CRL) entries
!    are also checked if the parameter <xref linkend="guc-ssl-crl-file"/> is set.
     <!-- If this URL changes replace it with a URL to www.archive.org. -->
     (See <ulink
     url="http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s02.html";></ulink>
--- 2247,2292 ----
    </para>
  
    <para>
!    The first certificate in <filename>server.crt</filename> must be the
!    server's certificate because it must match the server's private key.
!    The certificates of <quote>intermediate</quote> certificate authorities
!    can also be appended to the file.  Doing this avoids the necessity of
!    storing intermediate certificates on clients, assuming the root and
!    intermediate certificates were created with <literal>v3_ca</literal>
!    extensions.  This allows easier expiration of intermediate certificates.
!   </para>
! 
!   <para>
!    It is not necessary to add the root certificate to
!    <filename>server.crt</filename>.  Instead, clients must have the root
!    certificate of the server's certificate chain.
    </para>
  
    <sect2 id="ssl-client-certificates">
     <title>Using Client Certificates</title>
  
    <para>
!    To require the client to supply a trusted certificate,
!    place certificates of the root certificate authorities
!    (<acronym>CA</acronym>s) you trust in a file in the data
     directory, set the parameter <xref linkend="guc-ssl-ca-file"/> in
!    <filename>postgresql.conf</filename> to the new file name, and add the
!    authentication option <literal>clientcert=1</literal> to the appropriate
!    <literal>hostssl</literal> line(s) in <filename>pg_hba.conf</filename>.
!    A certificate will then be requested from the client during SSL
!    connection startup.  (See <xref linkend="libpq-ssl"/> for a description
!    of how to set up certificates on the client.)  The server will
     verify that the client's certificate is signed by one of the trusted
     certificate authorities.
    </para>
  
    <para>
!    Intermediate certificates that chain up to existing root certificates
!    can also appear in the <xref linkend="guc-ssl-ca-file"/> file if
!    you wish to avoid storing them on clients (assuming the root and
!    intermediate certificates were created with <literal>v3_ca</literal>
!    extensions).  Certificate Revocation List (CRL) entries are also
!    checked if the parameter <xref linkend="guc-ssl-crl-file"/> is set.
     <!-- If this URL changes replace it with a URL to www.archive.org. -->
     (See <ulink
     url="http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s02.html";></ulink>
*************** pg_dumpall -p 5432 | psql -d postgres -p
*** 2297,2310 ****
    </para>
  
    <para>
-    Note that the server's <filename>root.crt</filename> lists the top-level
-    CAs that are considered trusted for signing client certificates.
-    In principle it need
-    not list the CA that signed the server's certificate, though in most cases
-    that CA would also be trusted for client certificates.
-   </para>
- 
-   <para>
     If you are setting up client certificates, you may wish to use
     the <literal>cert</literal> authentication method, so that the certificates
     control user authentication as well as providing connection security.
--- 2303,2308 ----

Reply via email to