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

crypto: add cert check to CNNIC Whitelist #1895

Closed
wants to merge 1 commit into from

Conversation

shigeki
Copy link
Contributor

@shigeki shigeki commented Jun 4, 2015

When client connect to the server with certification issued by either CNNNIC Root CA or CNNNIC EV Root CA, check hash of server certification in the list of CNNICHashWhitelist.inc. If it's not, CERT_REVOKED error returns.

See for details in
https://blog.mozilla.org/security/2015/04/02/distrusting-new-cnnic-certificates/

Fixes: #1871

@@ -13,6 +13,9 @@
#include "util.h"
#include "util-inl.h"
#include "v8.h"
// CNNIC Hash WhiteList is taken from
// https://hg.mozilla.org/mozilla-central/raw-file/98820360ab66/security/certverifier/CNNICHashWhitelist.inc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't make cpplint complain about the long lines?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woops, make test did not call make cpplint . I have to fix several styles.

@shigeki
Copy link
Contributor Author

shigeki commented Jun 4, 2015

I had typos. s/CNNNIC/CNNIC /

@mscdex mscdex added the crypto Issues and PRs related to the crypto subsystem. label Jun 4, 2015
"\x03\x55\x04\x03\x13\x0A\x43\x4E\x4E\x49\x43\x20\x52\x4F\x4F\x54";
const unsigned char* cnnic_p = CNNIC_ROOT_CA_SUBJECT_DATA;
static X509_NAME *cnnic_name = d2i_X509_NAME(NULL, &cnnic_p,
sizeof(CNNIC_ROOT_CA_SUBJECT_DATA));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style issues: star leans left and nullptr, not NULL. cnnic_p should be static.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I think you're including the zero byte in the length now? Is that correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Styles are fixed. The length of sizeof(CNNIC_ROOT_CA_SUBJECT_DATA) is not zero. Did I read your comment correctly?

@shigeki shigeki force-pushed the CNNIC_Whitelist branch 2 times, most recently from bef171f to 062ac11 Compare June 4, 2015 17:40
@shigeki
Copy link
Contributor Author

shigeki commented Jun 4, 2015

The commit was updated according comments except the case of root_cert is nulland the duplicated call of SSL_get_verify_result(). I will take care of them tomorrow.

@shigeki
Copy link
Contributor Author

shigeki commented Jun 4, 2015

The test of revoked case was made with something artificial change by removing one existing cert hash of www1.cnnic.cn from the whitelist as below. I'm not sure how to test this in general.

diff --git a/src/CNNICHashWhitelist.inc b/src/CNNICHashWhitelist.inc
index e3c6a61..652209e 100644
--- a/src/CNNICHashWhitelist.inc
+++ b/src/CNNICHashWhitelist.inc
@@ -636,10 +636,10 @@ static const struct WhitelistedCNNICHash WhitelistedCNNICHashes[] = {
     { 0x1B, 0xEC, 0xFE, 0x78, 0xCE, 0x5E, 0x77, 0xA9, 0x77, 0xBB, 0x5F, 0xE3, 0x49, 0x91, 0x06, 0xC6,
       0x4C, 0xF2, 0xB0, 0x76, 0x16, 0x59, 0x49, 0x04, 0x11, 0x17, 0xCD, 0x8A, 0xBC, 0xD9, 0x05, 0xD4 },
   },
