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

Replace TLS-SNI-02 with TLS-ALPN-01. #112

Merged
merged 3 commits into from
Apr 16, 2018

Conversation

mdebski
Copy link
Contributor

@mdebski mdebski commented Apr 9, 2018

This pull request contains a simple TLS-ALPN-01 implementation, as described in draft [0]

[0] https://github.com/rolandshoemaker/acme-tls-alpn

va/va.go Outdated
InsecureSkipVerify: true,
})
func (va VAImpl) fetchCerts(hostPort string, config *tls.Config) ([]*x509.Certificate, *acme.ProblemDetails) {
config = config.Clone()

Choose a reason for hiding this comment

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

Given the config isn't being used anywhere else concurrently I think it's probably fine to not clone it and just work directly with the one passed in.

va/va.go Outdated
func (va VAImpl) fetchCerts(hostPort string, config *tls.Config) ([]*x509.Certificate, *acme.ProblemDetails) {
config = config.Clone()
config.InsecureSkipVerify = true
conn, err := tls.DialWithDialer(&net.Dialer{Timeout: time.Second * 5}, "tcp", hostPort, config)

Choose a reason for hiding this comment

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

I haven't tested this but from reading the crypto/tls docs for tls.ConnectionState I'm not sure this will enforce requiring that the negotiated protocol was one of those in config.NextProtos.

I think that conn.ConnectionState().NegotiatedProtocol still needs to be tested (and/or conn.ConnectionState().NegotiatedProtocolIsMutal) to be sure that the correct protocol is being used.

Choose a reason for hiding this comment

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

Perhaps fetchCerts should actually be fetchConnectionState and the callers can then use the tls.ConnectionState to for what they want (although I guess now we don't have TLS-SNI this will be the only caller ¯_(ツ)_/¯).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch!

Copy link
Contributor

@cpu cpu left a comment

Choose a reason for hiding this comment

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

Great work @mdebski ! Exciting to see an implementation of this challenge type :-) :-)

I left some feedback. It's mostly cosmetic/editorial. The overall PR looks great 👍

va/va.go Outdated
return acme.MalformedProblem(msg)
if !cs.NegotiatedProtocolIsMutual || cs.NegotiatedProtocol != acme.ACMETLS1Protocol {
result.Error = acme.UnauthorizedProblem(fmt.Sprintf(
"Cannot connect using %s for %s challenge",
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this error message should include the acronym "ALPN" somewhere, maybe: "Cannot mutually negotiate TLS ALPN %q for %s challenge" ?

va/va.go Outdated

if !validSanAName || !validSanBName {
// Verify SNI
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you expand on this comment? I think it would be worth highlighting that you're using task.Identifier here and the importance of this check with respect to acme-tls/1 and the required properties of the challenge type.

va/va.go Outdated

if !validSanAName || !validSanBName {
// Verify SNI
if len(leafCert.DNSNames) != 1 || !strings.EqualFold(leafCert.DNSNames[0], task.Identifier) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is strings.EqualFold too liberal for this purpose? I'm not 100% certain that case folding is required/wanted here. Can you expand on why you chose this instead of a direct comparison?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

va/va.go Outdated
if subtle.ConstantTimeCompare(h[:], ext.Value) == 1 {
return result
}
result.Error = acme.UnauthorizedProblem("Extension acmeValidationV1 value incorrect.")
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it might be clearer if this error string matched the format of the errText above, e.g: "Incorrect validation certificate for %s challenge. Missing expected acmeValidation1 extension 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.

In fact there is a serious bug - we should return an error if the extension is missing.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed! Good catch :-)

@cpu
Copy link
Contributor

cpu commented Apr 16, 2018

@rolandshoemaker Can you give this another 🔍 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants