Thread: Re: Trust intermediate CA for client certificates
On 03/07/2013 12:42 PM, Ray Stell wrote: > What Tom said works for me. Here is a page that gives an example and I think it demonstrates that the root CA does notallow everybody in the gate, the chain has to be in place: > http://stackoverflow.com/questions/1456034/trouble-understanding-ssl-certificate-chain-verification That page doesn't even mention PostgreSQL. > You can use the "openssl verify" command to test that the root is not wide open on it's own. The issue is the behavior of the PostgreSQL server. "openssl verify" is germane only in that it points to the source of the problem -- OpenSSL's insistence on ultimately validating all certificates against a self- signed root CA. This requires that the root CA certificate be present in root.crt, which causes the server to accept connections from all clients that can present a certificate chain leading to that root CA. If you don't believe me, test with the attached files, which implement the following hierarchy. +---------+ | Root CA | +---------+ /\ / \ / \ / \ / \ / \ / \ / \ +-----------+ +-----------+ | Server CA | | Client CA | +-----------+ +-----------+ /\ \ / \ \ / \ \ / \ \ / \ \ / \ \ / \ \ / \ \ +----------+ +--------+ +--------+ | postgres | | "Bad" | | "Good" | | (server) | | client | | client | +----------+ +--------+ +--------+ The goal is to configure the server such that the "good" client will be allowed to connect (because its certificate is signed by the Client CA), but the "bad" client will not be allowed to connect (because its certificate is not signed by the Client CA). You will find the following: 1. You cannot simply use client-ca,crt as $PGDATA/root.crt. OpenSSL will not validate a client certificate without access to the root CA certificate. 2. To enable client connections, you must add the root CA certificate to $PGDATA/root.crt -- "cat client-ca.crt root-ca.crt > root.crt". 3. Once the root CA certificate is trusted, however, the "bad" client can also connect by using a certificate chain that includes the Server CA certificate --"cat bad-client.crt server-ca.crt > ~/.postgresql/postgresql.crt". After looking at be-secure.c and investigating the way that OpenSSL validates certificates, I do not believe that there is any way of achieving the desired behavior with the current codebase. Adding pgsql-hackers to see if there is any interest in a patch to add this functionality. -- ======================================================================== Ian Pilcher arequipeno@gmail.com Sometimes there's nothing left to do but crash and burn...or die trying. ========================================================================
Attachment
On 03/09/2013 04:52 PM, Ian Pilcher wrote: > 3. Once the root CA certificate is trusted, however, the "bad" client > can also connect by using a certificate chain that includes the > Server CA certificate --"cat bad-client.crt server-ca.crt > > ~/.postgresql/postgresql.crt". > > After looking at be-secure.c and investigating the way that OpenSSL > validates certificates, I do not believe that there is any way of > achieving the desired behavior with the current codebase. I'm testing this and looking into it now. At first glance this looks like a genuine problem. We need to be storing the certs used for validating client cert auth separately from the certificate chain that links those certs to trusted self-signed CA roots. I was under the strong impression that OpenSSL would do this if the client validation certs were in root.crt and the certificate chain was in OpenSSL's certificate search path and am testing that now. Even if that's the case we need to at least document this issue and preferably detect the case where root.crt contains a certificate chain. If this tests out as expected you need to consider the effects it'd have on people who're not using self-signed CAs, but are instead using certs signed by big CAs. *Any other customer of the same CA could potentially connect to your server with a genuine, valid client cert issued to them by the CA*. Ouch. I'm going through and reproducing the problem now and will also test OpenSSL certificate chain lookup path configurations to see if there's a way to set things up correctly with the current backend code. I'll report back shortly. -- Craig Ringer http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services
On 03/09/2013 04:52 PM, Ian Pilcher wrote: > After looking at be-secure.c and investigating the way that OpenSSL > validates certificates, I do not believe that there is any way of > achieving the desired behavior with the current codebase. Test process: SET UP SERVER VERIFIED SSL (NO CLIENT CERTS) ------------------------------------------------------------------ Edited postgresql.conf and set: ssl=on ssl_cert_file = 'server.crt' ssl_key_file = 'server.key' ssl_ca_file='root.crt' Copied your samples: # cp $CERTS/postgres.crt server.crt # cp $CERTS/postgres.key server.key # cp $CERTS/client-ca.crt root.crt # chown postgres:postgres root.crt server.crt server.key # chmod 0600 server.crt server.key root.crt # systemctl restart postgresql-9.2.service $ psql "postgresql://localhost/?sslmode=require" SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256) (connects OK; expected since we aren't requiring client certs yet and we aren't validating the server cert). $ psql "postgresql://localhost/?sslmode=verify-ca" psql: root certificate file "/home/craig/.postgresql/root.crt" does not exist Either provide the file or change sslmode to disable server certificate verification. Again expected, though we really should be using the system SSL cert database. Anyway: $ mkdir .postgresql $ cp $CERTS/root-ca.crt ~/.postgresql/root.crt (This should be the trusted root, not server-ca or client-ca since we shouldn't have to keep copies of either to verify server trust). Now, test we can verify the server's identity: $ psql "postgresql://localhost/?sslmode=require" psql: SSL error: certificate verify failed Plonk, we can't. The reason for this is that the server has sent us its cert and we have the root cert, but we don't have the intermediate server-ca.crt . Append that to server.crt: # cat $CERTS/postgres.crt $CERTS/server-ca.crt > server.crt # systemctl restart postgresql-9.2.service $ psql "postgresql://localhost/?sslmode=require" SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256) OK, we're good now, the server is sending us the intermediate cert we require. Regular non-client-cert verified SSL is fine. Examination of the protocol chat shows that the server is sending a Server Hello with a Certificate message containing the server and intermdediate certificate DNs: id-at-commonName=postgres.example.com,id-at-organizationName=Ian Pilcher,id-at-localityName=Carrollton,id-at-stateOrProvinceName=Texas,id-at-countryName=US id-at-commonName=Server CA,id-at-organizationName=Ian Pilcher,id-at-localityName=Carrollton,id-at-stateOrProvinceName=Texas,id-at-countryName=US as expected. ENABLE CLIENT CERTIFICATE VERIFICATION --------------------------------------------------------- Now lets install our client certificates in the client. $ cp $CERTS/good-client.key ~/.postgresql/postgresql.key $ # Note that the order is important here, the client cert must appear first, followed by the chain cert(s) $ cat $CERTS/good-client.crt $CERTS/client-ca.crt > ~/.postgresql/postgresql.crt $ chmod 0600 .postgresql/postgresql.key $ psql "postgresql://localhost/?sslmode=verify-ca" psql: SSL error: tlsv1 alert unknown ca Examination of the handshake shows that the server is sending a request for client certificates signed by: Distinguished Name: (id-at-commonName=Client CA,id-at-organizationName=Ian Pilcher,id-at-localityName=Carrollton,id-at-stateOrProvinceName=Texas,id-at-countryName=US) and the client is sending in response: Certificate (id-at-commonName=Good Client,id-at-organizationName=Ian Pilcher,id-at-localityName=Carrollton,id-at-stateOrProvinceName=Texas,id-at-countryName=US) Certificate (id-at-commonName=Client CA,id-at-organizationName=Ian Pilcher,id-at-localityName=Carrollton,id-at-stateOrProvinceName=Texas,id-at-countryName=US) as expected, and good-client.crt is indeed signed by client-ca.crt . Again the issue appears to be that Pg can't find the root of trust, which is fair enough given that it is not present in Pg's root.crt or server.crt and it isn't installed system-wide either. We could add it to the server's root.crt but that'd cause the issues that started this thread: # cat $CERTS/client-ca.crt $CERTS/root-ca.crt > root.crt # systemctl restart postgresql-9.2.service the good client cert works now: $ psql "postgresql://localhost/?sslmode=verify-ca" SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256) PROBLEM VERIFIED -------------------------- ... but so does the one we don't want to trust, as per the problem report: $ cat $CERTS/bad-client.crt $CERTS/server-ca.crt > postgresql.crt $ cp $CERTS/bad-client.key postgresql.key $ chmod 600 postgresql.key $ psql "postgresql://localhost/?sslmode=verify-ca" SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256) So this problem is verified. THE SOLUTION -------------------- What we need to happen instead is for root.crt to contain only the trusted certificates and have a *separate* file or directory for intermediate certificates that OpenSSL can look up to get the intermediates it needs to validate client certs, like `ssl_ca_chain_file` or `ssl_ca_chain_path` if we want to support OpenSSL's hashed certificate directories. System wide installation of the root may allow OpenSSL to discover it and use it for verification back to the root without having to trust it to sign clients. I'll do some more checking to see if this is possible with how Pg uses OpenSSL but I'm inclined to doubt it. I thought you might be able to add the common root to the server.crt certificate chain to let OpenSSL discover it that way, but it looks like OpenSSL won't use certs it's seen in server.crt when verifying client cert trust paths. -- Craig Ringer http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services
On 03/18/2013 12:07 AM, Craig Ringer wrote: > So this problem is verified. Thanks for taking the time to look into this. Good to know I'm not crazy. > What we need to happen instead is for root.crt to contain only the > trusted certificates and have a *separate* file or directory for > intermediate certificates that OpenSSL can look up to get the > intermediates it needs to validate client certs, like > `ssl_ca_chain_file` or `ssl_ca_chain_path` if we want to support > OpenSSL's hashed certificate directories. I did a fair bit of searching and asked about this subject on the openssl-users list. The consensus seems to be that doing this with OpenSSL will require 2 separate sets of certificates and a validation callback. The two sets of certificates are: * Trusted certificates - What currently goes in the (unfortunately named) root.crt file. * Validation-only certificates - CA certificates that are used only to complete the chain from a trusted certificate to a self-signed root. I haven't been able to come up with a particularly good name for a file containing this type of certificate(s) -- validate.crt? All of the certificates in both sets get added to the SSL_CTX, so that OpenSSL can do its normal validation -- all the way to a root CA. The trusted certificates also need to be maintained as a separate set (X509_STORE?). Once OpenSSL has built the complete certificate chain, the validation callback can refuse the connection if the chain does not contain at least one of the *trusted* certificates. This is conceptually simple, and I've been fiddling with it for the last week or so. Unfortunately, the OpenSSL documentation has made this far more challenging that it should be. Simple things like reading multiple certificates from a file, checking whether an X509_STORE contains a particular certificate, etc. are all proving to be unexpectedly difficult. (I never thought that I'd miss the Java SSL API!) > System wide installation of the root may allow OpenSSL to discover it > and use it for verification back to the root without having to trust it > to sign clients. I'll do some more checking to see if this is possible > with how Pg uses OpenSSL but I'm inclined to doubt it. Me too. I think that OpenSSL's behavior embodies the idea that a certificate can only be validated if a chain can be formed to a self- signed root CA. (And there's probably a pretty good argument to be made for this position, particularly when CRLs are added to the mix.) > I thought you might be able to add the common root to the server.crt > certificate chain to let OpenSSL discover it that way, but it looks like > OpenSSL won't use certs it's seen in server.crt when verifying client > cert trust paths. Nope. It's pretty obvious from be-secure.c that only the certificates in root.crt will be used. -- ======================================================================== Ian Pilcher arequipeno@gmail.com Sometimes there's nothing left to do but crash and burn...or die trying. ========================================================================
On 03/18/2013 01:07 PM, Craig Ringer wrote: > System wide installation of the root may allow OpenSSL to discover it > and use it for verification back to the root without having to trust it > to sign clients. I'll do some more checking to see if this is possible > with how Pg uses OpenSSL but I'm inclined to doubt it. It looks like we aren't reading the system-wide certs or looking them up when certs aren't resolved in the files Pg explicitly passes to OpenSSL, so a system-wide install doesn't look like it'll work. I've had a look at how Apache handles this and it took me a while to work out what's going on. Apache uses SSLCACertificateFile (concatenated certs) / SSLCACertificatePath (hashed dir) to look up trusted certificate signers. It According to the docs it doesn't appear to make any provision there for trusting intermediate certificates but not their parents as signers of client certificates, but it looks like support is there, the docs just don't explain it well. Apache has SSLCADNRequestFile / SSLCADNRequestPath which are described as controlling the acceptable certificate names sent to clients in a client cert request. The docs don't make it clear if Apache will trust only client certs with these certs in their chains or whether this only controls the list of certificate DNs presented to the client rather than what's accepted in response. The code suggests that they control trust not just the cert list presented. In Apache's modules/ssl/ssl_engine_init.c it calls SSL_CTX_load_verify_locations on the SSLCACertificateFile and SSLCACertificatePath. It then calls ssl_init_FindCAList with the SSLCADNRequestFile/SSLCADNRequestPath if they're specified in the configuration, otherwise it calls it with the SSLCACertificateFile/SSLCACertificatePath . That calls ssl_init_PushCAList on all of the certs it finds in the File and Path variants. For each cert file that calls SSL_load_client_CA_file and for each cert within each file pushes the cert onto a STACK_OF(X509_NAME) if a cert with the same DN isn't already in the stack. It passes the stack to OpenSSL's SSL_CTX_set_client_CA_list . So what Apache does appears to boil down to: SSL_CTX_load_verify_locations(ca_file,ca_path); if (ca_dn_file || ca_dn_path) { SSL_CTX_set_client_CA_list( ... STACK_OF unique certs on ca_dn_file and ca_dn_path ... ); } else { SSL_CTX_set_client_CA_list( ... STACK_OF unique certs on ca_file and ca_path ); } This appears to match Ian's description of having a validation-only cert list and a separate list of certs used to verify clients. I'd like to follow Apache's model: in postgresql.conf, if ssl_ca_file is set then pass it to SSL_CTX_load_verify_locations . If the proposed new parameter ssl_ca_valid_client_signers_file is set then pass the certs in that to SSL_CTX_set_client_CA_list ; otherwise pass the certs in ssl_ca_file to SSL_CTX_set_client_CA_list and thus retain the current behaviour. Hopefully we can avoid the ugly read-and-deduplicate stuff Apache has to do because we currently only support a certfile anyway, we don't read certdirs, so I'll look for helper functions that wrap SSL_CTX_set_client_CA_list. -- Craig Ringer http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services
On 03/18/2013 02:27 PM, Ian Pilcher wrote: > On 03/18/2013 12:07 AM, Craig Ringer wrote: >> So this problem is verified. > * Trusted certificates - What currently goes in the (unfortunately > named) root.crt file. Well, a little unfortunate. It contains roots of *client authentication* trust, which is fair enough, they just aren't necessarily self-signed certificates that are roots of *certificate validity* trust (root CA certs). This list is set by SSL_CTX_set_client_CA_list . The examples section of its man page contains: Scan all certificates in CAfile and list them as acceptable CAs: SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile)); > * Validation-only certificates - CA certificates that are used only to > complete the chain from a trusted certificate to a self-signed root. > I haven't been able to come up with a particularly good name for a > file containing this type of certificate(s) -- validate.crt? We should probably take advantage of the fact that 9.2 made these filenames configurable to deprecate root.crt and choose two descriptive filenames, something like trusted_cert_roots.crt and trusted_client_cert_signers.crt . > This is conceptually simple, and I've been fiddling with it for the last > week or so. Unfortunately, the OpenSSL documentation has made this far > more challenging that it should be. Simple things like reading multiple > certificates from a file, checking whether an X509_STORE contains a > particular certificate, etc. are all proving to be unexpectedly > difficult. (I never thought that I'd miss the Java SSL API!) Apache's sources are useful there. When working with OpenSSL sometimes the sanest option is to find something you know already does it right, work out how, *understand why it works* and then apply that approach to your code. Blindly copying their approach is stupid and guaranteed to lead to security holes, but others' code remains some of the best documentation for OpenSSL if used for hints rather than blindly copied. -- Craig Ringer http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services
Craig, all, * Craig Ringer (craig@2ndquadrant.com) wrote: > PROBLEM VERIFIED Let me just say "ugh". I've long wondered why we have things set up in such a way that the whole chain has to be in one file, but it didn't occur to me that it'd actually end up causing this issue. In some ways, I really wonder about this being OpenSSL's fault as much as ours, but I doubt they'd see it that way. :) > What we need to happen instead is for root.crt to contain only the > trusted certificates and have a *separate* file or directory for > intermediate certificates that OpenSSL can look up to get the > intermediates it needs to validate client certs, like > `ssl_ca_chain_file` or `ssl_ca_chain_path` if we want to support > OpenSSL's hashed certificate directories. Makes sense to me. I'm not particular about the names, but isn't this set of CAs generally considered intermediary? Eg: 'trusted', ' intermediate', etc? Thanks, Stephen
Attachment
On 03/18/2013 02:01 AM, Craig Ringer wrote: > This appears to match Ian's description of having a validation-only cert > list and a separate list of certs used to verify clients. I'd like to > follow Apache's model: Ready for some more good news? It's possible that I'm missing something, but Apache (mod_ssl) appears to exhibit the exact same behavior. Tested on Fedora 18, with the following packages: httpd-2.4.3-15.fc18.x86_64 mod_ssl-2.4.3-15.fc18.x86_64 openssl-1.0.1e-3.fc18.x86_64 I have set the following in /etc/httpd/conf.d/ssl.conf: Listen 44443 https <VirtualHost _default_:44443> ServerName postgres.example.com SSLCertificateFile /etc/pki/tls/certs/postgres.crt SSLCertificateKeyFile /etc/pki/tls/private/postgres.key SSLCACertificateFile /etc/pki/tls/certs/client-ca.chain SSLCADNRequestFile /etc/pki/tls/certs/client-ca.crt SSLVerifyClient require SSLVerifyDepth 10 Notes: * The port is set to 44443, because that's hard-coded into the (attached) test client. * I am using the certificates that I previously sent. * ServerName is set to postgres.example.com to match its certificate. * postgres.crt contains its entire chain (postgres.crt + server-ca.crt + root-ca.crt), so that I don't have to specify a SSLCertificateChainFile. * client-ca.chain is client-ca.crt + root-ca.crt. As with PostgreSQL, I found that I have to provide the root CA certificate in order for any client to connect. With this configuration, the test client is able to connect with the "good" client certificate, but it is also able to connect with the "bad" client certificate when it presents a certificate chain that includes the server CA certificate. -- ======================================================================== Ian Pilcher arequipeno@gmail.com Sometimes there's nothing left to do but crash and burn...or die trying. ========================================================================
Attachment
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 03/18/2013 08:55 PM, Stephen Frost wrote: > Makes sense to me. I'm not particular about the names, but isn't this > set of CAs generally considered intermediary? Eg: 'trusted', ' > intermediate', etc? They are intermediary, but we're dealing with the case where trust and authorization are not the same thing. Trust stems from the trusted root in the SSL CA model, but that's a chain of trust for *identity* (authentication), not *authorization*. Bob J. Criminal might well have a client certificate from a trusted authority proving that he's who he says he is (he's authenticated) but we sure as hell don't want to authorize his access to anything. That's where the intermediate certs come in. We might say "Only users with certificates issued by our corporate HR team are authorized to connect to our servers". This is a root of trust, but this time it's a root of trust to *authorize*, not just to authenticate. The usual SSL terminology doesn't consider this, because it's a simple back and white trust model where authenticated = authorized. I guess that suggests we should be calling this something like 'ssl_authorized_client_roots'. - -- Craig Ringer http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.13 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iQEcBAEBAgAGBQJRR/dqAAoJELBXNkqjr+S2TV4H/3f9Hnf9JhSuGhWblh2adgTJ Rkdx/9RbByJDMJP0s0c8C1sXaWZGJmKmLhJoes4IIvOVW85SVUa9WoT+UBJPdx9P esUNsSLFokLqom3TxNRZOHaloyZ+OZafSUnKCwMOIvD0hIehrS3Wcg70QMSj06tX h22BVhA8bzO1Wdg9UdD98jcuWdEbLgWzVtvIXjICcMJ1azgiF1VY4zwUUbBJBfLG UIA7+2TtVaXQuge6qWgId0RTKKrb6cLHXCSQ/rigy0mRH9m/G5jKmqENvLAnafI4 4lSBPyDzNj2fBfP9YgIiAe/EGjnJMWQfBBghQI3QrK2kjOZXtzZoOb4XEjfn3FI= =u+2j -----END PGP SIGNATURE-----
Craig, * Craig Ringer (craig@2ndquadrant.com) wrote: > They are intermediary, but we're dealing with the case where trust and > authorization are not the same thing. Trust stems from the trusted root > in the SSL CA model, but that's a chain of trust for *identity* > (authentication), not *authorization*. Oh, I see. > The usual SSL terminology doesn't consider this, because it's a simple > back and white trust model where authenticated = authorized. That's not entirely accurate on a couple of levels. First, basic SSL is only concerned with authentication, authorization has historically been left up to the application. The more typical approach with the situation you're describing is to have an organization-level root CA which you only issue certs against. If you're using a public CA as your root, then you need to make sure you know how to ensure only the right people have access, typically be storing in the mapping table the unique ID issued by the CA for your users. It's very rare, from what I've seen, for public CAs to issue intermediate CAs to organizations to generate their own certs off of, so I'm a bit confused about how we got to this point. What I *have* seen is cross-root-cert trusts (known as the Federal Bridge in the US government), but that's quite a different thing as you have multiple self-signed root CAs involved and need to know how to properly traverse between them based on the trusts which have been built. Regarding cross-CAS authorization, there are extended attributes which are listed in the certificates that applications are expected to look at when considering authorization for the client. It's been taken further than that however, where inter-CA trusts have been defined with actual mappings between these extended attributes, including 'null' mappings (indicating that CA 'A' doesn't trust attribute 'q' from CA 'B'). > I guess that suggests we should be calling this something like > 'ssl_authorized_client_roots'. I'm no longer convinced that this really makes sense and I'm a bit worried about the simple authentication issue which I thought was at the heart of this concern. Is there anything there that you see as being an issue with what we're doing currently..? I do think we want to figure out a way to improve our mapping table to be able to use more than just the CN, since that can be repeated in multiple certs issued from a root CA, particularly when there are intermediary CAs. One option might be to provide a way to map against a specific issuing CA, or to a CA in the chain, but there's a lot of risk to that due to CA churn (in large setups, you're going to have lots of users who have certs issued from a bunch of different CAs, and those user certs will roll to new CAs as new badges are issued, for example..). It can get to be a real nightmare to try and keep up with all of the changes at that level. Thanks, Stephen
Attachment
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 03/19/2013 01:46 PM, Stephen Frost wrote: > If you're using a public CA as your > root, then you need to make sure you know how to ensure only the right > people have access, typically be storing in the mapping table the unique > ID issued by the CA for your users. Yep, in most applications I've seen you usually store a list of authorized SubjectDNs or you just use your own self-signed root and issue certs from it. I'm pretty sure I've seen tools match on part of the DN, like the organisation field, but since I can't remember *where* I'm not sure that's all that useful. > It's very rare, from what I've > seen, for public CAs to issue intermediate CAs to organizations to > generate their own certs off of, so I'm a bit confused about how we got > to this point. I don't know about "very rare" but it's certainly not common outside very large orgs. I tried to find a CA that'd let me issue intermediate client certs for 2ndQuadrant but found nobody that'd do it for certificate volumes less than several thousand new certs a month. I'd been using intermediate CAs based on my own self-signed CA root quite heavily in infrastructure elsewhere I was rather surprised that the same sort of thing wasn't easily available for public CAs. I get the impression it's fairly common in internal infrastructure, especially with the cert management tools offered by Microsoft Active Directory servers, but have no strong information to substantiate this. Nor do I know whether we need to support this mode of operation. BTW, This discussion has made me realise that I know less about SSL/TLS and X.509 certificate extensions than I'd like to when dealing with this topic. In particular, I don't know whether a CA can issue an intermediate CA with extensions that restrict it to validly signing only host certificates for hosts under a particular domain or user-identifying client certs with CNs under a particular organisation - and whether, if such extensions exist, applications actually check them when verifying the certificate trust chain. > What I *have* seen is cross-root-cert trusts (known as the Federal > Bridge in the US government), but that's quite a different thing as you > have multiple self-signed root CAs involved and need to know how to > properly traverse between them based on the trusts which have been > built. Ugh, that's not something I've ever had the ... privilege ... to deal with before. > > I'm no longer convinced that this really makes sense and I'm a bit > worried about the simple authentication issue which I thought was at the > heart of this concern. Is there anything there that you see as being an > issue with what we're doing currently..? Only for using intermediate certs as authorization roots, and it may be reasonable to say "we don't support that, use an authorized DN list". Or come up with a better solution like checking attributes of the SubjectDN for authorization purposes after validating the signature chain to prove authenticity. > I do think we want to figure out a way to improve our mapping table to > be able to use more than just the CN, since that can be repeated in > multiple certs issued from a root CA, particularly when there are > intermediary CAs. One option might be to provide a way to map against a > specific issuing CA, or to a CA in the chain, but there's a lot of risk > to that due to CA churn (in large setups, you're going to have lots of > users who have certs issued from a bunch of different CAs, and those > user certs will roll to new CAs as new badges are issued, for > example..). It can get to be a real nightmare to try and keep up with > all of the changes at that level. Certificate fingerprint? Easily obtained via most client UIs and via openssl x509 -in cert.crt -fingerprint, eg: SHA1 Fingerprint=DA:03:9B:FB:81:69:AB:48:64:3D:35:B4:90:56:CF:F1:24:FE:89:B0 However, if I was managing a group large enough to want cert auth I'd want to be able to specify something like: SubjectDNMatches: C=*, ST=*, L=*, O=MyCompany, CN=* ... in which case there'd no longer be a need to restrict trust to intermediate CAs, you'd just trust the root and restrict the authorized SubjectDNs. If you don't trust your own root CA not to issue certs in your company's name to 3rd parties you shouldn't be using it. (Whether it's actually sane to trust a CA is another argument). - -- Craig Ringer http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.13 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iQEcBAEBAgAGBQJRSAJZAAoJELBXNkqjr+S2JrcIALZebfEW4FbfFI6WOs6qDutr tz486SlnPV+cf29ex242evSUgNQTz38uFKMIs9EIRfe7sVKz3whn0MARmQY9dKph CusbXNqcPIBbZIZM1hObaKOnMvNnGk5sxnRh4iKjzcMjqCULG5LVX7bXAXn3PcjA u3lYlNWONWdmz708QOCgvpui4wEv5+bVuik/CnRdPu+BWAcndJHUMuxZMxkUC/rs 4OjLlEg6BPiXRgIKTFBNsa0vvCyVBUd5ri0RCtxUr5T/L/ORWdM+Ic0nqCEPTqyI EOtDKuNZUqEnsCOacwulwRDxQXnUoU+6zBHud8al32+PeWLKHLAIcFEiYYSQUjI= =Ba3M -----END PGP SIGNATURE-----
On Tue, Mar 19, 2013 at 01:46:32AM -0400, Stephen Frost wrote: > > I guess that suggests we should be calling this something like > > 'ssl_authorized_client_roots'. > > I'm no longer convinced that this really makes sense and I'm a bit > worried about the simple authentication issue which I thought was at the > heart of this concern. Is there anything there that you see as being an > issue with what we're doing currently..? I too am worried that make SSL even more flexible will make simple setups more complex to setup. -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + It's impossible for everything to be true. +
Craig, * Craig Ringer (craig@2ndquadrant.com) wrote: > Yep, in most applications I've seen you usually store a list of > authorized SubjectDNs or you just use your own self-signed root and > issue certs from it. Even with a self-signed root issuing certs, you need to map the individual cert to a PG user in some fashion. > I'm pretty sure I've seen tools match on part of the DN, like the > organisation field, but since I can't remember *where* I'm not sure > that's all that useful. Looking at what other tools do and how they handle this question would certainly be a good idea. > I don't know about "very rare" but it's certainly not common outside > very large orgs. I tried to find a CA that'd let me issue intermediate > client certs for 2ndQuadrant but found nobody that'd do it for > certificate volumes less than several thousand new certs a month. I'd > been using intermediate CAs based on my own self-signed CA root quite > heavily in infrastructure elsewhere I was rather surprised that the same > sort of thing wasn't easily available for public CAs. It's pretty simple, really- issuing certs is how the public CAs make their money. If they give you a CA cert that can issue certs, they're cut out of the loop. > I get the impression it's fairly common in internal infrastructure, > especially with the cert management tools offered by Microsoft Active > Directory servers, but have no strong information to substantiate this. > Nor do I know whether we need to support this mode of operation. In general, CAs view intermediate certs as a way to provide automated systems while having their self-signed root private key highly protected. The intermediate CAs therefore have a shorter life-span and end up changing much more frequently than the root certs (though root certs certainly also do change, but it's much more painful). That's one of the reasons that they're bad to use as part of the authentication criteria. The problem with trying to use intermediate CAs as a way of dividing up organizational responsibility is simply that there's very few systems out there which will support that kind of configuration, from what I've seen. Wrt Active Directory this problem is actually very well solved through use of Kerberos, where you have multiple realms, directional trust between the realms, and most tools (including PG) understand that a principal is the combination of username@REALM and let you authorize based on that. > BTW, This discussion has made me realise that I know less about SSL/TLS > and X.509 certificate extensions than I'd like to when dealing with this > topic. In particular, I don't know whether a CA can issue an > intermediate CA with extensions that restrict it to validly signing only > host certificates for hosts under a particular domain or > user-identifying client certs with CNs under a particular organisation - > and whether, if such extensions exist, applications actually check them > when verifying the certificate trust chain. You can set flags on certificates but I've not seen the kind of complex restrictions that you're describing. Remember that anything that the CA sets for an intermediate CA cert would have to be checked by whatever software is doing the certificate validation, meaning that you'd have to make sure all your certificate-based software is updated to do that kind of validation (and do it in a consistent way, or you'd get all kinds of fun failures). > Ugh, that's not something I've ever had the ... privilege ... to deal > with before. I worked for the company that built the original federal bridge software. :) I wasn't directly involved in that project, but I certainly gained some understanding of the complexities through working with the folks who were. > Only for using intermediate certs as authorization roots, and it may be > reasonable to say "we don't support that, use an authorized DN list". Or > come up with a better solution like checking attributes of the SubjectDN > for authorization purposes after validating the signature chain to prove > authenticity. I think it'd be valuable to distinguish "trusted CAs" from "intermediate CAs" in PG explicitly (as I recall, you can already do this by simply ensuring that your OpenSSL config is set up correctly for the system wide defaults). That's what most serious SSL users will be familiar with anyway. I'm on the fence about if only supporting a list of "trusted CAs" (through the cert files that we currently have) rises to the level of being a security issue, but we should at least update the documentation to reflect that all CAs listed in the file are fully trusted and plan to provide an intermediate CA list option. To be honest, our entire SSL support mechanism could really use some work and it'd be great if we had some folks looking into it seriously. One of the problems we've long had is the dependency on OpenSSL (yes, it's a problem) and it'd be good to consider, if we're changing the SSL configuration, how we could make it easier to introduce other SSL libraries in the future. > Certificate fingerprint? Easily obtained via most client UIs and via They change too much. This is the trade-off that you end up having to deal with- either you depend on the DN/CN, which can end up being duplicately issued by a given root CA, or you depend on the fingerprint and then have to re-enroll individuals whenever they get a new cert. This isn't an easy problem to solve, when dealing with the US ACES program, we could never get them to give us a "unique-to-a-person" identifier, the best we got was the DN. That changes when an individual changes organizations, which happens stupidly frequently in government, but (on rare occation..) it may also come with an actual change in responsibility, such that the individual shouldn't have access any longer. Being able to map certs based on the DN instead of just the CN would, imv, be a valuable improvment to the PG SSL options. We'd probably want to support that on a per-map basis and not just globally. > However, if I was managing a group large enough to want cert auth I'd > want to be able to specify something like: > > SubjectDNMatches: C=*, ST=*, L=*, O=MyCompany, CN=* If we had a way to use the DN in pg_ident.conf, you could use a regex to do the matching. > ... in which case there'd no longer be a need to restrict trust to > intermediate CAs, you'd just trust the root and restrict the authorized > SubjectDNs. In general, I'm open to doing it all kinds of ways; more options here would be better than what we've currently got. I would put splitting the CA cert chain file into trusted-CAs and intermediate-CAs as the higher priority here, followed by allowing the use of the DN for the mapping to PG user, and perhaps lastly something that tried to tie into a specific path, chain, or intermediate CA, as I don't see a very big use case for that. Thanks, Stephen
Attachment
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 03/19/2013 08:39 PM, Stephen Frost wrote: > Craig, > > * Craig Ringer (craig@2ndquadrant.com) wrote: >> Yep, in most applications I've seen you usually store a list of >> authorized SubjectDNs or you just use your own self-signed root and >> issue certs from it. > > Even with a self-signed root issuing certs, you need to map the > individual cert to a PG user in some fashion. > The more I look a this, the more it looks like trying to use intermediate CAs as authentication roots is largely wrong anyway. We should document this with something like: NOTE: Only self-signed root CA certificates should be added to ssl_ca_file. If you add an intermediate CA certificate (one that's not self-signed) then PostgreSQL will not be able to validate client certificates against it because it will not have access to the full certificate chain. You can't fix that by adding the full certificate chain then PostgreSQL will then accept client certificates trusted by any member of the chain, including the root, so the effect is the same as placing only the root certificate in the file. It is not currently possible to trust certificates signed by an intermediate CA but not the parents in its certificate chain. ... plus some explanation that having a valid trusted cert doesn't mean you're authorized for access, you still have to meet the requrements in pg_hba.conf, have a valid username/password or match an authorized certificate DN (depending on config), etc. As far as I'm concerned that's the immediate problem fixed. It may be worth adding a warning on startup if we find non-self-signed certs in root.crt too, something like 'WARNING: Intermediate certificate found in root.crt. This does not do what you expect and your configuration may be insecure; see the Client Certificates chapter in the documentation.' We could then look at using more flexible approaches to match PostgreSQL users to client certificates, like regexps or (preferably, IMO) DN-component based solutions to extract usernames from cert DNs, etc. Various ways to specify *authorization*. It's looking more and more like the *authentication* side is basically "do you trust this CA root not to sign certs for fraudlent/fake SubjectDNs or issue intermediate certs that might do so? Trust: include it. No trust: Don't." That's what we have now, it just needs to be explained better in the docs. - -- Craig Ringer http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.13 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iQEcBAEBAgAGBQJRSGoOAAoJELBXNkqjr+S26esIALSmgX6/4lC+J7W3YPDpl1DE UJsSGc46oBZbC/5xDwBELh2Tg+fqzIe+Kmx+EpsC20MaGinqEz9iwTb2M7vTFhxh nvAkp1Em8MhR6lvCKITjPnDBCv7yQ7K3yTAfHO+LU2J1t3eVhStpXh71/73pRLoQ p3SAUwO0EBnZFdY2HVLPABK7tpjuf5Mpn0QFR9T+KvsgcP9QXiV0UTFI0IxlQrpE NRlJfPwkoYAweISTACrDwqJHJ3sL/qLdOQ8l4BCsiwtqynX7fPhxmDUuBXrOTqlS dwW9ZkBJ9jvXjF3PPk1t0oujlMJGBC4Y7xgIb0Kd87Vyv/OTkWE4XKriDhIH6oQ= =f3qr -----END PGP SIGNATURE-----
On Tue, Mar 19, 2013 at 09:37:18PM +0800, Craig Ringer wrote: > On 03/19/2013 08:39 PM, Stephen Frost wrote: > > Craig, > > > > * Craig Ringer (craig@2ndquadrant.com) wrote: > >> Yep, in most applications I've seen you usually store a list of > >> authorized SubjectDNs or you just use your own self-signed root and > >> issue certs from it. > > > > Even with a self-signed root issuing certs, you need to map the > > individual cert to a PG user in some fashion. > > > > The more I look a this, the more it looks like trying to use > intermediate CAs as authentication roots is largely wrong anyway. We > should document this with something like: > > NOTE: Only self-signed root CA certificates should be added to > ssl_ca_file. If you add an intermediate CA certificate (one that's not > self-signed) then PostgreSQL will not be able to validate client > certificates against it because it will not have access to the full > certificate chain. You can't fix that by adding the full certificate > chain then PostgreSQL will then accept client certificates trusted by > any member of the chain, including the root, so the effect is the same > as placing only the root certificate in the file. It is not currently > possible to trust certificates signed by an intermediate CA but not the > parents in its certificate chain. > > ... plus some explanation that having a valid trusted cert doesn't mean > you're authorized for access, you still have to meet the requrements in > pg_hba.conf, have a valid username/password or match an authorized > certificate DN (depending on config), etc. > > As far as I'm concerned that's the immediate problem fixed. It may be > worth adding a warning on startup if we find non-self-signed certs in > root.crt too, something like 'WARNING: Intermediate certificate found in > root.crt. This does not do what you expect and your configuration may be > insecure; see the Client Certificates chapter in the documentation.' Yes, I like this. -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + It's impossible for everything to be true. +
* Craig Ringer (craig@2ndquadrant.com) wrote: > As far as I'm concerned that's the immediate problem fixed. It may be > worth adding a warning on startup if we find non-self-signed certs in > root.crt too, something like 'WARNING: Intermediate certificate found in > root.crt. This does not do what you expect and your configuration may be > insecure; see the Client Certificates chapter in the documentation.' I'm not sure that I follow this logic, unless you're proposing that intermediate CAs only be allowed to be picked up from system-wide configuration? That strikes me as overly constrained as I imagine there are valid configurations today which have intermediate CAs listed, with the intention that they be available for PG to build the chain from a client cert that is presented back up to the root. Now, the client might be able to provide such an intermediate CA cert too (one of the fun things about SSL is that the client can send any 'missing' certs to the server, if it has them available..), but it also might not. > We could then look at using more flexible approaches to match PostgreSQL > users to client certificates, like regexps or (preferably, IMO) > DN-component based solutions to extract usernames from cert DNs, etc. > Various ways to specify *authorization*. Sure. > It's looking more and more like the *authentication* side is basically > "do you trust this CA root not to sign certs for fraudlent/fake > SubjectDNs or issue intermediate certs that might do so? Trust: include > it. No trust: Don't." That's what we have now, it just needs to be > explained better in the docs. I certainly agree that the docs could be improved in this area. :) Thanks, Stephen
Attachment
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 03/19/2013 09:46 PM, Stephen Frost wrote: > * Craig Ringer (craig@2ndquadrant.com) wrote: >> As far as I'm concerned that's the immediate problem fixed. It may be >> worth adding a warning on startup if we find non-self-signed certs in >> root.crt too, something like 'WARNING: Intermediate certificate found in >> root.crt. This does not do what you expect and your configuration may be >> insecure; see the Client Certificates chapter in the documentation.' > > I'm not sure that I follow this logic, unless you're proposing that > intermediate CAs only be allowed to be picked up from system-wide > configuration? That strikes me as overly constrained as I imagine there > are valid configurations today which have intermediate CAs listed, with > the intention that they be available for PG to build the chain from a > client cert that is presented back up to the root. Now, the client > might be able to provide such an intermediate CA cert too (one of the > fun things about SSL is that the client can send any 'missing' certs to > the server, if it has them available..), but it also might not. > Drat, you're quite right. I've always included the full certificate chain in client certs but it's in no way required. I guess that pretty much means mainaining the status quo and documenting it better. - -- Craig Ringer http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.13 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iQEcBAEBAgAGBQJRSp3fAAoJELBXNkqjr+S2+JYH+wUo2mCMB2n3/mXo24l0rO5+ mxS6d9uJNIZZErZX2I/NfY59kLX1ypUAeGhQnCSOZuxig6Xd91nXzRdkaQF/+WHa 9hEAXbOtl7bMgj8cEIfloQlSU94VXamH53i5YL5ZVLqkQG/7uknY05NbJs3IGM5g ALrEgo3XOC8JyUz21hZzaQOb2vbdSh0F0O17EoJz1fLY6l5ScFnLWihKYurp5Oq0 em1bsN0GKckmSa7a9mJ37Hvowi92epbtF4XR1DyrQGOHQSCLq0NnCthA5MtdPXN0 +BJQWZfx0qcRcrHMILkFa0Uu7Bc9Ao0q06l55DNSyYXx1FWN0cBArGpXcoPb8Zs= =BAYd -----END PGP SIGNATURE-----
On Thu, Mar 21, 2013 at 01:42:55PM +0800, Craig Ringer wrote: > On 03/19/2013 09:46 PM, Stephen Frost wrote: > > * Craig Ringer (craig@2ndquadrant.com) wrote: > >> As far as I'm concerned that's the immediate problem fixed. It may be > >> worth adding a warning on startup if we find non-self-signed certs in > >> root.crt too, something like 'WARNING: Intermediate certificate found in > >> root.crt. This does not do what you expect and your configuration may be > >> insecure; see the Client Certificates chapter in the documentation.' > > > > I'm not sure that I follow this logic, unless you're proposing that > > intermediate CAs only be allowed to be picked up from system-wide > > configuration? That strikes me as overly constrained as I imagine there > > are valid configurations today which have intermediate CAs listed, with > > the intention that they be available for PG to build the chain from a > > client cert that is presented back up to the root. Now, the client > > might be able to provide such an intermediate CA cert too (one of the > > fun things about SSL is that the client can send any 'missing' certs to > > the server, if it has them available..), but it also might not. > > > > Drat, you're quite right. I've always included the full certificate > chain in client certs but it's in no way required. > > I guess that pretty much means mainaining the status quo and documenting > it better. I have developed the attached patch to document this behavior. My goals were: * clarify that a cert can match a remote intermediate or root certificate * clarify that the client cert must match a server root.crt * clarify that the server cert much match a client root.crt * clarify that the root certificate does not have to be specified in the client or server cert as long as the remote end has the chain to the root Does it meet these goals? Is it correct? -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
Attachment
On Sat, Nov 30, 2013 at 12:10:19PM -0500, Bruce Momjian wrote: > > Drat, you're quite right. I've always included the full certificate > > chain in client certs but it's in no way required. > > > > I guess that pretty much means maintaining the status quo and documenting > > it better. > > I have developed the attached patch to document this behavior. My goals > were: > > * clarify that a cert can match a remote intermediate or root certificate > * clarify that the client cert must match a server root.crt > * clarify that the server cert much match a client root.crt > * clarify that the root certificate does not have to be specified > in the client or server cert as long as the remote end has the chain > to the root > > Does it meet these goals? Is it correct? I have updated the patch, attached, to be clearer about the requirement that intermediate certificates need a chain to root certificates. -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
Attachment
Bruce Momjian <bruce@momjian.us> writes: > I have updated the patch, attached, to be clearer about the requirement > that intermediate certificates need a chain to root certificates. I see that you removed the sentence The root certificate should be included in every case where <filename>postgresql.crt</> contains more than one certificate. in both places where it appeared. I seem to remember that I'd put that in on the basis of experimentation, ie it didn't work to provide just a partial chain. You appear to be telling people that it's safe to omit the root cert, and I think this is wrong. Specifically, rather than the text "trusted by the server, i.e. signed by a certificate in the server's <filename>root.crt</filename> file", I think you need to say "trusted by the server, i.e., appears in the server's <filename>root.crt</filename> file". Have you experimented with the configuration you're proposing, and if so, with which OpenSSL versions? regards, tom lane
On Mon, Dec 2, 2013 at 12:59:41PM -0500, Tom Lane wrote: > Bruce Momjian <bruce@momjian.us> writes: > > I have updated the patch, attached, to be clearer about the requirement > > that intermediate certificates need a chain to root certificates. > > I see that you removed the sentence > > The root > certificate should be included in every case where > <filename>postgresql.crt</> contains more than one certificate. > > in both places where it appeared. I seem to remember that I'd put that > in on the basis of experimentation, ie it didn't work to provide just > a partial chain. You appear to be telling people that it's safe to > omit the root cert, and I think this is wrong. > > Specifically, rather than the text "trusted by the server, i.e. signed by > a certificate in the server's <filename>root.crt</filename> file", I think > you need to say "trusted by the server, i.e., appears in the server's > <filename>root.crt</filename> file". Have you experimented with the > configuration you're proposing, and if so, with which OpenSSL versions? I am basing the text on the tests done in this thread, though I can test it myself too (though I have not yet). This email indicates we only need the client cert in the client, not the chain to root: http://www.postgresql.org/message-id/5146A103.8080609@2ndquadrant.com OK, we're good now, the server is sending us the intermediate cert werequire. Regular non-client-cert verified SSL is fine. Examination ofthe protocol chat shows that the server is sending a Server Hello with aCertificate message containingthe server and intermdediate certificateDNs: It can get the root and intermediate from the server, hence the "signed by" rather than "appears" wording. This text indicates also that the client doesn't have to have the certificate chain to the root: http://www.postgresql.org/message-id/514A9DDF.3050702@2ndquadrant.comDrat, you're quite right. I've always included the fullcertificatechain in client certs but it's in no way required. I don't fully understand the issues but the discussion seens to indicate this. Am I missing something? Should I run some tests? -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
On 12/02/2013 02:45 PM, Bruce Momjian wrote: > On Mon, Dec 2, 2013 at 12:59:41PM -0500, Tom Lane wrote: >> Bruce Momjian <bruce@momjian.us> writes: >>> I have updated the patch, attached, to be clearer about the requirement >>> that intermediate certificates need a chain to root certificates. >> I see that you removed the sentence >> >> The root >> certificate should be included in every case where >> <filename>postgresql.crt</> contains more than one certificate. >> >> in both places where it appeared. I seem to remember that I'd put that >> in on the basis of experimentation, ie it didn't work to provide just >> a partial chain. You appear to be telling people that it's safe to >> omit the root cert, and I think this is wrong. >> >> Specifically, rather than the text "trusted by the server, i.e. signed by >> a certificate in the server's <filename>root.crt</filename> file", I think >> you need to say "trusted by the server, i.e., appears in the server's >> <filename>root.crt</filename> file". Have you experimented with the >> configuration you're proposing, and if so, with which OpenSSL versions? > I am basing the text on the tests done in this thread, though I can test > it myself too (though I have not yet). This email indicates we only > need the client cert in the client, not the chain to root: > > http://www.postgresql.org/message-id/5146A103.8080609@2ndquadrant.com > > OK, we're good now, the server is sending us the intermediate cert we > require. Regular non-client-cert verified SSL is fine. Examination of > the protocol chat shows that the server is sending a Server Hello with a > Certificate message containing the server and intermdediate certificate > DNs: > > It can get the root and intermediate from the server, hence the "signed > by" rather than "appears" wording. This text indicates also that the > client doesn't have to have the certificate chain to the root: > > http://www.postgresql.org/message-id/514A9DDF.3050702@2ndquadrant.com > Drat, you're quite right. I've always included the full certificate > chain in client certs but it's in no way required. > > I don't fully understand the issues but the discussion seens to indicate > this. Am I missing something? Should I run some tests? > AIUI, you need a complete chain from one end to the other. So the cert being checked can include the intermediate cert in what it sends, or it can be in the root.crt at the other end, but one way or another, the checking end needs a complete chain from a root cert to the cert from the other end. cheers andrew
Bruce Momjian <bruce@momjian.us> writes: > On Mon, Dec 2, 2013 at 12:59:41PM -0500, Tom Lane wrote: >> I see that you removed the sentence >> The root >> certificate should be included in every case where >> <filename>postgresql.crt</> contains more than one certificate. > I don't fully understand the issues but the discussion seens to indicate > this. Am I missing something? Should I run some tests? My recollection is that if the client cert file includes *only* the client's own cert, the server will puzzle out how that connects to the certs it has. However, if the client cert file contains more than one cert (ie, client's cert and some intermediate-CA cert), the server will *not* try to associate the intermediate cert with some root cert it has. It wants the chain the client sends to terminate in a cert that it has listed directly in root.crt. It's possible that my recollection is faulty, or that this behavior was a bug that's been fixed in more recent OpenSSL versions. If it's the latter, though, I hesitate to tell people they can rely on the corrected behavior. The text in question is from May 2010, and I would've been testing on whatever OpenSSL version was then current in Fedora, so it would hardly be a version that's disappeared from the wild. regards, tom lane
On 12/02/2013 02:01 PM, Andrew Dunstan wrote: > AIUI, you need a complete chain from one end to the other. So the cert > being checked can include the intermediate cert in what it sends, or it > can be in the root.crt at the other end, but one way or another, the > checking end needs a complete chain from a root cert to the cert from > the other end. Yes. And the problem is that there is no way to prevent OpenSSL from accepting intermediate certificates supplied by the client. As a result, the server cannot accept client certificates signed by one intermediate CA without also accepting *any* client certificate that can present a chain back to the root CA. Frankly, this whole conversation reinforces my belief that this behavior is so counter-intuitive that it really should be changed. GnuTLS for the win? -- ======================================================================== Ian Pilcher arequipeno@gmail.com Sent from the cloud -- where it's alreadytomorrow ========================================================================
Ian Pilcher <arequipeno@gmail.com> writes: > Yes. And the problem is that there is no way to prevent OpenSSL from > accepting intermediate certificates supplied by the client. As a > result, the server cannot accept client certificates signed by one > intermediate CA without also accepting *any* client certificate that can > present a chain back to the root CA. Isn't that sort of the point? regards, tom lane
On 12/02/2013 02:17 PM, Tom Lane wrote: > Ian Pilcher <arequipeno@gmail.com> writes: >> Yes. And the problem is that there is no way to prevent OpenSSL from >> accepting intermediate certificates supplied by the client. As a >> result, the server cannot accept client certificates signed by one >> intermediate CA without also accepting *any* client certificate that can >> present a chain back to the root CA. > > Isn't that sort of the point? > I'm not sure what you're asking. The desired behavior (IMO) would be to accept client certificates signed by some intermediate CAs without accepting any client certificate that can present a chain back to the trusted root. This is currently not possible, mainly due to the way that OpenSSL works. -- ======================================================================== Ian Pilcher arequipeno@gmail.com Sent from the cloud -- where it's alreadytomorrow ========================================================================
On 12/02/2013 03:21 PM, Ian Pilcher wrote: > On 12/02/2013 02:17 PM, Tom Lane wrote: >> Ian Pilcher <arequipeno@gmail.com> writes: >>> Yes. And the problem is that there is no way to prevent OpenSSL from >>> accepting intermediate certificates supplied by the client. As a >>> result, the server cannot accept client certificates signed by one >>> intermediate CA without also accepting *any* client certificate that can >>> present a chain back to the root CA. >> Isn't that sort of the point? >> > I'm not sure what you're asking. The desired behavior (IMO) would be to > accept client certificates signed by some intermediate CAs without > accepting any client certificate that can present a chain back to the > trusted root. This is currently not possible, mainly due to the way > that OpenSSL works. > Wouldn't that amount to only partially trusting the root? It seems kinda odd. In any case, It's not something I think Postgres needs to solve. cheers andrew
Ian Pilcher <arequipeno@gmail.com> writes: > On 12/02/2013 02:17 PM, Tom Lane wrote: >> Isn't that sort of the point? > I'm not sure what you're asking. The desired behavior (IMO) would be to > accept client certificates signed by some intermediate CAs without > accepting any client certificate that can present a chain back to the > trusted root. This is currently not possible, mainly due to the way > that OpenSSL works. That notion seems pretty bogus to me. If you don't trust the root CA to not hand out child CA certs to untrustworthy people, then you don't really trust the root CA, do you? You should just list the certs of the intermediate CAs you *do* trust in the server's root.crt. In any case, the idea that this is somehow OpenSSL's fault and another implementation of the same protocol wouldn't have the same issue sounds pretty silly. regards, tom lane
On Mon, Dec 2, 2013 at 03:01:25PM -0500, Andrew Dunstan wrote: > >I don't fully understand the issues but the discussion seens to indicate > >this. Am I missing something? Should I run some tests? > > > > AIUI, you need a complete chain from one end to the other. So the > cert being checked can include the intermediate cert in what it > sends, or it can be in the root.crt at the other end, but one way or > another, the checking end needs a complete chain from a root cert to > the cert from the other end. Yes, this was my understanding. Let me ask a simple question --- can you put only the client cert on the client (postgresql.crt) and only the root cert on the server (root.crt), and will it work? I think Tom's question is whether OpenSSL will read through all the entries in root.crt and find the one that signed the remote cert, and has it always done that, i.e. does the remote side have to provide the upper-level cert to match against. One big thing I learned from this is that the local root.crt is only used to verify remote certificates; it isn't related to how the remote end verifies your certificate. Now, in most cases, the root.crt is identical for clients and servers, but it doesn't have to be. Put another way, I thought you put the root cert in your local root.crt and the local cert in postgresql.crt or server.crt, but in fact the requirement is that the local certificate chain to root must be in the remote root.crt. Of course, I might be wrong, but I am trying to clarify this for our users. -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
Bruce Momjian <bruce@momjian.us> writes: > Yes, this was my understanding. Let me ask a simple question --- can > you put only the client cert on the client (postgresql.crt) and only the > root cert on the server (root.crt), and will it work? Yes, that's surely always worked. > I think Tom's question is whether OpenSSL will read through all the > entries in root.crt and find the one that signed the remote cert, and > has it always done that, i.e. does the remote side have to provide the > upper-level cert to match against. My point is specifically that it didn't seem to work when the client cert file includes an intermediate CA cert, but not a full path to a trusted root cert. (Note that anything in the server's root.crt file is a trusted root cert so far as the server is concerned --- it doesn't matter if it's a child of some other CA.) > One big thing I learned from this is that the local root.crt is only > used to verify remote certificates; it isn't related to how the remote > end verifies your certificate. Now, in most cases, the root.crt is > identical for clients and servers, but it doesn't have to be. Yes, we were already explaining that in the existing docs. regards, tom lane
On Mon, Dec 2, 2013 at 03:07:48PM -0500, Tom Lane wrote: > Bruce Momjian <bruce@momjian.us> writes: > > On Mon, Dec 2, 2013 at 12:59:41PM -0500, Tom Lane wrote: > >> I see that you removed the sentence > >> The root > >> certificate should be included in every case where > >> <filename>postgresql.crt</> contains more than one certificate. > > > I don't fully understand the issues but the discussion seens to indicate > > this. Am I missing something? Should I run some tests? > > My recollection is that if the client cert file includes *only* the > client's own cert, the server will puzzle out how that connects to the > certs it has. However, if the client cert file contains more than one > cert (ie, client's cert and some intermediate-CA cert), the server > will *not* try to associate the intermediate cert with some root cert it > has. It wants the chain the client sends to terminate in a cert that it > has listed directly in root.crt. OK, so you are saying if the client only supplies one cert, it will try to find a signing cert in root.crt, but if multiple certs are supplied, you have to get a cert match (not a signing). I can adjust the docs for that. -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
* Ian Pilcher (arequipeno@gmail.com) wrote: > On 12/02/2013 02:17 PM, Tom Lane wrote: > > Ian Pilcher <arequipeno@gmail.com> writes: > >> Yes. And the problem is that there is no way to prevent OpenSSL from > >> accepting intermediate certificates supplied by the client. As a > >> result, the server cannot accept client certificates signed by one > >> intermediate CA without also accepting *any* client certificate that can > >> present a chain back to the root CA. > > > > Isn't that sort of the point? Yes. > I'm not sure what you're asking. The desired behavior (IMO) would be to > accept client certificates signed by some intermediate CAs without > accepting any client certificate that can present a chain back to the > trusted root. This is currently not possible, mainly due to the way > that OpenSSL works. It's not possible because of the way certificate chains are *intended* to work.. What you're asking for is something which was not a use-case for certificates. Cross-organizational trusts were done through 'bridge' CAs, which then can have policies about what attributes are allowed to pass through a bridge or be trusted from a not-our-root-CA. Intermediate certificates are not the same thing and were never intended to be used in the way you're asking for. Thanks, Stephen
On 12/02/2013 03:44 PM, Tom Lane wrote: > Bruce Momjian <bruce@momjian.us> writes: >> Let me ask a simple question --- can >> you put only the client cert on the client (postgresql.crt) and only the >> root cert on the server (root.crt), and will it work? > Yes, that's surely always worked. Not if the client has been signed by an intermediate CA, surely. Either the server must have the intermediate CA cert in its root.crt or the client must supply it along with the end cert. cheers
On Mon, Dec 2, 2013 at 03:44:18PM -0500, Tom Lane wrote: > Bruce Momjian <bruce@momjian.us> writes: > > Yes, this was my understanding. Let me ask a simple question --- can > > you put only the client cert on the client (postgresql.crt) and only the > > root cert on the server (root.crt), and will it work? > > Yes, that's surely always worked. > > > I think Tom's question is whether OpenSSL will read through all the > > entries in root.crt and find the one that signed the remote cert, and > > has it always done that, i.e. does the remote side have to provide the > > upper-level cert to match against. > > My point is specifically that it didn't seem to work when the client cert > file includes an intermediate CA cert, but not a full path to a trusted > root cert. (Note that anything in the server's root.crt file is a trusted > root cert so far as the server is concerned --- it doesn't matter if it's > a child of some other CA.) OK, so you are really saying that a multi-cert client has to supply a chain right up to the root as the server will not walk the chain for you up to the root, at least for some versions of openssl --- kind of makes sense. The email tester seems to have a version that does, but as you stated, all versions might not. Because you said that all root.crt CAs are treated as trusted, can you just match an intermediate CA that appears in root.crt? Do you really need to match the a root CA or just one in root.crt? -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
On Mon, Dec 2, 2013 at 03:57:45PM -0500, Andrew Dunstan wrote: > > On 12/02/2013 03:44 PM, Tom Lane wrote: > >Bruce Momjian <bruce@momjian.us> writes: > >>Let me ask a simple question --- can > >>you put only the client cert on the client (postgresql.crt) and only the > >>root cert on the server (root.crt), and will it work? > >Yes, that's surely always worked. > > Not if the client has been signed by an intermediate CA, surely. > Either the server must have the intermediate CA cert in its root.crt > or the client must supply it along with the end cert. Right. Tom is saying that for his openssl version, he had to have the client supply a certificate _matching_ something in the remote root.crt, not just signed by it. -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
* Bruce Momjian (bruce@momjian.us) wrote: > Yes, this was my understanding. Let me ask a simple question --- can > you put only the client cert on the client (postgresql.crt) and only the > root cert on the server (root.crt), and will it work? Only if the client cert is signed directly by the root cert, which is generally discouraged.. The intermediate cert needs to be *somewhere*. As for Tom's question about the client presenting an intermediate cert- I don't know offhand if that works with our code, but as far as SSL goes, last I checked it's *intended* to work. > I think Tom's question is whether OpenSSL will read through all the > entries in root.crt and find the one that signed the remote cert, and > has it always done that, i.e. does the remote side have to provide the > upper-level cert to match against. Either side should be able to present certificates that build the chain of trust. Practically speaking, that may not work due to sheer number of combinations which you might end up with- I don't recall specifically if that ends up being an issue or not (it's been a while). > One big thing I learned from this is that the local root.crt is only > used to verify remote certificates; it isn't related to how the remote > end verifies your certificate. Now, in most cases, the root.crt is > identical for clients and servers, but it doesn't have to be. That's correct, yes. > Put another way, I thought you put the root cert in your local root.crt > and the local cert in postgresql.crt or server.crt, but in fact the > requirement is that the local certificate chain to root must be in the > remote root.crt. Right.. You use your cert to prove to the *other* guy that you are who you claim to be. Does that help in the understanding..? You don't need to prove to yourself who you are.. > Of course, I might be wrong, but I am trying to clarify this for our > users. Thanks for working on this. I do wish we could improve how we handle certificates in general- and that definitely goes for the documentation as much as the various options we provide. Thanks, Stephen
* Bruce Momjian (bruce@momjian.us) wrote: > On Mon, Dec 2, 2013 at 03:57:45PM -0500, Andrew Dunstan wrote: > > > > On 12/02/2013 03:44 PM, Tom Lane wrote: > > >Bruce Momjian <bruce@momjian.us> writes: > > >>Let me ask a simple question --- can > > >>you put only the client cert on the client (postgresql.crt) and only the > > >>root cert on the server (root.crt), and will it work? > > >Yes, that's surely always worked. > > > > Not if the client has been signed by an intermediate CA, surely. > > Either the server must have the intermediate CA cert in its root.crt > > or the client must supply it along with the end cert. > > Right. Tom is saying that for his openssl version, he had to have the > client supply a certificate _matching_ something in the remote root.crt, > not just signed by it. Err, no.. That's not right. The client certificate needs to be *signed* by the root certificate, or by an intermediate which is signed by the root and is available to the server for verification. The client certificate does *not* need to exist in the root.crt... Thanks, Stephen
On 12/02/2013 02:29 PM, Andrew Dunstan wrote: > Wouldn't that amount to only partially trusting the root? It seems kinda > odd. In any case, It's not something I think Postgres needs to solve. I think that the fundamental problem is that authentication and authorization are being conflated. From the OpenSSL point-of-view, it is checking that the client certificate is valid (not expired, signed by a trusted chain of CAs, etc.); i.e. it's only doing authentication. PostgreSQL is trusting any client certificate that is validated by OpenSSL. It's essentially trusting OpenSSL to do both authentication and authorization, but OpenSSL isn't doing the latter. Does PostgreSQL need to solve this? I don't know, but it certainly would be a nice capability to have -- if only to avoid the confusion that currently surrounds the issue. -- ======================================================================== Ian Pilcher arequipeno@gmail.com Sent from the cloud -- where it's alreadytomorrow ========================================================================
* Ian Pilcher (arequipeno@gmail.com) wrote: > On 12/02/2013 02:29 PM, Andrew Dunstan wrote: > > Wouldn't that amount to only partially trusting the root? It seems kinda > > odd. In any case, It's not something I think Postgres needs to solve. > > I think that the fundamental problem is that authentication and > authorization are being conflated. From the OpenSSL point-of-view, it > is checking that the client certificate is valid (not expired, signed by > a trusted chain of CAs, etc.); i.e. it's only doing authentication. Of course. > PostgreSQL is trusting any client certificate that is validated by > OpenSSL. It's essentially trusting OpenSSL to do both authentication > and authorization, but OpenSSL isn't doing the latter. That isn't at *all* accurate. Authorization is handled by pg_ident and PG's role and grant system. We are only using OpenSSL's trust of the certificate for authentication. > Does PostgreSQL need to solve this? I don't know, but it certainly > would be a nice capability to have -- if only to avoid the confusion > that currently surrounds the issue. I have no idea what you're getting at here. Thanks, Stephen
On Mon, Dec 2, 2013 at 04:12:13PM -0500, Stephen Frost wrote: > * Bruce Momjian (bruce@momjian.us) wrote: > > On Mon, Dec 2, 2013 at 03:57:45PM -0500, Andrew Dunstan wrote: > > > > > > On 12/02/2013 03:44 PM, Tom Lane wrote: > > > >Bruce Momjian <bruce@momjian.us> writes: > > > >>Let me ask a simple question --- can > > > >>you put only the client cert on the client (postgresql.crt) and only the > > > >>root cert on the server (root.crt), and will it work? > > > >Yes, that's surely always worked. > > > > > > Not if the client has been signed by an intermediate CA, surely. > > > Either the server must have the intermediate CA cert in its root.crt > > > or the client must supply it along with the end cert. > > > > Right. Tom is saying that for his openssl version, he had to have the > > client supply a certificate _matching_ something in the remote root.crt, > > not just signed by it. > > Err, no.. That's not right. > > The client certificate needs to be *signed* by the root certificate, or > by an intermediate which is signed by the root and is available to the > server for verification. > > The client certificate does *not* need to exist in the root.crt... Sorry, I should have said: Tom is saying that for his openssl version, a client that passedan intermediate certificate had to supply a certificate _matching_somethingin the remote root.crt, not just signed by it. At least I think that was the issue, rather than requiring the client to supply a "root" certificate, meaning the client can supply an intermediate or root certificicate, as long as it appears in the root.crt file on the remote end. Once I fully understand this I can post a proposed doc change. -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
Bruce Momjian <bruce@momjian.us> writes: > Sorry, I should have said: > Tom is saying that for his openssl version, a client that passed > an intermediate certificate had to supply a certificate _matching_ > something in the remote root.crt, not just signed by it. > At least I think that was the issue, rather than requiring the client to > supply a "root" certificate, meaning the client can supply an > intermediate or root certificicate, as long as it appears in the > root.crt file on the remote end. As far as the server is concerned, anything listed in its root.crt *is* a trusted root CA. Doesn't matter if it's a child of some other CA. The issue is that the client's cert has to be linked to some element of root.crt somehow. In principle you'd think that if the client provides an intermediate CA cert, the server should be able to match that to whichever root.crt member signed it, but that wasn't what I saw happening. It'd be good for someone who uses SSL more than I do to replicate the experiment, though. It's not impossible that I screwed up. regards, tom lane
* Bruce Momjian (bruce@momjian.us) wrote: > Sorry, I should have said: > > Tom is saying that for his openssl version, a client that passed > an intermediate certificate had to supply a certificate _matching_ > something in the remote root.crt, not just signed by it. > > At least I think that was the issue, rather than requiring the client to > supply a "root" certificate, meaning the client can supply an > intermediate or root certificicate, as long as it appears in the > root.crt file on the remote end. That wasn't the impression I got from Tom's comments; hopefully he'll clarify. I really don't think OpenSSL actually does 'matching' kind of work as is being described here.. It certainly shouldn't be deciding on the validity of a certificate based on that. I wonder if this is related to the question which was raised previously about if we trust *intermediate CAs* when no root CA exists (which we certainly should *not* be doing, but it's hardly clear what the heck happens when everything has to go into a file called 'root.crt'). > Once I fully understand this I can post a proposed doc change. Thank you much for offering to write up the docs around this. Stephen
On 12/02/2013 02:32 PM, Tom Lane wrote: > Ian Pilcher <arequipeno@gmail.com> writes: >> I'm not sure what you're asking. The desired behavior (IMO) would be to >> accept client certificates signed by some intermediate CAs without >> accepting any client certificate that can present a chain back to the >> trusted root. This is currently not possible, mainly due to the way >> that OpenSSL works. > > That notion seems pretty bogus to me. If you don't trust the root CA to > not hand out child CA certs to untrustworthy people, then you don't really > trust the root CA, do you? You should just list the certs of the > intermediate CAs you *do* trust in the server's root.crt. Assume you have a corporate policy that says that all SSL certificates must be signed for the corporate root CA, which is an intermediate CA signed by Verisign. Presumably this means that you (or someone in your organization) trusts Verisign to exercise some degree of care in issuing their certificates, but that's a long way from wanting to allow every Verisign-signed (or "rooted") certificate to connect to your database server. BTW, you can't just "list the certs of the intermediate CAs you do trust"; you have to put the root CA certificate into root.crt in order for OpenSSL to build a complete chain, and this means trusting *every* client certificate that can present a chain back to that root. That is the problem. > In any case, the idea that this is somehow OpenSSL's fault and another > implementation of the same protocol wouldn't have the same issue sounds > pretty silly. Actually other implementations do this. In fact, a flag was added to OpenSSL fairly recently to allow validating a chain only up to an intermediate CA for this very reason. -- ======================================================================== Ian Pilcher arequipeno@gmail.com Sent from the cloud -- where it's alreadytomorrow ========================================================================
On 12/02/2013 03:15 PM, Stephen Frost wrote: > That isn't at *all* accurate. Authorization is handled by pg_ident and > PG's role and grant system. We are only using OpenSSL's trust of the > certificate for authentication. OK, how do I configure Postgres to only allow connections when the client presents a certificate signed by a particular intermediate CA? AFAIK, there is currently no way to do this. -- ======================================================================== Ian Pilcher arequipeno@gmail.com Sent from the cloud -- where it's alreadytomorrow ========================================================================
On 12/02/2013 04:17 PM, Tom Lane wrote: > Bruce Momjian <bruce@momjian.us> writes: >> Sorry, I should have said: >> Tom is saying that for his openssl version, a client that passed >> an intermediate certificate had to supply a certificate _matching_ >> something in the remote root.crt, not just signed by it. >> At least I think that was the issue, rather than requiring the client to >> supply a "root" certificate, meaning the client can supply an >> intermediate or root certificicate, as long as it appears in the >> root.crt file on the remote end. > As far as the server is concerned, anything listed in its root.crt *is* a > trusted root CA. Doesn't matter if it's a child of some other CA. > > The issue is that the client's cert has to be linked to some element of > root.crt somehow. In principle you'd think that if the client provides > an intermediate CA cert, the server should be able to match that to > whichever root.crt member signed it, but that wasn't what I saw > happening. It'd be good for someone who uses SSL more than I do to > replicate the experiment, though. It's not impossible that I screwed up. > I have a test script I developed when I had some difficulties with intermediate CAs a while back. I'll see if I can clean it up and test this out. cheers andrew
* Tom Lane (tgl@sss.pgh.pa.us) wrote: > Bruce Momjian <bruce@momjian.us> writes: > > At least I think that was the issue, rather than requiring the client to > > supply a "root" certificate, meaning the client can supply an > > intermediate or root certificicate, as long as it appears in the > > root.crt file on the remote end. > > As far as the server is concerned, anything listed in its root.crt *is* a > trusted root CA. Doesn't matter if it's a child of some other CA. I was afraid that was the case.. Are we sure that's *still* being done? I recall there being discussion around this previously because it's surely wrong from a certificate trust perspective. At the same time, I'm not sure what options we have because of the existing GUCs and the APIs we use to talk with OpenSSL- that might just be how it works because we don't allow the user to provide a seperate file of intermediate CAs. This is one reason why I've generally encouraged use of the system-wide OpenSSL configuration directories and minimizing the configuration done in the PG files for certificate-based connections. > The issue is that the client's cert has to be linked to some element of > root.crt somehow. In principle you'd think that if the client provides > an intermediate CA cert, the server should be able to match that to > whichever root.crt member signed it, but that wasn't what I saw > happening. It'd be good for someone who uses SSL more than I do to > replicate the experiment, though. It's not impossible that I screwed up. Right, we have to be able to go from the client's cert up through to the root certificate. That 'root' certificate might possibly be anything we've told OpenSSL is a 'root' even when it's actually an intermediate CA, but in the 'outside' certificate world, the root CAs and the intermediate CAs are configured independently. Thanks, Stephen
On Mon, Dec 2, 2013 at 04:17:57PM -0500, Tom Lane wrote: > Bruce Momjian <bruce@momjian.us> writes: > > Sorry, I should have said: > > > Tom is saying that for his openssl version, a client that passed > > an intermediate certificate had to supply a certificate _matching_ > > something in the remote root.crt, not just signed by it. > > > At least I think that was the issue, rather than requiring the client to > > supply a "root" certificate, meaning the client can supply an > > intermediate or root certificicate, as long as it appears in the > > root.crt file on the remote end. > > As far as the server is concerned, anything listed in its root.crt *is* a > trusted root CA. Doesn't matter if it's a child of some other CA. Uh, the original poster complained that he couldn't put _just_ an intermediate certificate in root.crt and have it work: http://www.postgresql.org/message-id/kh90q0$tv8$1@ger.gmane.orgI expected that I could simply use the client CA certificateas$PGDATA/root.crt, but this does not work; I get an "unknown ca" error.AFAICT, there is absolutely no way tomake PostgreSQL trust a CA that isnot a self-signed root CA. I am confused. > The issue is that the client's cert has to be linked to some element of > root.crt somehow. In principle you'd think that if the client provides > an intermediate CA cert, the server should be able to match that to > whichever root.crt member signed it, but that wasn't what I saw > happening. It'd be good for someone who uses SSL more than I do to > replicate the experiment, though. It's not impossible that I screwed up. Agreed. Anyone? I can try, but I am a novice. -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
Ian Pilcher <arequipeno@gmail.com> writes: > BTW, you can't just "list the certs of the intermediate CAs you do > trust"; you have to put the root CA certificate into root.crt in order > for OpenSSL to build a complete chain, I believe you are mistaken. OpenSSL just wants a chain to one of the certs you've told it to trust. But in any case, Stephen is right that intermediate certs aren't meant to be used in the way you want. They're just a mechanism for a CA to use for its own purposes. regards, tom lane
On Mon, Dec 2, 2013 at 03:19:43PM -0600, Ian Pilcher wrote: > On 12/02/2013 02:32 PM, Tom Lane wrote: > > Ian Pilcher <arequipeno@gmail.com> writes: > >> I'm not sure what you're asking. The desired behavior (IMO) would be to > >> accept client certificates signed by some intermediate CAs without > >> accepting any client certificate that can present a chain back to the > >> trusted root. This is currently not possible, mainly due to the way > >> that OpenSSL works. > > > > That notion seems pretty bogus to me. If you don't trust the root CA to > > not hand out child CA certs to untrustworthy people, then you don't really > > trust the root CA, do you? You should just list the certs of the > > intermediate CAs you *do* trust in the server's root.crt. > > Assume you have a corporate policy that says that all SSL certificates > must be signed for the corporate root CA, which is an intermediate CA > signed by Verisign. Presumably this means that you (or someone in your > organization) trusts Verisign to exercise some degree of care in issuing > their certificates, but that's a long way from wanting to allow every > Verisign-signed (or "rooted") certificate to connect to your database > server. Yes, this is why we recommend self-signed certificates for Postgres. In this case, what value is there in using an intermediate certificate who's root is Verisign? > BTW, you can't just "list the certs of the intermediate CAs you do > trust"; you have to put the root CA certificate into root.crt in order > for OpenSSL to build a complete chain, and this means trusting *every* > client certificate that can present a chain back to that root. That is > the problem. > > > In any case, the idea that this is somehow OpenSSL's fault and another > > implementation of the same protocol wouldn't have the same issue sounds > > pretty silly. > > Actually other implementations do this. In fact, a flag was added to > OpenSSL fairly recently to allow validating a chain only up to an > intermediate CA for this very reason. Interesting. -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
* Ian Pilcher (arequipeno@gmail.com) wrote: > On 12/02/2013 03:15 PM, Stephen Frost wrote: > > That isn't at *all* accurate. Authorization is handled by pg_ident and > > PG's role and grant system. We are only using OpenSSL's trust of the > > certificate for authentication. > > OK, how do I configure Postgres to only allow connections when the > client presents a certificate signed by a particular intermediate CA? You don't- but that's because the certificate trust chain isn't part of the trust definition for certificates- which is a *certificate* thing and hasn't got anything to do with PG. It would also make CA rollover *extremely* painful, which is why people don't do it. You want your intermediate CAs to have relatively short-lived times and if you start codifying which intermediate CAs you trust, things get very ugly when you need to bring a new intermediate CA online to replace the ageing one and people start trying to access your service with certificates signed off the new one. Which certificate-based system allows you to do this? As I mentioned up-thread, in the certificate realm (at least in the US government..), this is handled through CA bridges between root CAs (there is no single 'US government' root CA). Thanks, Stephen
* Ian Pilcher (arequipeno@gmail.com) wrote: > > In any case, the idea that this is somehow OpenSSL's fault and another > > implementation of the same protocol wouldn't have the same issue sounds > > pretty silly. > > Actually other implementations do this. In fact, a flag was added to > OpenSSL fairly recently to allow validating a chain only up to an > intermediate CA for this very reason. Perhaps that's been a recent change, but it certainly wasn't part of the original approach and complaining that PG doesn't do it is hardly fair. Indeed, it sounds like this is something which should *still* be done outside of PG and through however you configure OpenSSL on your system. Regardless, it's completely off-topic for this discussion, which is about documenting what we *currently* do. If you'd like to propose a new set of features, or better yet, a rework of how we configure SSL in PG, please do so on another thread. :) Thanks! Stephen
On 12/02/2013 04:17 PM, Tom Lane wrote: > Bruce Momjian <bruce@momjian.us> writes: >> Sorry, I should have said: >> Tom is saying that for his openssl version, a client that passed >> an intermediate certificate had to supply a certificate _matching_ >> something in the remote root.crt, not just signed by it. >> At least I think that was the issue, rather than requiring the client to >> supply a "root" certificate, meaning the client can supply an >> intermediate or root certificicate, as long as it appears in the >> root.crt file on the remote end. > As far as the server is concerned, anything listed in its root.crt *is* a > trusted root CA. Doesn't matter if it's a child of some other CA. But it does need to be signed by a trusted signatory. At least in my test script (pretty ugly, but shown below for completeness), the Intermediate CA cert is signed with the Root cert rather than being self-signed as the Root cert is, and so if the server doesn't have that root cert as a trusted cert the validation fails. In case 1, we put the root CA cert on the server and append the intermediate CA cert to the client's cert. This succeeds. In case 2, we put the intermediate CA cert on the server without the root CA's cert, and use the bare client cert. This fails. In case 3, we put both the root and the intermediate certs in the server's root.crt, and use the bare client key, and as expected this succeeds. So the idea that you can just plonk any Intermediate CA cert in root.crt and have all keys it signs validated is not true, AFAICT. OpenSSL version 1.0.0j was used in these tests, on a Fedora 16 box. cheers andrew SUBJ='/C=US/ST=Virginia/L=Herndon/O=testca/OU=eng' ROOTPASS='rootyroot' INTERMEDIATEPASS='branchybranch' LEAFPASS='leafyleaf' CLIENTLOGIN=andrew SERVERHOST=emma INSTALL='/home/andrew/pgl/inst.93.5709' DATA="$INSTALL/testca" PGPORT=5809; export PGPORT rm -rf myCA ; rm -rf myCA mkdir myCA cd myCA # make root ca in its own directory mkdir rootCA cd rootCA DIR=`pwd` cp /etc/pki/tls/openssl.cnf . sed -i -e "s,^dir.*,dir = $DIR," -e 's/#unique_subject/unique_subject/' openssl.cnf mkdir certs private newcerts chmod 700 . echo 1000 > serial touch index.txt echo 01 > crlnumber openssl req -passout pass:"$ROOTPASS" -new -x509 -days 3650 -extensions v3_ca -config openssl.cnf -subj "$SUBJ/CN=root CA" -keyout private/cakey.pem -out cacert.pem openssl rsa -passin pass:"$ROOTPASS" -in private/cakey.pem -out private/cakey.pem # now intermediate CA cd .. cp /etc/pki/tls/openssl.cnf . DIR=`pwd` sed -i -e "s,^dir.*,dir = $DIR," -e 's/#unique_subject/unique_subject/' openssl.cnf mkdir certs private newcerts chmod 700 . echo 1000 > serial touch index.txt echo 01 > crlnumber openssl genrsa -passout pass:"$INTERMEDIATEPASS" -des3 -out private/rakey.pem 4096 openssl rsa -passin pass:"$INTERMEDIATEPASS" -in private/rakey.pem -out private/rakey.pem openssl req -passin pass:INTERMEDIATEPASS -new -subj "$SUBJ/CN=intermediate" -sha1 -key private/rakey.pem -out ra.csr -config openssl.cnf # sign using root CA openssl ca -extensions v3_ca -days 365 -out ra.crt -in ra.csr -config rootCA/openssl.cnf -batch rm ra.csr cp rootCA/cacert.pem root.crt # # postgresql client # openssl req -passout pass:$LEAFPASS -subj "$SUBJ/CN=$CLIENTLOGIN" -config openssl.cnf -new -out postgresql.req -keyout postgresql.key openssl rsa -passin pass:$LEAFPASS -in postgresql.key -out postgresql.key openssl ca -config openssl.cnf -in postgresql.req -out postgresql.crt -cert ra.crt -keyfile private/rakey.pem -batch chmod 600 postgresql.key rm postgresql.req # # postgresql server # openssl req -passout pass:$LEAFPASS -config openssl.cnf -subj "$SUBJ/CN=$SERVERHOST" -new -out server.req -keyout server.key openssl rsa -passin pass:$LEAFPASS -in server.key -out server.key openssl ca -config openssl.cnf -in server.req -out server.crt -cert ra.crt -keyfile private/rakey.pem -batch chmod 600 server.key rm server.req cat ra.crt >> server.crt cat postgresql.crt ra.crt >> client.crt # copy certs to server cp root.crt $DATA/root.crt cp server.crt $DATA cp server.key $DATA rm -f $DATA/root.crl # restart the server set -x (cd $INSTALL && $INSTALL/bin/pg_ctl -D $DATA -l $DIR/logfile.tca -w restart) # make sure certs work ok $INSTALL/bin/psql "sslmode=verify-ca host=localhost sslrootcert=root.crt sslcert=client.crt sslkey=postgresql.key" -c 'select $$key 1 OK$$, ssl_client_dn(), ssl_client_serial(), ssl_issuer_dn()' # copy intermediate cert to server's root and try again with bare client cert cp ra.crt $DATA/root.crt (cd $INSTALL && $INSTALL/bin/pg_ctl -D $DATA -l $DIR/logfile.tca -w restart) $INSTALL/bin/psql "sslmode=verify-ca host=localhost sslrootcert=root.crt sslcert=postgresql.crt sslkey=postgresql.key" -c 'select $$key 1 OK$$, ssl_client_dn(), ssl_client_serial(), ssl_issuer_dn()' # copy root cert to server's root after intermediate crt and try again with bare client cert cat root.crt >> $DATA/root.crt (cd $INSTALL && $INSTALL/bin/pg_ctl -D $DATA -l $DIR/logfile.tca -w restart) $INSTALL/bin/psql "sslmode=verify-ca host=localhost sslrootcert=root.crt sslcert=postgresql.crt sslkey=postgresql.key" -c 'select $$key 1 OK$$, ssl_client_dn(), ssl_client_serial(), ssl_issuer_dn()'
* Andrew Dunstan (andrew@dunslane.net) wrote: > But it does need to be signed by a trusted signatory. At least in my > test script (pretty ugly, but shown below for completeness), the > Intermediate CA cert is signed with the Root cert rather than being > self-signed as the Root cert is, and so if the server doesn't have > that root cert as a trusted cert the validation fails. Ok, good, that's really how it "should" be. As a side-note, I'd be very curious about a self-signed intermediate cert.. :) > In case 1, we put the root CA cert on the server and append the > intermediate CA cert to the client's cert. This succeeds. In case 2, > we put the intermediate CA cert on the server without the root CA's > cert, and use the bare client cert. This fails. In case 3, we put > both the root and the intermediate certs in the server's root.crt, > and use the bare client key, and as expected this succeeds. Excellent, that's really how it ought to be and I'm glad you had a chance to test and verify it. > So the idea that you can just plonk any Intermediate CA cert in > root.crt and have all keys it signs validated is not true, AFAICT. I'm afraid it may have been true once, a while back, but we fixed it. Thanks! Stephen
On Mon, Dec 2, 2013 at 04:56:56PM -0500, Stephen Frost wrote: > * Ian Pilcher (arequipeno@gmail.com) wrote: > > > In any case, the idea that this is somehow OpenSSL's fault and another > > > implementation of the same protocol wouldn't have the same issue sounds > > > pretty silly. > > > > Actually other implementations do this. In fact, a flag was added to > > OpenSSL fairly recently to allow validating a chain only up to an > > intermediate CA for this very reason. > > Perhaps that's been a recent change, but it certainly wasn't part of the > original approach and complaining that PG doesn't do it is hardly fair. > Indeed, it sounds like this is something which should *still* be done > outside of PG and through however you configure OpenSSL on your system. > > Regardless, it's completely off-topic for this discussion, which is > about documenting what we *currently* do. If you'd like to propose a > new set of features, or better yet, a rework of how we configure SSL in > PG, please do so on another thread. :) Uh, this thread actually started with Ian's feature request, and has changed to document the current behavior. -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
* Bruce Momjian (bruce@momjian.us) wrote: > Uh, this thread actually started with Ian's feature request, and has > changed to document the current behavior. Whoops, apologies for that then- I clearly came into it (or perhaps more accurately, was brought into it) after the start of the thread. I'm happy to start a new thread for the discussion around documenting the current behavior, if that would help. :) Thanks! Stephen
On Mon, Dec 2, 2013 at 05:35:06PM -0500, Andrew Dunstan wrote: > > On 12/02/2013 04:17 PM, Tom Lane wrote: > >Bruce Momjian <bruce@momjian.us> writes: > >>Sorry, I should have said: > >> Tom is saying that for his openssl version, a client that passed > >> an intermediate certificate had to supply a certificate _matching_ > >> something in the remote root.crt, not just signed by it. > >>At least I think that was the issue, rather than requiring the client to > >>supply a "root" certificate, meaning the client can supply an > >>intermediate or root certificicate, as long as it appears in the > >>root.crt file on the remote end. > >As far as the server is concerned, anything listed in its root.crt *is* a > >trusted root CA. Doesn't matter if it's a child of some other CA. > > > But it does need to be signed by a trusted signatory. At least in my > test script (pretty ugly, but shown below for completeness), the > Intermediate CA cert is signed with the Root cert rather than being > self-signed as the Root cert is, and so if the server doesn't have > that root cert as a trusted cert the validation fails. > > In case 1, we put the root CA cert on the server and append the > intermediate CA cert to the client's cert. This succeeds. In case 2, > we put the intermediate CA cert on the server without the root CA's > cert, and use the bare client cert. This fails. In case 3, we put > both the root and the intermediate certs in the server's root.crt, > and use the bare client key, and as expected this succeeds. > > So the idea that you can just plonk any Intermediate CA cert in > root.crt and have all keys it signs validated is not true, AFAICT. > > OpenSSL version 1.0.0j was used in these tests, on a Fedora 16 box. OK, that behavior matches the behavior Ian observed and also matches my most recent doc patch. I know Tom saw something different, but unless he can reproduce it, I am thinking my doc patch is our best solution. -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
On Mon, Dec 2, 2013 at 12:44:08PM -0500, Bruce Momjian wrote: > On Sat, Nov 30, 2013 at 12:10:19PM -0500, Bruce Momjian wrote: > > > Drat, you're quite right. I've always included the full certificate > > > chain in client certs but it's in no way required. > > > > > > I guess that pretty much means maintaining the status quo and documenting > > > it better. > > > > I have developed the attached patch to document this behavior. My goals > > were: > > > > * clarify that a cert can match a remote intermediate or root certificate > > * clarify that the client cert must match a server root.crt > > * clarify that the server cert much match a client root.crt > > * clarify that the root certificate does not have to be specified > > in the client or server cert as long as the remote end has the chain > > to the root > > > > Does it meet these goals? Is it correct? > > I have updated the patch, attached, to be clearer about the requirement > that intermediate certificates need a chain to root certificates. Patch applied to head. -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +