forked from TrueCloudLab/certificates
commit
33b6d4c3c8
4 changed files with 50 additions and 2 deletions
|
@ -10,11 +10,13 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -114,6 +116,17 @@ func http01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWeb
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tlsAlert(err error) uint8 {
|
||||||
|
var opErr *net.OpError
|
||||||
|
if errors.As(err, &opErr) {
|
||||||
|
v := reflect.ValueOf(opErr.Err)
|
||||||
|
if v.Kind() == reflect.Uint8 {
|
||||||
|
return uint8(v.Uint())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, vo *ValidateChallengeOptions) error {
|
func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, vo *ValidateChallengeOptions) error {
|
||||||
config := &tls.Config{
|
config := &tls.Config{
|
||||||
NextProtos: []string{"acme-tls/1"},
|
NextProtos: []string{"acme-tls/1"},
|
||||||
|
@ -129,6 +142,14 @@ func tlsalpn01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSON
|
||||||
|
|
||||||
conn, err := vo.TLSDial("tcp", hostPort, config)
|
conn, err := vo.TLSDial("tcp", hostPort, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// With Go 1.17+ tls.Dial fails if there's no overlap between configured
|
||||||
|
// client and server protocols. When this happens the connection is
|
||||||
|
// closed with the error no_application_protocol(120) as required by
|
||||||
|
// RFC7301. See https://golang.org/doc/go1.17#ALPN
|
||||||
|
if tlsAlert(err) == 120 {
|
||||||
|
return storeError(ctx, db, ch, true, NewError(ErrorRejectedIdentifierType,
|
||||||
|
"cannot negotiate ALPN acme-tls/1 protocol for tls-alpn-01 challenge"))
|
||||||
|
}
|
||||||
return storeError(ctx, db, ch, false, WrapError(ErrorConnectionType, err,
|
return storeError(ctx, db, ch, false, WrapError(ErrorConnectionType, err,
|
||||||
"error doing TLS dial for %s", hostPort))
|
"error doing TLS dial for %s", hostPort))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1395,7 +1395,7 @@ func TestTLSALPN01Validate(t *testing.T) {
|
||||||
assert.Equals(t, updch.Type, ch.Type)
|
assert.Equals(t, updch.Type, ch.Type)
|
||||||
assert.Equals(t, updch.Value, ch.Value)
|
assert.Equals(t, updch.Value, ch.Value)
|
||||||
|
|
||||||
err := NewError(ErrorConnectionType, "error doing TLS dial for %v:443: tls: DialWithDialer timed out", ch.Value)
|
err := NewError(ErrorConnectionType, "error doing TLS dial for %v:443:", ch.Value)
|
||||||
|
|
||||||
assert.HasPrefix(t, updch.Error.Err.Error(), err.Err.Error())
|
assert.HasPrefix(t, updch.Error.Err.Error(), err.Err.Error())
|
||||||
assert.Equals(t, updch.Error.Type, err.Type)
|
assert.Equals(t, updch.Error.Type, err.Type)
|
||||||
|
|
|
@ -59,7 +59,9 @@ func Parse(rawuri string) (*URI, error) {
|
||||||
if u.Scheme == "" {
|
if u.Scheme == "" {
|
||||||
return nil, errors.Errorf("error parsing %s: scheme is missing", rawuri)
|
return nil, errors.Errorf("error parsing %s: scheme is missing", rawuri)
|
||||||
}
|
}
|
||||||
v, err := url.ParseQuery(u.Opaque)
|
// Starting with Go 1.17 url.ParseQuery returns an error using semicolon as
|
||||||
|
// separator.
|
||||||
|
v, err := url.ParseQuery(strings.ReplaceAll(u.Opaque, ";", "&"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "error parsing %s", rawuri)
|
return nil, errors.Wrapf(err, "error parsing %s", rawuri)
|
||||||
}
|
}
|
||||||
|
|
|
@ -274,3 +274,28 @@ func TestURI_Pin(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestURI_String(t *testing.T) {
|
||||||
|
mustParse := func(s string) *URI {
|
||||||
|
u, err := Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
uri *URI
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"ok new", New("yubikey", url.Values{"slot-id": []string{"9a"}, "foo": []string{"bar"}}), "yubikey:foo=bar;slot-id=9a"},
|
||||||
|
{"ok parse", mustParse("yubikey:slot-id=9a;foo=bar?bar=zar"), "yubikey:slot-id=9a;foo=bar?bar=zar"},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := tt.uri.String(); got != tt.want {
|
||||||
|
t.Errorf("URI.String() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue