Skip to content

Commit 6446285

Browse files
FiloSottilegopherbot
authored andcommitted
crypto/rand: move OS interaction to crypto/internal/sysrand
We're going to use that package as the passive entropy source for the FIPS module, and we need to import it from a package that will be imported by crypto/rand. Since there is no overridable Reader now, introduced a mechanism to test the otherwise impossible failure of the OS entropy source. For #69536 Change-Id: I558687ed1ec896dba05b99b937970bb809de3fe7 Reviewed-on: https://go-review.googlesource.com/c/go/+/624976 Reviewed-by: Daniel McCarney <daniel@binaryparadox.net> Reviewed-by: Roland Shoemaker <roland@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Filippo Valsorda <filippo@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
1 parent f705cf8 commit 6446285

File tree

17 files changed

+245
-84
lines changed

17 files changed

+245
-84
lines changed
File renamed without changes.
File renamed without changes.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2010 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package rand provides cryptographically secure random bytes from the
6+
// operating system.
7+
package sysrand
8+
9+
import (
10+
"os"
11+
"sync"
12+
"sync/atomic"
13+
"time"
14+
_ "unsafe"
15+
)
16+
17+
var firstUse atomic.Bool
18+
19+
func warnBlocked() {
20+
println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
21+
}
22+
23+
// fatal is [runtime.fatal], pushed via linkname.
24+
//
25+
//go:linkname fatal
26+
func fatal(string)
27+
28+
var testingOnlyFailRead bool
29+
30+
// Read fills b with cryptographically secure random bytes from the operating
31+
// system. It always fills b entirely and crashes the program irrecoverably if
32+
// an error is encountered. The operating system APIs are documented to never
33+
// return an error on all but legacy Linux systems.
34+
func Read(b []byte) {
35+
if firstUse.CompareAndSwap(false, true) {
36+
// First use of randomness. Start timer to warn about
37+
// being blocked on entropy not being available.
38+
t := time.AfterFunc(time.Minute, warnBlocked)
39+
defer t.Stop()
40+
}
41+
if err := read(b); err != nil || testingOnlyFailRead {
42+
var errStr string
43+
if !testingOnlyFailRead {
44+
errStr = err.Error()
45+
} else {
46+
errStr = "testing simulated failure"
47+
}
48+
fatal("crypto/rand: failed to read random data (see https://go.dev/issue/66821): " + errStr)
49+
panic("unreachable") // To be sure.
50+
}
51+
}
52+
53+
// The urandom fallback is only used on Linux kernels before 3.17 and on AIX.
54+
55+
var urandomOnce sync.Once
56+
var urandomFile *os.File
57+
var urandomErr error
58+
59+
func urandomRead(b []byte) error {
60+
urandomOnce.Do(func() {
61+
urandomFile, urandomErr = os.Open("/dev/urandom")
62+
})
63+
if urandomErr != nil {
64+
return urandomErr
65+
}
66+
for len(b) > 0 {
67+
n, err := urandomFile.Read(b)
68+
// Note that we don't ignore EAGAIN because it should not be possible to
69+
// hit for a blocking read from urandom, although there were
70+
// unreproducible reports of it at https://go.dev/issue/9205.
71+
if err != nil {
72+
return err
73+
}
74+
b = b[n:]
75+
}
76+
return nil
77+
}

src/crypto/rand/rand_aix.go renamed to src/crypto/internal/sysrand/rand_aix.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
package rand
5+
package sysrand
66

77
func read(b []byte) error {
88
return urandomRead(b)

src/crypto/rand/rand_arc4random.go renamed to src/crypto/internal/sysrand/rand_arc4random.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
//go:build darwin || openbsd
66

7-
package rand
7+
package sysrand
88

99
import "internal/syscall/unix"
1010

src/crypto/rand/rand_getrandom.go renamed to src/crypto/internal/sysrand/rand_getrandom.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
//go:build dragonfly || freebsd || linux || solaris
66

7-
package rand
7+
package sysrand
88

99
import (
1010
"errors"

src/crypto/rand/rand_js.go renamed to src/crypto/internal/sysrand/rand_js.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
package rand
5+
package sysrand
66

77
// The maximum buffer size for crypto.getRandomValues is 65536 bytes.
88
// https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues#exceptions

src/crypto/rand/rand_linux_test.go renamed to src/crypto/internal/sysrand/rand_linux_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
package rand_test
5+
package sysrand_test
66

77
import (
88
"bytes"
9-
"crypto/rand/internal/seccomp"
9+
"crypto/internal/sysrand/internal/seccomp"
1010
"internal/syscall/unix"
1111
"internal/testenv"
1212
"os"
@@ -33,7 +33,6 @@ func TestNoGetrandom(t *testing.T) {
3333
t.Skip("skipping test in short mode")
3434
}
3535
testenv.MustHaveExec(t)
36-
testenv.MustHaveCGO(t)
3736

3837
done := make(chan struct{})
3938
go func() {

src/crypto/rand/rand_netbsd.go renamed to src/crypto/internal/sysrand/rand_netbsd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
package rand
5+
package sysrand
66

77
import "internal/syscall/unix"
88

src/crypto/rand/rand_plan9.go renamed to src/crypto/internal/sysrand/rand_plan9.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
package rand
5+
package sysrand
66

77
import (
88
"internal/byteorder"

0 commit comments

Comments
 (0)