Hi, OpenSSL now has X509_V_FLAG_PARTIAL_CHAIN support in the code base as of 1.0.2a.
I would like to submit a patch to enable X509_V_FLAG_PARTIAL_CHAIN support in OpenLDAP libldap, assuming it exists in the version of OpenSSL being use to build OpenLDAP.
Before I submit any patch I would like to know that would be acceptable for integration.
Should support always be enabled if the version of OpenSSL has it e.g. ifdef on X509_V_FLAG_PARTIAL_CHAIN Should it be a config time option check and ifdef enable if found in e.g. like the ifdef on HAVE_OPENSSL_CRL Are there more requirements that is required in the patch, before it would be accepted such as ldap_set_option support?
Thanks in advance, Doug.
Doug Leavitt wrote:
Hi, OpenSSL now has X509_V_FLAG_PARTIAL_CHAIN support in the code base as of 1.0.2a.
I would like to submit a patch to enable X509_V_FLAG_PARTIAL_CHAIN support in OpenLDAP libldap, assuming it exists in the version of OpenSSL being use to build OpenLDAP.
What's the use case? It appears that the feature has been in OpenSSL since around 2012, but I don't see much documentation or chatter about it. Why is it useful, and do GnuTLS and MozNSS already support a similar feature?
Before I submit any patch I would like to know that would be acceptable for integration.
Should support always be enabled if the version of OpenSSL has it e.g. ifdef on X509_V_FLAG_PARTIAL_CHAIN Should it be a config time option check and ifdef enable if found in e.g. like the ifdef on HAVE_OPENSSL_CRL Are there more requirements that is required in the patch, before it would be accepted such as ldap_set_option support?
Thanks in advance, Doug.
Sorry for the delay. I needed to do some due diligence before responding.
On 06/06/15 13:35, Howard Chu wrote:
Doug Leavitt wrote:
Hi, OpenSSL now has X509_V_FLAG_PARTIAL_CHAIN support in the code base as of 1.0.2a.
I would like to submit a patch to enable X509_V_FLAG_PARTIAL_CHAIN support in OpenLDAP libldap, assuming it exists in the version of OpenSSL being use to build OpenLDAP.
What's the use case? It appears that the feature has been in OpenSSL since around 2012, but I don't see much documentation or chatter about it. Why is it useful, and do GnuTLS and MozNSS already support a similar feature?
The use case is:
You have a certificate issued by a CA:
rootCA -> mysystem
You don't want to trust all of the certificates issued by that CA. You only want to trust that particular certificate.
OpenSSL by default ignores trust-list entries that are not for root CAs. Adding just the "mysystem" certificate has no effect. With this change, you can add the "mysystem" certificate and that will cause OpenSSL to accept this certificate, even though the trust list does not include the CA's root certificate.
A more complex case:
rootCA -> mycompanyCA -> mysystem
You don't want to trust all of the certificates issued by that CA. You only want to trust certificates issued by your company's CA. Again, OpenSSL by default will not let you trust an intermediate CA. With this change, you can add mycompanyCA's certificate and that will cause OpenSSL to accept certificates signed by your company CA.
The reason this is coming up now, is that the old Mozilla libldap/NSS combination supported this by default but the combination of OpenLDAP/OpenSSL currently does not. We first discovered the issue back in 2012 and realized that OpenSSL did not support partial chains. Working through our security team the project that discovered the issue convinced the OpenSSL upstream to add the X509_V_FLAG_PARTIAL_CHAIN support so that eventually we could find a way to incorporate that support back into OpenLDAP.
Additionally we have since uncovered some programs that depend on this Mozilla functionality and we would like to see it supported in the OpenLDAP/OpenSSL so those applications can finish moving off Mozilla libldap/NSS.
Moving forward to today it looks like OpenSSL has the support, disabled by default, and both GNUTLS and NSS have the support for partial chains enabled by default.
In GNUTLS, the support is here: https://gitlab.com/gnutls/gnutls/blob/master/lib/x509/verify.c#L868
In NSS the support is here: http://mxr.mozilla.org/security/source/security/nss/lib/certhigh/certvfy.c#5...
where intermediate certificates are processed (with the final decision at 557), and that leaf certificates are handled at http://mxr.mozilla.org/security/source/security/nss/lib/certhigh/certvfy.c#9...
In OpenSSL the support is disabled by default here: https://github.com/openssl/openssl/blob/master/crypto/x509/x509_vfy.c#L819
Our hope is to have OpenLDAP/OpenSSL be either on par with OpenLDAP/NSS and OpenLDAP/GNUTLS or at least have the option of be on par without having to maintain a downstream code fork.
The code change itself is simple. At a minimum it is as simple as adding:
#ifdef X509_V_FLAG_PARTIAL_CHAIN /* * Allow intermediate or leaf certificates in the trust list to * act as trust anchors. */ X509_STORE_set_flags(SSL_CTX_get_cert_store(ctx), X509_V_FLAG_PARTIAL_CHAIN); #endif
after:
http://www.openldap.org/devel/gitweb.cgi?p=openldap.git;a=blob;f=libraries/l...
From our investigation always adding the support does not seem to be harmful in any way and maintains compatibility with some existing software.
Hence the original question.
Thanks in advance for your consideration, Doug.
Before I submit any patch I would like to know that would be acceptable for integration.
Should support always be enabled if the version of OpenSSL has it e.g. ifdef on X509_V_FLAG_PARTIAL_CHAIN Should it be a config time option check and ifdef enable if found in e.g. like the ifdef on HAVE_OPENSSL_CRL Are there more requirements that is required in the patch, before it would be accepted such as ldap_set_option support?
Thanks in advance, Doug.
On Mon, 22 Jun 2015, Doug Leavitt wrote:
[...]
The code change itself is simple. At a minimum it is as simple as adding:
#ifdef X509_V_FLAG_PARTIAL_CHAIN
Perhaps with a doc patch too, since this would make OpenLDAP one of (apparently very) few OpenSSL-linked applications that honors partial chains.
OpenSSL by default ignores trust-list entries that are not for root CAs. Adding just the "mysystem" certificate has no effect. With this change, you can add the "mysystem" certificate and that will cause OpenSSL to accept this certificate, even though the trust list does not include the CA's root certificate.
The comment "even though the trust list does not include the CA's root certificate" seems a bit odd to me:
An argument that we take today's behavior (require rootCA; mysystemA[rootCA] or mysystemB[rootCA] are both OK) and make it more strict with "require rootCA AND mysystemA[rootCA]" intuitively sounds like an increase in security...if you have a client environment controlled enough to distribute ldap.example.com's material along with your CA store, go for it.
But the concept of "require ldap.example.com" while (optionally?) throwing out the existing rootCA (and presumably its associated CRL/OCSP/etc.) checking sounds like it could introduce risk. So is ldap.example.com truly an "add" to the chain, or is the rootCA not included (i.e. removed)?
Doug Leavitt wrote:
Sorry for the delay. I needed to do some due diligence before responding.
On 06/06/15 13:35, Howard Chu wrote:
Doug Leavitt wrote:
Hi, OpenSSL now has X509_V_FLAG_PARTIAL_CHAIN support in the code base as of 1.0.2a.
I would like to submit a patch to enable X509_V_FLAG_PARTIAL_CHAIN support in OpenLDAP libldap, assuming it exists in the version of OpenSSL being use to build OpenLDAP.
What's the use case? It appears that the feature has been in OpenSSL since around 2012, but I don't see much documentation or chatter about it. Why is it useful, and do GnuTLS and MozNSS already support a similar feature?
The use case is:
You have a certificate issued by a CA:
rootCA -> mysystem
You don't want to trust all of the certificates issued by that CA. You only want to trust that particular certificate.
"You" is too ambiguous here. Does the server carry a partial trust chain in its config, or does the client?
Pretty sure adding this feature will break compatibility with default OpenSSL installs. We already went thru this headache for GnuTLS.
http://www.openldap.org/its/index.cgi/Software%20Bugs?id=5991
Normal practice for servers is to trust only a single CA chain - the one that issued its own cert and all the client certs that it intends to honor.
Normal practice for clients is to trust multiple CA chains, assuming the client is used with multiple servers owned by disparate admin authorities. (Or, if only used in one administrative context, just a single chain.)
So far it looks to me like you want to support broken server configurations.
I recognize the desire to only trust the immediate superior CA of an end entity's own cert; that sort of makes sense. But certs can only be trusted if you also trust their issuer, you cannot make valid assertions about a cert if you don't follow the chain all the way back to a self-signer (which you also explicitly trust).
Also if you only want to trust the 1-level superior of a particular cert, you probably should not have been using commercial/3rd-party CAs in the first place. Clearly in the scenarios you've outlined, the fact that someone paid for a cert from a well-known commercial root CA is irrelevant here. They would have been better off creating their own CA cert and using it to create their end entity certs.
All of this smells of worst-practice to me.
OpenSSL by default ignores trust-list entries that are not for root CAs. Adding just the "mysystem" certificate has no effect. With this change, you can add the "mysystem" certificate and that will cause OpenSSL to accept this certificate, even though the trust list does not include the CA's root certificate.
A more complex case:
rootCA -> mycompanyCA -> mysystem
You don't want to trust all of the certificates issued by that CA. You only want to trust certificates issued by your company's CA. Again, OpenSSL by default will not let you trust an intermediate CA. With this change, you can add mycompanyCA's certificate and that will cause OpenSSL to accept certificates signed by your company CA.
The reason this is coming up now, is that the old Mozilla libldap/NSS combination supported this by default but the combination of OpenLDAP/OpenSSL currently does not. We first discovered the issue back in 2012 and realized that OpenSSL did not support partial chains. Working through our security team the project that discovered the issue convinced the OpenSSL upstream to add the X509_V_FLAG_PARTIAL_CHAIN support so that eventually we could find a way to incorporate that support back into OpenLDAP.
Additionally we have since uncovered some programs that depend on this Mozilla functionality and we would like to see it supported in the OpenLDAP/OpenSSL so those applications can finish moving off Mozilla libldap/NSS.
Moving forward to today it looks like OpenSSL has the support, disabled by default, and both GNUTLS and NSS have the support for partial chains enabled by default.
In GNUTLS, the support is here: https://gitlab.com/gnutls/gnutls/blob/master/lib/x509/verify.c#L868
In NSS the support is here: http://mxr.mozilla.org/security/source/security/nss/lib/certhigh/certvfy.c#5... where intermediate certificates are processed (with the final decision at 557), and that leaf certificates are handled at http://mxr.mozilla.org/security/source/security/nss/lib/certhigh/certvfy.c#9...
In OpenSSL the support is disabled by default here: https://github.com/openssl/openssl/blob/master/crypto/x509/x509_vfy.c#L819
Our hope is to have OpenLDAP/OpenSSL be either on par with OpenLDAP/NSS and OpenLDAP/GNUTLS or at least have the option of be on par without having to maintain a downstream code fork.
The code change itself is simple. At a minimum it is as simple as adding:
#ifdef X509_V_FLAG_PARTIAL_CHAIN /* * Allow intermediate or leaf certificates in the trust list to * act as trust anchors. */ X509_STORE_set_flags(SSL_CTX_get_cert_store(ctx), X509_V_FLAG_PARTIAL_CHAIN); #endif
after:
http://www.openldap.org/devel/gitweb.cgi?p=openldap.git;a=blob;f=libraries/l...
From our investigation always adding the support does not seem to be harmful in any way and maintains compatibility with some existing software.
Hence the original question.
Thanks in advance for your consideration, Doug.
Before I submit any patch I would like to know that would be acceptable for integration.
Should support always be enabled if the version of OpenSSL has it e.g. ifdef on X509_V_FLAG_PARTIAL_CHAIN Should it be a config time option check and ifdef enable if found in e.g. like the ifdef on HAVE_OPENSSL_CRL Are there more requirements that is required in the patch, before it would be accepted such as ldap_set_option support?
Thanks in advance, Doug.
Including Jordan Brown who is the person that has been replying previously. This is a merger of both previous responses from Aaron and Howard.
Doug.
On 06/23/15 09:37, Howard Chu wrote: On 06/23/15 08:56, Aaron Richton wrote:
On Mon, 22 Jun 2015, Doug Leavitt wrote:
[...]
The code change itself is simple. At a minimum it is as simple as adding:
#ifdef X509_V_FLAG_PARTIAL_CHAIN
Perhaps with a doc patch too, since this would make OpenLDAP one of (apparently very) few OpenSSL-linked applications that honors partial chains.
I think perhaps the most informative way to look at it is by way of comparison to browser behavior.
If you have a web site with a certificate like: rootCA -> servercert and your browser's trust list doesn't include rootCA, your browser will prompt you for a security exception. When you approve the security exception, it will add servercert to its trust list... not rootCA. After that, it will accept connections using servercert, but will not in general accept certificates signed by rootCA.
We want that same semantic in LDAP processing.
(Now, to be complete there would also be ways to accept cases like certificates that have the wrong server name in them. Browsers handle that; I'm not proposing a way for LDAP to handle those cases.)
OpenSSL by default ignores trust-list entries that are not for root CAs. Adding just the "mysystem" certificate has no effect. With this change, you can add the "mysystem" certificate and that will cause OpenSSL to accept this certificate, even though the trust list does not include the CA's root certificate.
The comment "even though the trust list does not include the CA's root certificate" seems a bit odd to me:
An argument that we take today's behavior (require rootCA; mysystemA[rootCA] or mysystemB[rootCA] are both OK) and make it more strict with "require rootCA AND mysystemA[rootCA]" intuitively sounds like an increase in security...if you have a client environment controlled enough to distribute ldap.example.com's material along with your CA store, go for it.
But the concept of "require ldap.example.com" while (optionally?) throwing out the existing rootCA (and presumably its associated CRL/OCSP/etc.) checking sounds like it could introduce risk. So is ldap.example.com truly an "add" to the chain, or is the rootCA not included (i.e. removed)?
This change is interesting in cases where rootCA is not included in the trust list. (It may have been removed, or may have never been included; that depends on what your original trust list looked like.)
Let's take a few examples.
Consider two certificates: a certificate issued to myserver by rootCA, and a certificate issued to a villain by rootCA.
Trust list: rootCA Today: accept all certificates rootCA->*, including both rootCA->myserver and rootCA->villain With this change: Same
Trust list: rootCA, rootCA->myserver Today: Accept all certificates rootCA->*. (myserver entry has no effect) With this change: Same
Trust list: rootCA->myserver (no rootCA certificate) Today: Accept nothing. With this change: Accept rootCA->myserver (but not rootCA->villain)
First, note that the behavior changes only when the rootCA->myserver certificate is included in the trust list. Today, that entry is completely meaningless in an OpenLDAP trust list. Second, note that today, if you want to be able to connect to myserver, you *must* accept all rootCA-signed certificates. You cannot choose to accept rootCA->myserver while rejecting rootCA->villain. With this change, you can choose to accept myserver while rejecting villain.
Similar discussions apply to intermediate CAs and are left as an exercise for the reader.
Pretty sure adding this feature will break compatibility with default OpenSSL installs. We already went thru this headache for GnuTLS.
http://www.openldap.org/its/index.cgi/Software%20Bugs?id=5991
This bug talks about what certificates one presents to the peer. That's not at all the question. The question is what certificates one (in particular the client, but could apply to the server too) *accepts*.
Normal practice for servers is to trust only a single CA chain - the one that issued its own cert and all the client certs that it intends to honor.
I'm talking about what certificates a client accepts, not what certificates a server accepts, but the same principles apply.
Suppose that Verisign issued your server's certificate, and will issue all of your clients' certificates. OK, but... you are also forced to accept certificates that Verisign issued to *me*. Did you really want to accept those?
Normal practice for clients is to trust multiple CA chains, assuming the client is used with multiple servers owned by disparate admin authorities. (Or, if only used in one administrative context, just a single chain.)
So far it looks to me like you want to support broken server configurations.
No... we want to trust only particular subtrees, not necessarily all certificates signed by the root.
I recognize the desire to only trust the immediate superior CA of an end entity's own cert; that sort of makes sense. But certs can only be trusted if you also trust their issuer, you cannot make valid assertions about a cert if you don't follow the chain all the way back to a self-signer (which you also explicitly trust).
Not at all true.
Once Verisign has issued a CA certificate to (say) Oracle, only Oracle can issue new certificates against that CA certificate. Even Verisign cannot issue certificates against that CA certificate, because Verisign does not have the private key for that certificate. Verisign could issue a new (bogus) certificate that says "Oracle", but it would not be the same certificate; if you are trusting that original certificate then certificates based on the new bogus certificate would not be trusted.
Also if you only want to trust the 1-level superior of a particular cert, you probably should not have been using commercial/3rd-party CAs in the first place. Clearly in the scenarios you've outlined, the fact that someone paid for a cert from a well-known commercial root CA is irrelevant here. They would have been better off creating their own CA cert and using it to create their end entity certs.
That assumes that the server administrators and all of the client share the same level of paranoia.
Less paranoid clients might trust the 3rd party root CA, while more paranoid clients might trust only the organization's CA (rootCA->orgCA), and still more paranoid clients might trust only the particular server (rootCA->orgCA->myserver). A client should be in charge of its own level of paranoia - it would be wrong for a paranoid client to force the server to force all of the other clients to be paranoid, just as it would be wrong for a less-paranoid client to force the server to force all of the other clients to be less paranoid.