-  {
-    { 0x1B, 0xF4, 0x8A, 0x83, 0x3C, 0xE4, 0x05, 0x64, 0x8C, 0xC0, 0xBD, 0xD3, 0xB5, 0xB8, 0xC1, 0x8E,
-      0xB5, 0x13, 0x15, 0x34, 0x29, 0x3A, 0xB2, 0x63, 0x44, 0xB5, 0x00, 0x76, 0x48, 0x11, 0x41, 0xED },
-  },
+//  {
+//    { 0x1B, 0xF4, 0x8A, 0x83, 0x3C, 0xE4, 0x05, 0x64, 0x8C, 0xC0, 0xBD, 0xD3, 0xB5, 0xB8, 0xC1, 0x8E,
+//      0xB5, 0x13, 0x15, 0x34, 0x29, 0x3A, 0xB2, 0x63, 0x44, 0xB5, 0x00, 0x76, 0x48, 0x11, 0x41, 0xED },
+//  },
   {
     { 0x1C, 0x04, 0x82, 0x0F, 0x7B, 0x4A, 0x2F, 0x1E, 0x38, 0x5D, 0xE1, 0xDE, 0x16, 0xB2, 0x22, 0x6E,
       0x88, 0x3D, 0x9C, 0x34, 0x66, 0x3E, 0x1B, 0x64, 0xE8, 0x5B, 0x98, 0x0E, 0xAF, 0xF0, 0xB9, 0xD3 },
var tls = require('tls');
var client = tls.connect(443, 'www1.cnnic.cn',{
},function() {
  client.end();
});
client.on('clientError', function(e) {
 console.log('clientError:', e);
});
client.on('error', function(e) {
 console.log('error:', e);
});
$ ./iojs ~/cnnic_test.js
error: { [Error: certificate revoked] code: 'CERT_REVOKED' }

"\x03\x55\x04\x03\x13\x0A\x43\x4E\x4E\x49\x43\x20\x52\x4F\x4F\x54";
const uint8_t* cnnic_p = CNNIC_ROOT_CA_SUBJECT_DATA;
static X509_NAME* cnnic_name =
d2i_X509_NAME(nullptr, &cnnic_p, sizeof(CNNIC_ROOT_CA_SUBJECT_DATA));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean with the zero byte is that sizeof("...") also includes the implicit '\0'. I speculate that's not the intent here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I missed it. It should be sizeof(CNNIC_ROOT_CA_SUBJECT_DATA)-1. Fortunately d2i API handles ASN.1 length properly so that the rest of unnecessary data are ignored. I will fix it.

@shigeki
Copy link
Contributor Author

shigeki commented Jun 10, 2015

@bnoordhuis Sorry for my late response.
I found a serious bug in my previous commit. The chain obtained from SSL_get_peer_cert_chain() only contains certs sent from a server so that root certs added with SSL_CTX_set_cert_store() are not included. The completed cert chain can be obtained via the store context in VerifyCallback.

In the X509_verify_cert() where the verify callback is invoked, the cert chain is stacked from leaf to root in order during examining the issuer but I don't have a confident that the root is always stacked at the last in the cert chain so that FindRoot is still remained and add the check the root_cert never to be null.

I also added the tests to confirm this whitelist check. Please take an another look.

"\x30\x32\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02\x43\x4E\x31\x0E\x30"
"\x0C\x06\x03\x55\x04\x0A\x13\x05\x43\x4E\x4E\x49\x43\x31\x13\x30\x11\x06"
"\x03\x55\x04\x03\x13\x0A\x43\x4E\x4E\x49\x43\x20\x52\x4F\x4F\x54";
const uint8_t* cnnic_p = CNNIC_ROOT_CA_SUBJECT_DATA;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be static.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

ARRAY_SIZE(WhitelistedCNNICHashes),
CNNIC_WHITELIST_HASH_LEN, compar);
if (result == nullptr) {
X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having this side effect here still doesn't sit right with me. I'd really prefer it if you (for example) changed it to return a ternary value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain your worry about the side effects more clearly?

In X509_STORE_CTX_get_error(3SSL) ,

X509_STORE_CTX_set_error() sets the error code of ctx to s. For example it might be used in a verification callback to set an error based on additional checks.

it says that X509_STORE_CTX_set_error can be used in a verify callback.
In this case when the callback returns 0, it immediately goes to finish X509_verify_cert() as https://github.com/openssl/openssl/blob/master/crypto/x509/x509_vfy.c#L1785-L1787
and put the context error to verify_result as
https://github.com/openssl/openssl/blob/OpenSSL_1_0_2-stable/ssl/ssl_cert.c#L759-L768. I could not find any side effects here.

If this has the side effect, how can I set an error code?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One solution is to make this function return an enum { ALLOWED, DISALLOWED, REVOKED } instead of an int. Then, in VerifyCallback(), call X509_STORE_CTX_set_error() iff the return value is REVOKED.

If you change the return value, you should rename the function, because it's no longer the boolean function that the IsFoo() name implies.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just update this PR. Does 5023980183dfce012dc9d000d8f5853a739e14c1 meet your comment above?

@bnoordhuis
Copy link
Member

LGTM if the CI is happy.

When client connect to the server with certification issued by either
CNNIC Root CA or CNNIC EV Root CA, check hash of server
certification in the list of CNNICHashWhitelist.inc. If it's not,
CERT_REVOKED error returns.

See for details in
https://blog.mozilla.org/security/2015/04/02/distrusting-new-cnnic-certificates/
shigeki pushed a commit that referenced this pull request Jun 16, 2015
When client connect to the server with certification issued by either
CNNIC Root CA or CNNIC EV Root CA, check hash of server
certification in the list of CNNICHashWhitelist.inc. If it's not,
CERT_REVOKED error returns.

See for details in
https://blog.mozilla.org/security/2015/04/02/distrusting-new-cnnic-certificates/

PR-URL: #1895
Reviewed-By: Ben Noordhuis <[email protected]>
@shigeki
Copy link
Contributor Author

shigeki commented Jun 16, 2015

@bnoordhuis Thanks for reviewing many times.

CI is https://jenkins-iojs.nodesource.com/job/iojs+any-pr+multi/19/.
Most of tests are green except one test failure of test-util-debug.js in armv7-wheezy which is not related this PR.

Landed in 3beb880.

@shigeki shigeki closed this Jun 16, 2015
@rvagg rvagg mentioned this pull request Jun 16, 2015
shigeki added a commit that referenced this pull request Feb 3, 2017
CNNIC Whitelist was updated with removing expired certificates.

Fixes: #1895
PR-URL: #9469
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Fedor Indutny <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
italoacasas pushed a commit that referenced this pull request Feb 4, 2017
CNNIC Whitelist was updated with removing expired certificates.

Fixes: #1895
PR-URL: #9469
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Fedor Indutny <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
italoacasas pushed a commit to italoacasas/node that referenced this pull request Feb 14, 2017
CNNIC Whitelist was updated with removing expired certificates.

Fixes: nodejs#1895
PR-URL: nodejs#9469
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Fedor Indutny <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
krydos pushed a commit to krydos/node that referenced this pull request Feb 25, 2017
CNNIC Whitelist was updated with removing expired certificates.

Fixes: nodejs#1895
PR-URL: nodejs#9469
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Fedor Indutny <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
jasnell pushed a commit that referenced this pull request Mar 7, 2017
CNNIC Whitelist was updated with removing expired certificates.

Fixes: #1895
PR-URL: #9469
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Fedor Indutny <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
jasnell pushed a commit that referenced this pull request Mar 7, 2017
CNNIC Whitelist was updated with removing expired certificates.

Fixes: #1895
PR-URL: #9469
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Fedor Indutny <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
MylesBorins pushed a commit that referenced this pull request Mar 9, 2017
CNNIC Whitelist was updated with removing expired certificates.

Fixes: #1895
PR-URL: #9469
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Fedor Indutny <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
MylesBorins pushed a commit that referenced this pull request Mar 9, 2017
CNNIC Whitelist was updated with removing expired certificates.

Fixes: #1895
PR-URL: #9469
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Fedor Indutny <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
kevinsawicki pushed a commit to electron/node that referenced this pull request May 16, 2017
CNNIC Whitelist was updated with removing expired certificates.

Fixes: nodejs/node#1895
PR-URL: nodejs/node#9469
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Fedor Indutny <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
root_cert = FindRoot(chain);
CHECK_NE(root_cert, nullptr);
root_name = X509_get_subject_name(root_cert);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shigeki Do you remember why you wrote it like this? Unless I misunderstand something a valid chain contains only one self-signed certificate and it's always the last one, isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bnoordhuis Honestly I did not remember it. But I guess I wrote it in order to care about the alt cert chain which has a cross cert in its chain as below. When the SHA-1 root was deleted in the root store, I was just afraid of the case when the last one in the cert chain stack was not SHA-2 root but its cross root to SHA-1.
alt_chain 001

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
crypto Issues and PRs related to the crypto subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants