dockerimg: clean up password matching code
Minor fixes:
* use crypto/rand.Text instead of hand-rolling one
* avoid converting the password during checking, that's not constant time
* don't use constant time comparisons against a constant string, there's no point
diff --git a/dockerimg/dockerimg.go b/dockerimg/dockerimg.go
index 039c84d..01a7392 100644
--- a/dockerimg/dockerimg.go
+++ b/dockerimg/dockerimg.go
@@ -323,17 +323,10 @@
return gs.srv.Serve(gs.gitLn)
}
-func mkRandToken() string {
- var b [16]byte
- if _, err := rand.Read(b[:]); err != nil {
- panic(err)
- }
- return hex.EncodeToString(b[:])
-}
-
func newGitServer(gitRoot string) (*gitServer, error) {
- ret := &gitServer{}
- ret.pass = mkRandToken()
+ ret := &gitServer{
+ pass: rand.Text(),
+ }
gitLn, err := net.Listen("tcp4", ":0")
if err != nil {
@@ -342,7 +335,7 @@
ret.gitLn = gitLn
srv := http.Server{
- Handler: &gitHTTP{gitRepoRoot: gitRoot, pass: ret.pass},
+ Handler: &gitHTTP{gitRepoRoot: gitRoot, pass: []byte(ret.pass)},
}
ret.srv = &srv
@@ -469,7 +462,7 @@
}
// Contact the container and configure it.
-func postContainerInitConfig(ctx context.Context, localAddr, commit, gitPort string, gitPass string) error {
+func postContainerInitConfig(ctx context.Context, localAddr, commit, gitPort, gitPass string) error {
localURL := "http://" + localAddr
initMsg, err := json.Marshal(map[string]string{
"commit": commit,
diff --git a/dockerimg/githttp.go b/dockerimg/githttp.go
index 6f0ec55..38a8b54 100644
--- a/dockerimg/githttp.go
+++ b/dockerimg/githttp.go
@@ -13,7 +13,7 @@
type gitHTTP struct {
gitRepoRoot string
- pass string
+ pass []byte
}
func (g *gitHTTP) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@@ -38,12 +38,8 @@
return
}
- // Perform constant-time comparison to prevent timing attacks
- usernameMatch := subtle.ConstantTimeCompare([]byte(username), []byte("sketch")) == 1
- passwordMatch := subtle.ConstantTimeCompare([]byte(password), []byte(g.pass)) == 1
-
// Check if credentials are valid
- if !usernameMatch || !passwordMatch {
+ if username != "sketch" || subtle.ConstantTimeCompare([]byte(password), g.pass) != 1 {
w.Header().Set("WWW-Authenticate", `Basic realm="Git Repository"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
slog.InfoContext(r.Context(), "githttp: denied (basic auth)", "remote addr", r.RemoteAddr)