Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

intermediate CA certificate can be not trusted. #36453

Closed
kadinwu opened this issue Dec 9, 2020 · 12 comments
Closed

intermediate CA certificate can be not trusted. #36453

kadinwu opened this issue Dec 9, 2020 · 12 comments
Labels
tls Issues and PRs related to the tls subsystem.

Comments

@kadinwu
Copy link

kadinwu commented Dec 9, 2020

  • Version: 12.18.2
  • Platform: Linux
  • Subsystem:

What steps will reproduce the bug?

  1. Only add server intermediate CA certificate to trusted certs.
  2. Trying to Connect to this server over tls, but got below error:

Error: unable to get issuer certificate
at TLSSocket.onConnectSecure (_tls_wrap.js:1496:34)
at TLSSocket.emit (events.js:315:20)
at TLSSocket._finishInit (_tls_wrap.js:938:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:696:12) {
code: 'UNABLE_TO_GET_ISSUER_CERT'
}

if add root CA certificate to trusted certs, then can connect to server.

How often does it reproduce? Is there a required condition?

What is the expected behavior?

Able to connect server over tls with server intermediate CA certificate trusted.
Or provider any option to support openssl partial_chain verify:
https://www.openssl.org/docs/manmaster/man1/openssl-verification-options.html

What do you see instead?

Additional information

@Trott Trott added the tls Issues and PRs related to the tls subsystem. label Dec 11, 2020
@Trott
Copy link
Member

Trott commented Dec 11, 2020

@nodejs/crypto

@kaizhu256
Copy link
Contributor

