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

Implement support for crypto/rc4 using OpenSSL/CNG #1065

Merged
merged 5 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 45 additions & 2 deletions eng/doc/fips/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ The Go crypto documentation is available online at https://pkg.go.dev/crypto.
- [func Prime](#func-prime)
- [func Read](#func-read)
- [crypto/rc4](#cryptorc4)
- [func NewCipher](#func-newcipher-1)
- [crypto/sha1](#cryptosha1)
- [func New](#func-new-1)
- [func Sum](#func-sum)
Expand Down Expand Up @@ -806,7 +807,44 @@ Read is a helper function that calls rand.Reader.Read using io.ReadFull.

### [crypto/rc4](https://pkg.go.dev/crypto/rc4)

Not implemented by any backend.
Package rc4 implements RC4 encryption, as defined in Bruce Schneier's Applied Cryptography.

#### func [NewCipher](https://pkg.go.dev/crypto/rc4#NewCipher)

```go
func rc4.NewCipher() rc4.Cipher
```

NewCipher creates and returns a new Cipher. The key argument should be the RC4 key, at least 1 byte and at most 256 bytes.

**Requirements**

Some OpenSSL distributions don't implement RC4, e.g., OpenSSL 1.x compiled with `-DOPENSSL_NO_RC4` and OpenSSL 3.x that can't load the legacy provider.
In those cases, `rc4.NewCipher()` will fall back to standard Go crypto.

**Implementation**

<details><summary>OpenSSL (click for details)</summary>

The cipher is generated using [EVP_CIPHER_CTX_new] and [EVP_CipherInit_ex] with the cipher type [EVP_rc4].

The rc4.Cipher methods are implemented as follows:

- `Reset` using [EVP_CIPHER_CTX_free].
- `XORKeyStream` using [EVP_EncryptUpdate].

</details>

<details><summary>CNG (click for details)</summary>

The cipher is generated using [BCryptGenerateSymmetricKey] using the `BCRYPT_RC4_ALGORITHM` mode.

The rc4.Cipher methods are implemented as follows:

- `Reset` using [BCryptDestroyKey].
- `XORKeyStream` using [BCryptEncrypt].

</details>

### [crypto/sha1](https://pkg.go.dev/crypto/sha1)

Expand Down Expand Up @@ -1437,6 +1475,7 @@ When using TLS in FIPS-only mode the TLS handshake has the following restriction
[EVP_aes_128_cbc]: https://www.openssl.org/docs/man3.0/man3/EVP_aes_128_cbc.html
[EVP_aes_192_cbc]: https://www.openssl.org/docs/man3.0/man3/EVP_aes_192_cbc.html
[EVP_aes_256_cbc]: https://www.openssl.org/docs/man3.0/man3/EVP_aes_256_cbc.html
[EVP_rc4]: https://www.openssl.org/docs/man3.0/man3/EVP_rc4.html
[EVP_sha1]: https://www.openssl.org/docs/man3.0/man3/EVP_sha1.html
[EVP_sha224]: https://www.openssl.org/docs/man3.0/man3/EVP_sha224.html
[EVP_sha256]: https://www.openssl.org/docs/man3.0/man3/EVP_sha256.html
Expand All @@ -1450,6 +1489,9 @@ When using TLS in FIPS-only mode the TLS handshake has the following restriction
[EVP_MAC_init]: https://www.openssl.org/docs/man3.0/man3/EVP_MAC_init.html
[EVP_MAC_update]: https://www.openssl.org/docs/man3.0/man3/EVP_MAC_update.html
[EVP_MAC_final]: https://www.openssl.org/docs/man3.0/man3/EVP_MAC_final.html
[EVP_CIPHER_CTX_new]: https://www.openssl.org/docs/man3.0/man3/EVP_CIPHER_CTX_new.html
[EVP_CipherInit_ex]: https://www.openssl.org/docs/man3.0/man3/EVP_CipherInit_ex.html
[EVP_CIPHER_CTX_free]: https://www.openssl.org/docs/man3.0/man3/EVP_CIPHER_CTX_free.html

[algorithm identifier]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-identifiers
[named elliptic curve]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-named-elliptic-curves
Expand All @@ -1469,4 +1511,5 @@ When using TLS in FIPS-only mode the TLS handshake has the following restriction
[BCRYPT_OAEP_PADDING_INFO]: https://docs.microsoft.com/en-us/windows/win32/api/Bcrypt/ns-bcrypt-bcrypt_oaep_padding_info
[BCRYPT_PKCS1_PADDING_INFO]: https://docs.microsoft.com/en-us/windows/win32/api/Bcrypt/ns-bcrypt-bcrypt_pkcs1_padding_info
[BCRYPT_PSS_PADDING_INFO]: https://docs.microsoft.com/en-us/windows/win32/api/Bcrypt/ns-bcrypt-bcrypt_pss_padding_info
[BCryptDeriveKey]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptderivekey
[BCryptDeriveKey]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptderivekey
[BCryptDestroyKey]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptdestroykey
83 changes: 75 additions & 8 deletions patches/0002-Add-crypto-backend-foundation.patch
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ Subject: [PATCH] Add crypto backend foundation
src/crypto/hmac/hmac.go | 2 +-
src/crypto/hmac/hmac_test.go | 2 +-
src/crypto/internal/backend/backend_test.go | 30 ++++
src/crypto/internal/backend/bbig/big.go | 17 +++
src/crypto/internal/backend/bbig/big.go | 17 ++
src/crypto/internal/backend/common.go | 78 ++++++++++
src/crypto/internal/backend/isrequirefips.go | 9 ++
src/crypto/internal/backend/nobackend.go | 145 +++++++++++++++++++
src/crypto/internal/backend/nobackend.go | 154 +++++++++++++++++++
src/crypto/internal/backend/norequirefips.go | 9 ++
src/crypto/internal/backend/stub.s | 10 ++
src/crypto/md5/md5.go | 7 +
src/crypto/md5/md5_test.go | 4 +
src/crypto/rand/rand_unix.go | 2 +-
src/crypto/rc4/rc4.go | 18 +++
src/crypto/rsa/boring.go | 4 +-
src/crypto/rsa/notboring.go | 2 +-
src/crypto/rsa/pkcs1v15.go | 2 +-
Expand All @@ -39,14 +40,14 @@ Subject: [PATCH] Add crypto backend foundation
src/crypto/sha512/sha512.go | 2 +-
src/crypto/sha512/sha512_test.go | 2 +-
src/crypto/tls/cipher_suites.go | 2 +-
src/crypto/tls/handshake_client.go | 25 +++-
src/crypto/tls/handshake_server.go | 25 +++-
src/crypto/tls/handshake_client.go | 25 ++-
src/crypto/tls/handshake_server.go | 25 ++-
src/crypto/tls/key_schedule.go | 18 ++-
src/crypto/tls/prf.go | 77 +++++++---
src/crypto/tls/prf_test.go | 12 +-
src/go/build/deps_test.go | 2 +
src/runtime/runtime_boring.go | 5 +
42 files changed, 473 insertions(+), 65 deletions(-)
43 files changed, 500 insertions(+), 65 deletions(-)
create mode 100644 src/crypto/internal/backend/backend_test.go
create mode 100644 src/crypto/internal/backend/bbig/big.go
create mode 100644 src/crypto/internal/backend/common.go
Expand Down Expand Up @@ -395,10 +396,10 @@ index 00000000000000..e5d7570d6d4363
+const isRequireFIPS = true
diff --git a/src/crypto/internal/backend/nobackend.go b/src/crypto/internal/backend/nobackend.go
new file mode 100644
index 00000000000000..275a6078f90514
index 00000000000000..f45f2fe76d54f1
--- /dev/null
+++ b/src/crypto/internal/backend/nobackend.go
@@ -0,0 +1,145 @@
@@ -0,0 +1,154 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
Expand Down Expand Up @@ -544,6 +545,15 @@ index 00000000000000..275a6078f90514
+func NewDESCipher(key []byte) (cipher.Block, error) { panic("cryptobackend: not available") }
+
+func NewTripleDESCipher(key []byte) (cipher.Block, error) { panic("cryptobackend: not available") }
+
+func SupportsRC4() bool { panic("cryptobackend: not available") }
+
+type RC4Cipher struct{}
+
+func (c *RC4Cipher) Reset() { panic("cryptobackend: not available") }
+func (c *RC4Cipher) XORKeyStream(dst, src []byte) { panic("cryptobackend: not available") }
+
+func NewRC4Cipher(key []byte) (*RC4Cipher, error) { panic("cryptobackend: not available") }
diff --git a/src/crypto/internal/backend/norequirefips.go b/src/crypto/internal/backend/norequirefips.go
new file mode 100644
index 00000000000000..26bfb5f6a643f3
Expand Down Expand Up @@ -642,6 +652,63 @@ index 40fce36314adfa..1d6231ae91d5ae 100644
"errors"
"io"
"os"
diff --git a/src/crypto/rc4/rc4.go b/src/crypto/rc4/rc4.go
index f08da0e469cd07..b3e7db0413ed72 100644
--- a/src/crypto/rc4/rc4.go
+++ b/src/crypto/rc4/rc4.go
@@ -11,6 +11,7 @@ package rc4

import (
"crypto/internal/alias"
+ boring "crypto/internal/backend"
"strconv"
)

@@ -18,6 +19,8 @@ import (
type Cipher struct {
s [256]uint32
i, j uint8
+
+ boring *boring.RC4Cipher
}

type KeySizeError int
@@ -33,6 +36,13 @@ func NewCipher(key []byte) (*Cipher, error) {
if k < 1 || k > 256 {
return nil, KeySizeError(k)
}
+ if boring.Enabled && boring.SupportsRC4() {
+ c, err := boring.NewRC4Cipher(key)
+ if err != nil {
+ return nil, err
+ }
+ return &Cipher{boring: c}, nil
+ }
var c Cipher
for i := 0; i < 256; i++ {
c.s[i] = uint32(i)
@@ -50,6 +60,10 @@ func NewCipher(key []byte) (*Cipher, error) {
// Deprecated: Reset can't guarantee that the key will be entirely removed from
// the process's memory.
func (c *Cipher) Reset() {
+ if boring.Enabled && boring.SupportsRC4() {
+ c.boring.Reset()
+ return
+ }
for i := range c.s {
c.s[i] = 0
}
@@ -59,6 +73,10 @@ func (c *Cipher) Reset() {
// XORKeyStream sets dst to the result of XORing src with the key stream.
// Dst and src must overlap entirely or not at all.
func (c *Cipher) XORKeyStream(dst, src []byte) {
+ if boring.Enabled && boring.SupportsRC4() {
+ c.boring.XORKeyStream(dst, src)
+ return
+ }
if len(src) == 0 {
return
}
diff --git a/src/crypto/rsa/boring.go b/src/crypto/rsa/boring.go
index b9f9d3154f2589..ecb43aaf264743 100644
--- a/src/crypto/rsa/boring.go
Expand Down Expand Up @@ -1187,7 +1254,7 @@ index 8233985a62bd22..f46d4636557714 100644
serverMACString := hex.EncodeToString(serverMAC)
clientKeyString := hex.EncodeToString(clientKey)
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 187dff74cfcb54..0fc11c2fb3ae7b 100644
index fcd5e939980f52..f10ecff5168acc 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -428,6 +428,7 @@ var depsRules = `
Expand Down
19 changes: 15 additions & 4 deletions patches/0003-Add-BoringSSL-crypto-backend.patch
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ Subject: [PATCH] Add BoringSSL crypto backend

---
.../internal/backend/bbig/big_boring.go | 12 ++
src/crypto/internal/backend/boring_linux.go | 175 ++++++++++++++++++
2 files changed, 187 insertions(+)
src/crypto/internal/backend/boring_linux.go | 186 ++++++++++++++++++
2 files changed, 198 insertions(+)
create mode 100644 src/crypto/internal/backend/bbig/big_boring.go
create mode 100644 src/crypto/internal/backend/boring_linux.go

Expand All @@ -30,10 +30,10 @@ index 00000000000000..0b62cef68546d0
+var Dec = bbig.Dec
diff --git a/src/crypto/internal/backend/boring_linux.go b/src/crypto/internal/backend/boring_linux.go
new file mode 100644
index 00000000000000..bc5c54b02acf2f
index 00000000000000..af2d4b857df333
--- /dev/null
+++ b/src/crypto/internal/backend/boring_linux.go
@@ -0,0 +1,175 @@
@@ -0,0 +1,186 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
Expand Down Expand Up @@ -209,3 +209,14 @@ index 00000000000000..bc5c54b02acf2f
+func NewTripleDESCipher(key []byte) (cipher.Block, error) {
+ panic("cryptobackend: not available")
+}
+
+func SupportsRC4() bool { return false }
+
+type RC4Cipher struct{}
+
+func (c *RC4Cipher) Reset() { panic("cryptobackend: not available") }
+func (c *RC4Cipher) XORKeyStream(dst, src []byte) { panic("cryptobackend: not available") }
+
+func NewRC4Cipher(key []byte) (*RC4Cipher, error) {
+ panic("cryptobackend: not available")
+}
30 changes: 19 additions & 11 deletions patches/0004-Add-OpenSSL-crypto-backend.patch
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Subject: [PATCH] Add OpenSSL crypto backend
src/crypto/ecdsa/notboring.go | 2 +-
src/crypto/internal/backend/bbig/big.go | 2 +-
.../internal/backend/bbig/big_openssl.go | 12 +
src/crypto/internal/backend/openssl_linux.go | 279 ++++++++++++++++++
src/crypto/internal/backend/openssl_linux.go | 287 ++++++++++++++++++
src/crypto/internal/boring/fipstls/stub.s | 2 +-
src/crypto/internal/boring/fipstls/tls.go | 2 +-
src/crypto/rsa/boring.go | 2 +-
Expand All @@ -37,7 +37,7 @@ Subject: [PATCH] Add OpenSSL crypto backend
.../goexperiment/exp_opensslcrypto_on.go | 9 +
src/internal/goexperiment/flags.go | 1 +
src/os/exec/exec_test.go | 9 +
33 files changed, 361 insertions(+), 23 deletions(-)
33 files changed, 369 insertions(+), 23 deletions(-)
create mode 100644 src/crypto/internal/backend/bbig/big_openssl.go
create mode 100644 src/crypto/internal/backend/openssl_linux.go
create mode 100644 src/internal/goexperiment/exp_opensslcrypto_off.go
Expand Down Expand Up @@ -190,10 +190,10 @@ index 00000000000000..e6695dd66b1d02
+var Dec = bbig.Dec
diff --git a/src/crypto/internal/backend/openssl_linux.go b/src/crypto/internal/backend/openssl_linux.go
new file mode 100644
index 00000000000000..d342e4b0f11e23
index 00000000000000..ff02e561452aa3
--- /dev/null
+++ b/src/crypto/internal/backend/openssl_linux.go
@@ -0,0 +1,279 @@
@@ -0,0 +1,287 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
Expand Down Expand Up @@ -322,14 +322,14 @@ index 00000000000000..d342e4b0f11e23
+ return openssl.SupportsHash(h)
+}
+
+func NewMD5() hash.Hash { return openssl.NewMD5() }
+func NewMD5() hash.Hash { return openssl.NewMD5() }
+func NewSHA1() hash.Hash { return openssl.NewSHA1() }
+func NewSHA224() hash.Hash { return openssl.NewSHA224() }
+func NewSHA256() hash.Hash { return openssl.NewSHA256() }
+func NewSHA384() hash.Hash { return openssl.NewSHA384() }
+func NewSHA512() hash.Hash { return openssl.NewSHA512() }
+
+func MD5(p []byte) (sum [16]byte) { return openssl.MD5(p) }
+func MD5(p []byte) (sum [16]byte) { return openssl.MD5(p) }
+func SHA1(p []byte) (sum [20]byte) { return openssl.SHA1(p) }
+func SHA224(p []byte) (sum [28]byte) { return openssl.SHA224(p) }
+func SHA256(p []byte) (sum [32]byte) { return openssl.SHA256(p) }
Expand Down Expand Up @@ -473,6 +473,14 @@ index 00000000000000..d342e4b0f11e23
+func NewTripleDESCipher(key []byte) (cipher.Block, error) {
+ return openssl.NewTripleDESCipher(key)
+}
+
+func SupportsRC4() bool {
+ return openssl.SupportsRC4()
+}
+
+type RC4Cipher = openssl.RC4Cipher
+
+func NewRC4Cipher(key []byte) (*RC4Cipher, error) { return openssl.NewRC4Cipher(key) }
diff --git a/src/crypto/internal/boring/fipstls/stub.s b/src/crypto/internal/boring/fipstls/stub.s
index f2e5a503eaacb6..1dc7116efdff2e 100644
--- a/src/crypto/internal/boring/fipstls/stub.s
Expand Down Expand Up @@ -669,24 +677,24 @@ index c83a7272c9f01f..a0548a7f9179c5 100644
package x509

diff --git a/src/go.mod b/src/go.mod
index 8f7dd5c0b69932..b5222cd4fb66b3 100644
index 8f7dd5c0b69932..0a9f28adb67211 100644
--- a/src/go.mod
+++ b/src/go.mod
@@ -3,6 +3,7 @@ module std
go 1.22

require (
+ github.com/golang-fips/openssl/v2 v2.0.0-rc.3.0.20230926133027-251d5fd9efa6
+ github.com/golang-fips/openssl/v2 v2.0.0-rc.3.0.20231013091736-92d3f16e56cd
golang.org/x/crypto v0.14.0
golang.org/x/net v0.17.0
)
diff --git a/src/go.sum b/src/go.sum
index 22511da608a07b..2e071695221e13 100644
index 22511da608a07b..afa147f35171de 100644
--- a/src/go.sum
+++ b/src/go.sum
@@ -1,3 +1,5 @@
+github.com/golang-fips/openssl/v2 v2.0.0-rc.3.0.20230926133027-251d5fd9efa6 h1:htngJbDceHA29WbezaO55msU/iITDkdto1p1iHHmjC0=
+github.com/golang-fips/openssl/v2 v2.0.0-rc.3.0.20230926133027-251d5fd9efa6/go.mod h1:7tuBqX2Zov8Yq5mJ2yzlKhpnxOnWyEzi38AzeWRuQdg=
+github.com/golang-fips/openssl/v2 v2.0.0-rc.3.0.20231013091736-92d3f16e56cd h1:+SvJEqhqQ8d/wzyk+xmTgBpHDOYQtnS/F8283hznEAc=
+github.com/golang-fips/openssl/v2 v2.0.0-rc.3.0.20231013091736-92d3f16e56cd/go.mod h1:7tuBqX2Zov8Yq5mJ2yzlKhpnxOnWyEzi38AzeWRuQdg=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
Expand Down
Loading
Loading