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

src: refactor GetPeerCertificate #17372

Closed
wants to merge 1 commit into from

Conversation

danbev
Copy link
Contributor

@danbev danbev commented Nov 28, 2017

These commits split the GetPeerCertificate function into smaller function as described in the TODO comment:

// TODO(indutny): Split it into multiple smaller functions

I've mostly left the code as it was and want to trigger CI to pick up any issues.

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • commit message follows commit guidelines
Affected core subsystem(s)

src

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. crypto Issues and PRs related to the crypto subsystem. labels Nov 28, 2017
@danbev
Copy link
Contributor Author

danbev commented Nov 28, 2017

// Put issuer inside the object
static void AddIssuer(X509** cert,
const STACK_OF(X509)* const peer_certs,
Local<Object>* const info,
Copy link
Member

Choose a reason for hiding this comment

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

Why is this a pointer?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason was so that code in GetPeerCertificate depends on the value being pointed to by info be updated. But I realise that info does not have to be a pointer and we only need update it's pointer for this to work. Not sure if that made sense but I'll add a commit and hopefully this will become clearer. Thanks for pointing this out.

continue;

Local<Object> ca_info = X509ToObject(env, ca);
(*info)->Set(env->issuercert_string(), ca_info);
Copy link
Member

Choose a reason for hiding this comment

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

Feel free to switch this over to the non-deprecated overload of Set() if you like :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah good point, I'll update to use the function taking a context. Thanks

Copy link
Member

Choose a reason for hiding this comment

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

Related: it would be more efficient to move these two lines out of the loop. Likewise in GetLastIssuedCert().


static X509* GetLastIssuedCert(X509** cert,
const SSL* const ssl,
Local<Object>* const info,
Copy link
Member

Choose a reason for hiding this comment

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

Similar question here

// Put issuer inside the object
static void AddIssuer(X509** cert,
const STACK_OF(X509)* const peer_certs,
Local<Object>* const info,
Copy link
Member

Choose a reason for hiding this comment

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

You don't have to pass a pointer since you don't replace the Object, just add properties to 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.

Thanks, I've changed this now (locally).

@@ -1974,7 +1974,78 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) {
}


// TODO(indutny): Split it into multiple smaller functions
// Put issuer inside the object
Copy link
Member

Choose a reason for hiding this comment

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

Not a hugely useful comment. If you call the function AddIssuerToObject(), it's self-documenting.

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 like that, I'll rename the function.

(*info)->Set(env->issuercert_string(), ca_info);
*info = ca_info;

// NOTE: Intentionally freeing cert that is not used anymore
Copy link
Member

Choose a reason for hiding this comment

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

Since you're here, can you punctuate the comments?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Absolutely.

Local<Object>* const info,
Environment* const env) {
*cert = sk_X509_delete(peer_certs, 0);
while (sk_X509_num(peer_certs) > 0) {
Copy link
Member

Choose a reason for hiding this comment

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

Unrelated observation: I think this could just be for (;;) { - the same check is effectively done at the end of the loop when i == 0.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice, I'll take a closer look at this.

return false;
}
return true;
}
Copy link
Member

Choose a reason for hiding this comment

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

It might be nicer (certainly more Obviously Correct) to move the sk_X509_pop_free() on error into this function.

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'll take a look and fix this. Thanks

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 pushed a few commit but I've not addressed this yet. Will revisit this next week. I was wondering if you meant that I add sk_X509_pop_free() to this function in addition to the one in GetPeerCertificate which I think is needed as peer_cert is used after this function?

continue;

Local<Object> ca_info = X509ToObject(env, ca);
(*info)->Set(env->issuercert_string(), ca_info);
Copy link
Member

Choose a reason for hiding this comment

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

Related: it would be more efficient to move these two lines out of the loop. Likewise in GetLastIssuedCert().

if (!sk_X509_push(peer_certs, cert))
goto done;
if (!CloneSSLCerts(&cert, &peer_certs, ssl_certs)) {
goto done;
}
Copy link
Member

Choose a reason for hiding this comment

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

Can you drop the braces for consistency with the surrounding code?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I'll remove them

// TODO(indutny): Split it into multiple smaller functions
// Put issuer inside the object
static void AddIssuer(X509** cert,
const STACK_OF(X509)* const peer_certs,
Copy link
Member

Choose a reason for hiding this comment

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

peer_certs can't be const because it's modified inside the function.

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've changed that now.

@danbev danbev force-pushed the refactor_getpeercertificate branch from 7042685 to 476e116 Compare December 2, 2017 13:50
@danbev
Copy link
Contributor Author

danbev commented Dec 2, 2017

Related: it would be more efficient to move these two lines out of the loop. Likewise in > GetLastIssuedCert().

I've pushed a few commit but I've not addressed this yet. Will revisit this next week.

@danbev
Copy link
Contributor Author

danbev commented Dec 2, 2017

@danbev
Copy link
Contributor Author

danbev commented Dec 5, 2017

Local<Object> ca_info = X509ToObject(env, ca);
info->Set(env->issuercert_string(), ca_info);

Related: it would be more efficient to move these two lines out of the loop. Likewise in GetLastIssuedCert().

@bnoordhuis I've been looking into moving these lines out of the loop and ran into an issue. My understanding is that this code is creating a link/chain of #issuerCertificate from the object instance. Something like:

object -> #issuerCertificate -> ca_info -> #issuerCertificate -> ca_info

Without setting the #issuerCertificate in the loop a certificates would be skipped. Sorry if I'm missing something here, I've been looking at this for a while now and think I need some help.

@danbev
Copy link
Contributor Author

danbev commented Dec 5, 2017

Local<Object> ca_info = X509ToObject(env, ca);
info->Set(env->issuercert_string(), ca_info);
info = ca_info;
// Clone `ssl_certs`, because we are going to destruct it.
Copy link
Member

Choose a reason for hiding this comment

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

nit: destructdestroy? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perhaps this comment could be remove now. Just reading it again perhaps the method signature should be changed to:

if (CloneSSLCerts(&cert, ssl_certs, &peer_certs)) {

What do you think, would that be clear without the comment?

Copy link
Member

Choose a reason for hiding this comment

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

Yep, self-explanatory now.

continue;

Local<Object> ca_info = X509ToObject(env, ca);
object->Set(context, env->issuercert_string(), ca_info).ToChecked();
Copy link
Member

Choose a reason for hiding this comment

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

I think we've settled on .FromJust() (232 vs 44 hits for .ToChecked() at the time of writing.)

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'll correct these.

break;

Local<Object> ca_info = X509ToObject(env, ca);
issuer_chain->Set(context, env->issuercert_string(), ca_info).ToChecked();
Copy link
Member

Choose a reason for hiding this comment

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

Likewise.

// NOTE: Intentionally freeing cert that is not used anymore
X509_free(cert);
issuer_chain = AddIssuerToObject(result, &cert, peer_certs, env);
issuer_chain = GetLastIssuedCert(&cert, w->ssl_, issuer_chain, env);
Copy link
Member

Choose a reason for hiding this comment

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

You're right you can't factor out the .Set() calls because they build up a linked list but that arguably makes AddIssuerToObject() a bit of a misnomer.

Can you try to pass arguments in the same order to both functions?

Copy link
Contributor Author

@danbev danbev Dec 6, 2017

Choose a reason for hiding this comment

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

Perhaps a better name would be AddIssuerChainToObject?

Can you try to pass arguments in the same order to both functions?

Yep, I'll update the order. Thanks

Local<Object> ca_info = X509ToObject(env, ca);
info->Set(env->issuercert_string(), ca_info);
info = ca_info;
// Clone `ssl_certs`, because we are going to destruct it.
Copy link
Member

Choose a reason for hiding this comment

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

Yep, self-explanatory now.

@addaleax
Copy link
Member

CI: https://ci.nodejs.org/job/node-test-commit/14720/

@danbev
Copy link
Contributor Author

danbev commented Dec 12, 2017

test/windows-fanned failure looks unrelated

console output:

ERROR: Error fetching remote repo 'jenkins_tmp'
hudson.plugins.git.GitException: Failed to fetch from [email protected]:janeasystems/node_binary_tmp.git
	at hudson.plugins.git.GitSCM.fetchFrom(GitSCM.java:825)
	at hudson.plugins.git.GitSCM.retrieveChanges(GitSCM.java:1092)
	at hudson.plugins.git.GitSCM.checkout(GitSCM.java:1123)
	at hudson.scm.SCM.checkout(SCM.java:495)
	at hudson.model.AbstractProject.checkout(AbstractProject.java:1202)
	at hudson.model.AbstractBuild$AbstractBuildExecution.defaultCheckout(AbstractBuild.java:574)
	at jenkins.scm.SCMCheckoutStrategy.checkout(SCMCheckoutStrategy.java:86)
	at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:499)
	at hudson.model.Run.execute(Run.java:1724)
	at hudson.matrix.MatrixRun.run(MatrixRun.java:146)
	at hudson.model.ResourceController.execute(ResourceController.java:97)
	at hudson.model.Executor.run(Executor.java:421)
Caused by: hudson.plugins.git.GitException: Command "git reset --hard" returned status code 128:
stdout: 
stderr: fatal: Unable to create 'c:/workspace/node-test-binary-windows/.git/index.lock': File exists.

@danbev
Copy link
Contributor Author

danbev commented Dec 12, 2017

@bnoordhuis When you get a chance would you be able to take a look at the lastest updates and see what you think?

Copy link
Member

@bnoordhuis bnoordhuis left a comment

Choose a reason for hiding this comment

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

LGTM with two requests.

}
}
if (!result) {
sk_X509_pop_free(*peer_certs, X509_free);
Copy link
Member

Choose a reason for hiding this comment

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

In a similar vein, can you add *peer_certs = nullptr;?

}
sk_X509_pop_free(peer_certs, X509_free);
return object;
}
Copy link
Member