was bitten by this at work for couple months (during which disabled NODE_TLS_REJECT_UNAUTHORIZED=0 when i didn't know better).

eventually stumbled on solution trying to get curl to work as well. not sure whether this should be fixed or not, b/c curl has the same behavior (although both nodejs and curl need better documentation telling users they need to include the root-certifcate as well).

@mildsunrise
Copy link
Member

mildsunrise commented Dec 11, 2020

This is expected behaviour and not a Node.js decision, but an OpenSSL one.
OpenSSL expects trust anchors to be self-signed certificates and ignores intermediate ones.
It can be changed with the X509_V_FLAG_PARTIAL_CHAIN flag which was added in v1.1.0:

The X509_V_FLAG_PARTIAL_CHAIN flag causes non-self-signed certificates in the trust store to be treated as trust anchors, in the same way as self-signed root CA certificates. This makes it possible to trust self-issued certificates as well as certificates issued by an intermediate CA without having to trust their ancestor root CA. With OpenSSL 1.1.0 and later and X509_V_FLAG_PARTIAL_CHAIN set, chain construction stops as soon as the first certificate contained in the trust store is added to the chain, whether that certificate is a self-signed "root" certificate or a not self-signed "intermediate" or self-issued certificate. Thus, when an intermediate certificate is found in the trust store, the verified chain passed to callbacks may be shorter than it otherwise would be without the X509_V_FLAG_PARTIAL_CHAIN flag.

Curl decided to enable it by default a year ago, see curl/curl#4655 for discussion. For curl it makes more sense because it's more agnostic of the TLS implementation, and the other backends do support intermediate certs as trust anchors.

Node.js is tied to OpenSSL, and changing a setting like this would have security implications, it would have to be semver-major at least IMHO.

@kadinwu
Copy link
Author

kadinwu commented Dec 12, 2020

This is expected behaviour and not a Node.js decision, but an OpenSSL one.
OpenSSL expects trust anchors to be self-signed certificates and ignores intermediate ones.
It can be changed with the X509_V_FLAG_PARTIAL_CHAIN flag which was added in v1.1.0:

The X509_V_FLAG_PARTIAL_CHAIN flag causes non-self-signed certificates in the trust store to be treated as trust anchors, in the same way as self-signed root CA certificates. This makes it possible to trust self-issued certificates as well as certificates issued by an intermediate CA without having to trust their ancestor root CA. With OpenSSL 1.1.0 and later and X509_V_FLAG_PARTIAL_CHAIN set, chain construction stops as soon as the first certificate contained in the trust store is added to the chain, whether that certificate is a self-signed "root" certificate or a not self-signed "intermediate" or self-issued certificate. Thus, when an intermediate certificate is found in the trust store, the verified chain passed to callbacks may be shorter than it otherwise would be without the X509_V_FLAG_PARTIAL_CHAIN flag.

Curl decided to enable it by default a year ago, see curl/curl#4655 for discussion. For curl it makes more sense because it's more agnostic of the TLS implementation, and the other backends do support intermediate certs as trust anchors.

Node.js is tied to OpenSSL, and changing a setting like this would have security implications, it would have to be semver-major at least IMHO.

Thanks for the quick reply.
By Default, X509_V_FLAG_PARTIAL_CHAIN flag is disabled is make sense for me. It is more secure, but it doesn't mean enable it is not secure. I just want nodejs can expose a way to set this flag.
just to confirm, in latest nodejs, there is no way to configure X509_V_FLAG_PARTIAL_CHAIN flag and pass to openssl, right?
If so, do you have any plan to support it?

@zipou
Copy link

zipou commented Jun 15, 2023

Hello, I just bumped into this issue when I was trying to discover why my nodejs apps throw "UNABLE_TO_GET_ISSUER_CERT" with my certificate design (CA / Client Cert / Server Cert)

So to just ask agin the question of @kadinwu , will be any way of passing this the X509_V_FLAG_PARTIAL_CHAIN flag in a future release of nodejs ?

I did not find anything mentionning that in the documentation, but may be I missed it ?

Regards,

@mildsunrise
Copy link
Member

AFAIK we have never exposed options for certificate verification (X509_VERIFY_PARAM) such as the flags in this case.
a priori I see it feasible and simple enough to do, but I haven't been very active at the project and I'm worried if it hasn't been done yet there's a reason for it. I couldn't find issues or PRs talking about it, so maybe there's just not been enough demand.

@bnoordhuis
Copy link
Member

One reason is that it's practically guaranteed people are going to misuse it: google error message, copy first stack overflow answer, move on, herp derp, not understanding or caring about the security implications.

I mean, look at how often people abuse NODE_TLS_REJECT_UNAUTHORIZED to get around certificate errors. Adding it as an escape hatch when I turned on TLS verify-by-default is probably the biggest regret I have over the last 12-13 years.

@mildsunrise
Copy link
Member

understandable, but by that rule we also shouldn't have exposed SSL options, protocol version, global keylog, etc. I'm not sure to what extent it's good to prevent perfectly legitimate use cases to protect users from themselves... maybe a middle ground here would be to only expose flag constants that have reduced potential for misuse, such as CRL_CHECK*, X509_STRICT, CHECK_SS_SIGNATURE, PARTIAL_CHAIN, but users would probably hardcode other constants anyway.

@galaxyfeeder
Copy link

+1 to expose an option that enables setting this flag for allowing trusting intermediate CAs

@schaefec
Copy link

This is very much needed in our product as well. We're making use of different TLS implementations. Looks like in all our cases we can configure a non-root certificate as a trust anchor (e.g. JSSE from Java allows this, the crypto/tls package in golang seems to support this, etc.) but nodejs doesn't.

+1 for exposing a parameter or a way to configure nodejs (snd with that openssl underneath) to accept non-root certificates as trust anchors.

@galaxyfeeder
Copy link

I need to have deeper look into it and try some things, however, based on openssl documentation, a trust anchor can be configured in multiple ways and setting the certificates as TRUSTED CERTIFICATE in the PEM format should allow adding an intermediate CA and validating against it, being present in the trust store. All without the need of setting the X509_V_FLAG_PARTIAL_CHAIN flag.

Based on the following parts of the linked openssl docs:

From the OpenSSL perspective, a trust anchor is a certificate that should be augmented with an explicit designation for which uses of a target certificate the certificate may serve as a trust anchor. In PEM encoding, this is indicated by the TRUSTED CERTIFICATE string. Such a designation provides a set of positive trust attributes explicitly stating trust for the listed purposes and/or a set of negative trust attributes explicitly rejecting the use for the listed purposes. The purposes are encoded using the values defined for the extended key usages (EKUs) that may be given in X.509 extensions of end-entity certificates. See also the "Extended Key Usage" section below.

A certificate, which may be CA certificate or an end-entity certificate, is considered a trust anchor for the given use if and only if all the following conditions hold:

  • It is an an element of the trust store.
  • It does not have a negative trust attribute rejecting the given use.
  • It has a positive trust attribute accepting the given use or (by default) one of the following compatibility conditions apply: It is self-signed or the -partial_chain option is given (which corresponds to the X509_V_FLAG_PARTIAL_CHAIN flag being set).

@schaefec
Copy link

Thanks a lot for the hint @galaxyfeeder!

What I did to test that I can add an intermediate certificate as a trust is the following:

  1. Add trust attribute to my intermediate certificate using openssl x509

openssl x509 -in <path>/intermediate.crt -addtrust serverAuth -out <path>/intermediate-trusted.crt

  1. Starting a simple http server using openssl s_server which returns only the end entity certificate and the intermeidate certificate in the TLS handshake

openssl s_server -no-CAfile -no-CApath -no-CAstore -CAfile intermediate.crt -cert cert.crt -key key.key -www

  1. Executing the following code to check if my intermediate certificate is treated as a trust anchor in node now:
const https = require('node:https');
var fs = require('fs');

var https_options = {
  ca: [
          fs.readFileSync('<path>/intermediate-trusted.crt')
       ]
};

https.get('https://<my hostname>:4433/', https_options , (res) => {
  console.log('statusCode:', res.statusCode);
  console.log('headers:', res.headers);

  res.on('data', (d) => {
    process.stdout.write(d);
  });

}).on('error', (e) => {
  console.error(e);
});

This works well. However, I was not able to add my end entity certificate as a trust anchor by setting the trust attributes similar as I did for the intermediate certificate although this should work according to openssl's documentation

A certificate, which may be CA certificate or an end-entity certificate, is considered a trust anchor for the given use if and only if all the following conditions hold:

It is an an element of the trust store.
It does not have a negative trust attribute rejecting the given use.
It has a positive trust attribute accepting the given use or (by default) one of the following compatibility conditions apply: It is self-signed or the -partial_chain option is given (which corresponds to the X509_V_FLAG_PARTIAL_CHAIN flag being set).

It's good to be able to establish trust to an intermediate certificate (which is what is mentioned in the title of this issue), however, I would also be interested into establishing a trust to an end-entity in some situations. If anyone succeeeds to do this, please let us know.

addaleax added a commit to addaleax/node that referenced this issue Sep 5, 2024
This commit exposes the `X509_V_FLAG_PARTIAL_CHAIN` OpenSSL flag to users.
This is behavior that has been requested repeatedly in the Github issues,
and allows aligning behavior with other TLS libraries and commonly used
applications (e.g. `curl`).

Fixes: nodejs#36453
addaleax added a commit to addaleax/node that referenced this issue Sep 5, 2024
This commit exposes the `X509_V_FLAG_PARTIAL_CHAIN` OpenSSL flag to users.
This is behavior that has been requested repeatedly in the Github issues,
and allows aligning behavior with other TLS libraries and commonly used
applications (e.g. `curl`).

As a drive-by, simplify the `SecureContext` source by deduplicating
call sites at which a new custom certificate store was created for the
`secureContext` in question.

Fixes: nodejs#36453
addaleax added a commit to addaleax/node that referenced this issue Sep 5, 2024
This commit exposes the `X509_V_FLAG_PARTIAL_CHAIN` OpenSSL flag to
users. This is behavior that has been requested repeatedly in the
Github issues, and allows aligning behavior with other TLS libraries
and commonly used applications (e.g. `curl`).

As a drive-by, simplify the `SecureContext` source by deduplicating
call sites at which a new custom certificate store was created for the
`secureContext` in question.

Fixes: nodejs#36453
aduh95 pushed a commit that referenced this issue Sep 12, 2024
This commit exposes the `X509_V_FLAG_PARTIAL_CHAIN` OpenSSL flag to
users. This is behavior that has been requested repeatedly in the
Github issues, and allows aligning behavior with other TLS libraries
and commonly used applications (e.g. `curl`).

As a drive-by, simplify the `SecureContext` source by deduplicating
call sites at which a new custom certificate store was created for the
`secureContext` in question.

Fixes: #36453
PR-URL: #54790
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
targos pushed a commit that referenced this issue Sep 22, 2024
This commit exposes the `X509_V_FLAG_PARTIAL_CHAIN` OpenSSL flag to
users. This is behavior that has been requested repeatedly in the
Github issues, and allows aligning behavior with other TLS libraries
and commonly used applications (e.g. `curl`).

As a drive-by, simplify the `SecureContext` source by deduplicating
call sites at which a new custom certificate store was created for the
`secureContext` in question.

Fixes: #36453
PR-URL: #54790
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
targos pushed a commit that referenced this issue Sep 26, 2024
This commit exposes the `X509_V_FLAG_PARTIAL_CHAIN` OpenSSL flag to
users. This is behavior that has been requested repeatedly in the
Github issues, and allows aligning behavior with other TLS libraries
and commonly used applications (e.g. `curl`).

As a drive-by, simplify the `SecureContext` source by deduplicating
call sites at which a new custom certificate store was created for the
`secureContext` in question.

Fixes: #36453
PR-URL: #54790
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
targos pushed a commit that referenced this issue Oct 2, 2024
This commit exposes the `X509_V_FLAG_PARTIAL_CHAIN` OpenSSL flag to
users. This is behavior that has been requested repeatedly in the
Github issues, and allows aligning behavior with other TLS libraries
and commonly used applications (e.g. `curl`).

As a drive-by, simplify the `SecureContext` source by deduplicating
call sites at which a new custom certificate store was created for the
`secureContext` in question.

Fixes: #36453
PR-URL: #54790
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
targos pushed a commit that referenced this issue Oct 2, 2024
This commit exposes the `X509_V_FLAG_PARTIAL_CHAIN` OpenSSL flag to
users. This is behavior that has been requested repeatedly in the
Github issues, and allows aligning behavior with other TLS libraries
and commonly used applications (e.g. `curl`).

As a drive-by, simplify the `SecureContext` source by deduplicating
call sites at which a new custom certificate store was created for the
`secureContext` in question.

Fixes: #36453
PR-URL: #54790
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
louwers pushed a commit to louwers/node that referenced this issue Nov 2, 2024
This commit exposes the `X509_V_FLAG_PARTIAL_CHAIN` OpenSSL flag to
users. This is behavior that has been requested repeatedly in the
Github issues, and allows aligning behavior with other TLS libraries
and commonly used applications (e.g. `curl`).

As a drive-by, simplify the `SecureContext` source by deduplicating
call sites at which a new custom certificate store was created for the
`secureContext` in question.

Fixes: nodejs#36453
PR-URL: nodejs#54790
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
tpoisseau pushed a commit to tpoisseau/node that referenced this issue Nov 21, 2024
This commit exposes the `X509_V_FLAG_PARTIAL_CHAIN` OpenSSL flag to
users. This is behavior that has been requested repeatedly in the
Github issues, and allows aligning behavior with other TLS libraries
and commonly used applications (e.g. `curl`).

As a drive-by, simplify the `SecureContext` source by deduplicating
call sites at which a new custom certificate store was created for the
`secureContext` in question.

Fixes: nodejs#36453
PR-URL: nodejs#54790
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tls Issues and PRs related to the tls subsystem.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants