Lego: http.Client panic with GetOCSP in v2.0.1

Created on 11 Jan 2019  路  4Comments  路  Source: go-acme/lego

Hi,

I've just been upgrading a project to use 2.0.1 and have made all the necessary API changes. Everything seems to have gone fine except for getting OCSP responses, the HTTPClient is panicing.

I've managed to reproduce it outside of my application with the following code:

package main

import (
    "crypto"
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/rand"
    "fmt"
    "log"

    "github.com/xenolf/lego/providers/dns/dnsmadeeasy"

    "github.com/xenolf/lego/certcrypto"
    "github.com/xenolf/lego/certificate"
    "github.com/xenolf/lego/challenge"
    "github.com/xenolf/lego/lego"
    "github.com/xenolf/lego/registration"
)

// You'll need a user or account type that implements acme.User
type MyUser struct {
    Email        string
    Registration *registration.Resource
    key          crypto.PrivateKey
}

func (u *MyUser) GetEmail() string {
    return u.Email
}
func (u MyUser) GetRegistration() *registration.Resource {
    return u.Registration
}
func (u *MyUser) GetPrivateKey() crypto.PrivateKey {
    return u.key
}

func main() {

    // Create a user. New accounts need an email and private key to start.
    privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    if err != nil {
        log.Fatal(err)
    }

    myUser := MyUser{
        Email: "[email protected]",
        key:   privateKey,
    }

    config := lego.NewConfig(&myUser)

    config.CADirURL = lego.LEDirectoryStaging
    config.Certificate.KeyType = certcrypto.RSA2048

    // A client facilitates communication with the CA server.
    client, err := lego.NewClient(config)
    if err != nil {
        log.Fatal(err)
    }

    providerConfig := dnsmadeeasy.NewDefaultConfig()
    providerConfig.BaseURL = "https://api.dnsmadeeasy.com/V2.0"
    providerConfig.APIKey = "xxx"
    providerConfig.APISecret = "yyy"
    provider, err := dnsmadeeasy.NewDNSProviderConfig(providerConfig)
    if err != nil {
        log.Fatal(err)
    }
    err = client.Challenge.SetDNS01Provider(provider)
    if err != nil {
        log.Fatal(err)
    }
    client.Challenge.Remove(challenge.HTTP01)
    client.Challenge.Remove(challenge.TLSALPN01)

    // New users will need to register
    reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
    if err != nil {
        log.Fatal(err)
    }
    myUser.Registration = reg

    request := certificate.ObtainRequest{
        Domains: []string{"www.example.com"},
        Bundle:  true,
    }
    certificates, err := client.Certificate.Obtain(request)
    if err != nil {
        log.Fatal(err)
    }

    b, r, err := client.Certificate.GetOCSP(certificates.Certificate)
    if err != nil {
        log.Fatal(err)
    }

    // Each certificate comes back with the cert bytes, the bytes of the client's
    // private key, and a certificate URL. SAVE THESE TO DISK.
    fmt.Printf("%#v\n", certificates)
    fmt.Printf("%#v\n", b)
    fmt.Printf("%#v\n", r)

    // ... all done.
}

The output for this is:

2019/01/11 12:41:10 [INFO] acme: Registering account for [email protected]
2019/01/11 12:41:11 [INFO] [www.example.com] acme: Obtaining bundled SAN certificate
2019/01/11 12:41:11 [INFO] [www.example.com] AuthURL: https://acme-staging-v02.api.letsencrypt.org/acme/authz/wBlS1SDwmM0ECnpSHIplrN4YLpVDFbWh9MwK4Ej1pN0
2019/01/11 12:41:11 [INFO] [www.example.com] acme: Could not find solver for: tls-alpn-01
2019/01/11 12:41:11 [INFO] [www.example.com] acme: Could not find solver for: http-01
2019/01/11 12:41:11 [INFO] [www.example.com] acme: use dns-01 solver
2019/01/11 12:41:11 [INFO] [www.example.com] acme: Preparing to solve DNS-01
2019/01/11 12:41:13 [INFO] [www.example.com] acme: Trying to solve DNS-01
2019/01/11 12:41:13 [INFO] [www.example.com] acme: Checking DNS record propagation using [1.1.1.1:53]
2019/01/11 12:41:13 [INFO] Wait for propagation [timeout: 1m0s, interval: 2s]
2019/01/11 12:41:13 [INFO] [www.example.com] acme: Waiting for DNS record propagation.
2019/01/11 12:41:16 [INFO] [www.example.com] The server validated our request
2019/01/11 12:41:16 [INFO] [www.example.com] acme: Cleaning DNS-01 challenge
2019/01/11 12:41:18 [INFO] [www.example.com] acme: Validations succeeded; requesting certificates
2019/01/11 12:41:20 [INFO] [www.example.com] Server responded with a certificate.
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x11d2a12]

goroutine 1 [running]:
net/http.(*Client).deadline(0x0, 0xc0002b8160, 0x30, 0xc000146ed0)
    /usr/local/Cellar/go/1.11.4/libexec/src/net/http/client.go:187 +0x22
net/http.(*Client).do(0x0, 0xc0001c8100, 0x0, 0x0, 0x0)
    /usr/local/Cellar/go/1.11.4/libexec/src/net/http/client.go:527 +0xab
net/http.(*Client).Do(0x0, 0xc0001c8100, 0xc, 0x13acb61, 0x18)
    /usr/local/Cellar/go/1.11.4/libexec/src/net/http/client.go:509 +0x35
net/http.(*Client).Post(0x0, 0xc0001d4180, 0x26, 0x13acb61, 0x18, 0x1400e60, 0xc000146e70, 0x0, 0x7, 0xc0002062a0)
    /usr/local/Cellar/go/1.11.4/libexec/src/net/http/client.go:769 +0xf8
github.com/moomerman/go-lib/vendor/github.com/xenolf/lego/certificate.(*Certifier).GetOCSP(0xc000146270, 0xc0001f6000, 0xde2, 0xe00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
    /Users/richard/workspace/go/src/github.com/moomerman/go-lib/vendor/github.com/xenolf/lego/certificate/certificates.go:448 +0x449
main.main()
    /Users/richard/workspace/go/src/github.com/moomerman/go-lib/autocert/test/main.go:93 +0x5b3
exit status 2

I put in a hack above https://github.com/xenolf/lego/blob/b91dbb66156befa3d04452fa8185e2325f70992f/certificate/certificates.go#L446 to re-intialise the c.core.HTTPClient and it works after that.

Note: The stacktrace says line 448 instead of 446 because I have two commented out lines in my version. I have tried it with a pristine version too, to rule out any local issues.

arelib bug

All 4 comments

@moomermanAs I understand it, you are creating a new HTTP client?

FYI these two lines are not needed with v2:

client.Challenge.Remove(challenge.HTTP01)
client.Challenge.Remove(challenge.TLSALPN01)

@ldez when I create a new http client above line 446 eg c.core.HTTPClient = &http.Client{} then it works. But out of the box with no modifications it panics. So there's something wrong with the HTTPClient, but I had a dig around and couldn't see what was wrong.

OK thanks, good to know you don't need to opt out of all the other challenges any more!

I found the root cause :tada:

Thank you for your detailed issue, I appreciate that very much :+1:

Can confirm the fix on your branch works for me 馃挴 thank you!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

onlyjob picture onlyjob  路  3Comments

datafoo picture datafoo  路  3Comments

AlbinOS picture AlbinOS  路  3Comments

mhf-ir picture mhf-ir  路  3Comments

benjamincudi picture benjamincudi  路  3Comments