Choose a reason for hiding this comment

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

Just a suggestion but it would be better if this function didn't mutate and invalidate peer_certs.

Failing that, perhaps pass peer_certs as an indirect pointer and set *peer_certs = nullptr; 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.

Sounds good, I'll take a look. Thanks

Copy link
Member

@jasnell jasnell left a comment

Choose a reason for hiding this comment

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

LGTM with @bnoordhuis suggestion

@maclover7 maclover7 added the wip Issues and PRs that are still a work in progress. label Dec 19, 2017
@BridgeAR
Copy link
Member

@danbev would you be so kind and please update this accordingly to the suggestions? :-)

@danbev
Copy link
Contributor Author

danbev commented Jan 20, 2018

@BridgeAR I hope to revisit this next week (though I've got a sick kid here and I might not be working at all next week by the looks of it)

@BridgeAR
Copy link
Member

Ping @danbev

1 similar comment
@BridgeAR
Copy link
Member

BridgeAR commented Feb 7, 2018

Ping @danbev

@danbev
Copy link
Contributor Author

danbev commented Feb 7, 2018

@BridgeAR I've just not had time to revisit this yet but intend to.

@BridgeAR
Copy link
Member

BridgeAR commented Mar 2, 2018

@BridgeAR BridgeAR added author ready PRs that have at least one approval, no pending requests for changes, and a CI started. and removed wip Issues and PRs that are still a work in progress. labels Mar 2, 2018
@BridgeAR
Copy link
Member

BridgeAR commented Mar 2, 2018

@bnoordhuis @jasnell @addaleax PTAL

@danbev danbev added the wip Issues and PRs that are still a work in progress. label Mar 2, 2018
@danbev
Copy link
Contributor Author

danbev commented Mar 2, 2018

I'm setting this to in-progress as I've not hade time to look closer at @bnoordhuis latest suggestions. I hope to make some time for this soon.

bnoordhuis pushed a commit to bnoordhuis/io.js that referenced this pull request Mar 2, 2018
PR-URL: nodejs#17372
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: James M Snell <[email protected]>
@bnoordhuis
Copy link
Member

#19087 - had 30 minutes to kill. :-)

@danbev
Copy link
Contributor Author

danbev commented Mar 3, 2018

Closing in favour of #19087

@danbev danbev closed this Mar 3, 2018
@danbev danbev deleted the refactor_getpeercertificate branch March 6, 2018 11:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
author ready PRs that have at least one approval, no pending requests for changes, and a CI started. c++ Issues and PRs that require attention from people who are familiar with C++. crypto Issues and PRs related to the crypto subsystem. wip Issues and PRs that are still a work in progress.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants