]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.boringcrypto] all: merge commit 9d0819b27c (CL 314609) into dev.boringcrypto
authorFilippo Valsorda <filippo@golang.org>
Wed, 12 May 2021 17:23:21 +0000 (19:23 +0200)
committerFilippo Valsorda <filippo@golang.org>
Thu, 13 May 2021 16:59:22 +0000 (12:59 -0400)
There used to be two BoringCrypto-specific behaviors related to cipher
suites in crypto/tls:

1. in FIPS-only mode, only a restricted set of AES ciphers is allowed

2. NOT in FIPS-only mode, AES would be prioritized over ChaCha20 even if
   AES hardware was not available

The motivation of (2) is unclear, and BoringSSL doesn't have equivalent
logic. This merge drops (2), and keeps (1). Note that the list of
FIPS-only ciphers does not have priority semantics anymore, but the
default logic still sorts them the same way as they used to be.

Change-Id: I50544011085cfa2b087f323aebf5338c0bd2dd33

86 files changed:
README.boringcrypto.md [new file with mode: 0644]
api/go1.16.txt
api/go1.9.txt
codereview.cfg
misc/boring/README.md [new file with mode: 0644]
misc/boring/RELEASES [new file with mode: 0644]
misc/boring/VERSION [new file with mode: 0644]
misc/boring/build.docker [new file with mode: 0755]
misc/boring/build.release [new file with mode: 0755]
misc/boring/dockerfile.in [new file with mode: 0644]
misc/boring/merge.sh [new file with mode: 0755]
misc/boring/release.sh [new file with mode: 0755]
src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/go/go_boring_test.go [new file with mode: 0644]
src/cmd/go/go_test.go
src/cmd/go/internal/load/pkg.go
src/cmd/link/internal/ld/lib.go
src/crypto/aes/cipher.go
src/crypto/aes/cipher_asm.go
src/crypto/boring/boring.go [new file with mode: 0644]
src/crypto/boring/boring_test.go [new file with mode: 0644]
src/crypto/boring/notboring_test.go [new file with mode: 0644]
src/crypto/ecdsa/boring.go [new file with mode: 0644]
src/crypto/ecdsa/ecdsa.go
src/crypto/ed25519/ed25519_test.go
src/crypto/ed25519/internal/edwards25519/edwards25519_test.go
src/crypto/hmac/hmac.go
src/crypto/hmac/hmac_test.go
src/crypto/internal/boring/Dockerfile [new file with mode: 0644]
src/crypto/internal/boring/LICENSE [new file with mode: 0644]
src/crypto/internal/boring/aes.go [new file with mode: 0644]
src/crypto/internal/boring/boring.go [new file with mode: 0644]
src/crypto/internal/boring/boring_test.go [new file with mode: 0644]
src/crypto/internal/boring/build.sh [new file with mode: 0755]
src/crypto/internal/boring/doc.go [new file with mode: 0644]
src/crypto/internal/boring/ecdsa.go [new file with mode: 0644]
src/crypto/internal/boring/fipstls/dummy.s [new file with mode: 0644]
src/crypto/internal/boring/fipstls/tls.go [new file with mode: 0644]
src/crypto/internal/boring/goboringcrypto.h [new file with mode: 0644]
src/crypto/internal/boring/goboringcrypto_linux_amd64.syso [new file with mode: 0644]
src/crypto/internal/boring/hmac.go [new file with mode: 0644]
src/crypto/internal/boring/notboring.go [new file with mode: 0644]
src/crypto/internal/boring/rand.go [new file with mode: 0644]
src/crypto/internal/boring/rsa.go [new file with mode: 0644]
src/crypto/internal/boring/sha.go [new file with mode: 0644]
src/crypto/internal/boring/sig/sig.go [new file with mode: 0644]
src/crypto/internal/boring/sig/sig_amd64.s [new file with mode: 0644]
src/crypto/internal/boring/sig/sig_other.s [new file with mode: 0644]
src/crypto/issue21104_test.go
src/crypto/rand/rand_unix.go
src/crypto/rsa/boring.go [new file with mode: 0644]
src/crypto/rsa/boring_test.go [new file with mode: 0644]
src/crypto/rsa/pkcs1v15.go
src/crypto/rsa/pkcs1v15_test.go
src/crypto/rsa/pss.go
src/crypto/rsa/pss_test.go
src/crypto/rsa/rsa.go
src/crypto/rsa/rsa_test.go
src/crypto/sha1/boring.go [new file with mode: 0644]
src/crypto/sha1/notboring.go [new file with mode: 0644]
src/crypto/sha1/sha1.go
src/crypto/sha1/sha1_test.go
src/crypto/sha256/sha256.go
src/crypto/sha256/sha256_test.go
src/crypto/sha512/sha512.go
src/crypto/sha512/sha512_test.go
src/crypto/tls/auth.go
src/crypto/tls/auth_test.go
src/crypto/tls/boring.go [new file with mode: 0644]
src/crypto/tls/boring_test.go [new file with mode: 0644]
src/crypto/tls/cipher_suites.go
src/crypto/tls/common.go
src/crypto/tls/fipsonly/fipsonly.go [new file with mode: 0644]
src/crypto/tls/fipsonly/fipsonly_test.go [new file with mode: 0644]
src/crypto/tls/handshake_client.go
src/crypto/tls/handshake_client_tls13.go
src/crypto/tls/handshake_messages_test.go
src/crypto/tls/handshake_server.go
src/crypto/tls/handshake_server_tls13.go
src/crypto/x509/verify.go
src/go/build/build.go
src/go/build/deps_test.go
src/internal/boringtest/boring.go [new file with mode: 0644]
src/internal/boringtest/boring_test.go [new file with mode: 0644]
src/runtime/race/testdata/mop_test.go
src/runtime/runtime_boring.go [new file with mode: 0644]

diff --git a/README.boringcrypto.md b/README.boringcrypto.md
new file mode 100644 (file)
index 0000000..54adda6
--- /dev/null
@@ -0,0 +1,20 @@
+# dev.boringcrypto branch
+
+We have been working inside Google on a fork of Go that uses
+BoringCrypto (the core of [BoringSSL][]) for various crypto
+primitives, in furtherance of some [work related to FIPS 140-2][sp].
+We have heard that some external users of Go would be interested in
+this code as well, so this branch holds the patches to make Go use
+BoringCrypto.
+
+[BoringSSL]: https://boringssl.googlesource.com/boringssl/
+[sp]: https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp3678.pdf
+
+Unlike typical dev branches, we do not intend any eventual merge of
+this code into the master branch. Instead we intend to maintain in
+this branch the latest release plus BoringCrypto patches.
+
+To be clear, we are not making any statements or representations about
+the suitability of this code in relation to the FIPS 140-2 standard.
+Interested users will have to evaluate for themselves whether the code
+is useful for their own purposes.
index ce015fd6fb7ebdc8f7dfac932737d5ff18228fa9..d9fb7e38843a70031016a833c0a417c73909a270 100644 (file)
@@ -1,5 +1,6 @@
 pkg archive/zip, method (*ReadCloser) Open(string) (fs.File, error)
 pkg archive/zip, method (*Reader) Open(string) (fs.File, error)
+pkg crypto/boring, func Enabled() bool
 pkg crypto/x509, method (SystemRootsError) Unwrap() error
 pkg debug/elf, const DT_ADDRRNGHI = 1879047935
 pkg debug/elf, const DT_ADDRRNGHI DynTag
index c23a17ea1a39491822283aa30de439301b5ffc0f..c7a4968aaf701db13a4ed7809a3dde22c8e741fd 100644 (file)
@@ -7,6 +7,7 @@ pkg crypto, const BLAKE2b_512 Hash
 pkg crypto, const BLAKE2s_256 = 16
 pkg crypto, const BLAKE2s_256 Hash
 pkg crypto/x509, type Certificate struct, ExcludedDNSDomains []string
+pkg crypto/x509, type VerifyOptions struct, IsBoring func(*Certificate) bool
 pkg database/sql, method (*Conn) BeginTx(context.Context, *TxOptions) (*Tx, error)
 pkg database/sql, method (*Conn) Close() error
 pkg database/sql, method (*Conn) ExecContext(context.Context, string, ...interface{}) (Result, error)
index 77a74f108eae362626abcdbfcf41ddb9a33b02cd..4157a7260b332d6ed757c3a60df37f9ccd3bd8ab 100644 (file)
@@ -1 +1,2 @@
-branch: master
+branch: dev.boringcrypto
+parent-branch: master
diff --git a/misc/boring/README.md b/misc/boring/README.md
new file mode 100644 (file)
index 0000000..bd8deff
--- /dev/null
@@ -0,0 +1,108 @@
+# README.md
+
+This directory holds build scripts for unofficial, unsupported
+distributions of Go+BoringCrypto.
+
+## Version strings
+
+The distribution name for a Go+BoringCrypto release has the form `<GoVersion>b<BoringCryptoVersion>`,
+where `<GoVersion>` is the Go version the release is based on, and `<BoringCryptoVersion>` is
+an integer that increments each time there is a new release with different BoringCrypto bits.
+The `<BoringCryptoVersion>` is stored in the `VERSION` file in this directory.
+
+For example, the first release is based on Go 1.8.3 is `go1.8.3b1`.
+If the BoringCrypto bits are updated, the next would be `go1.8.3b2`.
+If, after that, Go 1.9 is released and the same BoringCrypto code added to it,
+that would result in `go1.9b2`. There would likely not be a `go1.9b1`,
+since that would indicate Go 1.9 with the older BoringCrypto code.
+
+## Releases
+
+The `build.release` script prepares a binary release and publishes it in Google Cloud Storage
+at `gs://go-boringcrypto/`, making it available for download at
+`https://go-boringcrypto.storage.googleapis.com/<FILE>`.
+The script records each published release in the `RELEASES` file in this directory.
+
+The `build.docker` script, which must be run after `build.release`, prepares a Docker image
+and publishes it on hub.docker.com in the goboring organization.
+`go1.8.3b1` is published as `goboring/golang:1.8.3b1`.
+
+## Release process
+
+Development is done on the dev.boringcrypto branch, which tracks
+master. Releases are cut from dev.boringcrypto.go1.X branches,
+which are BoringCrypto backported to the Go 1.X release branches.
+To issue new BoringCrypto releases based on Go 1.X:
+
+1. If the BoringCrypto bits have been updated, increment the
+   number in `VERSION`, send that change out as a CL for review,
+   get it committed to dev.boringcrypto, and run `git sync`.
+
+2. Change to the dev.boringcrypto.go1.X branch and cherry-pick
+   all BoringCrypto updates, including the update of the
+   `VERSION` file. If desired, merge release-branch.go1.X into
+   dev.boringcrypto.go1.X. Mail them out and get them committed.
+
+3. **Back on the dev.boringcrypto branch**, run `git fetch`,
+   `make.bash` and then `build.release dev.boringcrypto.go1.X`.
+   The script will determine the base Go version and the
+   BoringCrypto version, build a release, and upload it.
+
+4. Run `build.docker`, which will build and upload a Docker image
+   from the latest release.
+
+5. Send out a CL with the updated `RELEASES` file and get it
+   committed to dev.boringcrypto.
+
+## Building from Docker
+
+A Dockerfile that starts with `FROM golang:1.8.3` can switch
+to `FROM goboring/golang:1.8.3b2` (see [goboring/golang on Docker Hub](https://hub.docker.com/r/goboring/golang/))
+and should need no other modifications.
+
+## Building from Bazel
+
+Starting from [bazelbuild/rules_go](https://github.com/bazelbuild/rules_go)
+tag 0.7.1, simply download the BoringCrypto-enabled Go SDK using
+`go_download_sdk()` before calling `go_register_toolchains()`.
+
+For example, to use Go 1.9.3 with BoringCrypto on Linux, use the following lines
+in `WORKSPACE`:
+```python
+load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_download_sdk", "go_register_toolchains")
+
+go_rules_dependencies()
+
+go_download_sdk(
+    name = "go_sdk",
+    sdks = {
+       "linux_amd64": ("go1.9.3b4.linux-amd64.tar.gz", "db1997b2454a2f27669b849d2d2cafb247a55128d53da678f06cb409310d6660"),
+    },
+    urls = ["https://storage.googleapis.com/go-boringcrypto/{}"],
+)
+
+go_register_toolchains()
+```
+
+**Note**: you must *not* enable `pure` mode, since cgo must be enabled. To
+ensure that binaries are linked with BoringCrypto, you can set `pure = "off"` on
+all relevant `go_binary` rules.
+
+## Caveat
+
+BoringCrypto is used for a given build only in limited circumstances:
+
+  - The build must be GOOS=linux, GOARCH=amd64.
+  - The build must have cgo enabled.
+  - The android build tag must not be specified.
+  - The cmd_go_bootstrap build tag must not be specified.
+
+The version string reported by `runtime.Version` does not indicate that BoringCrypto
+was actually used for the build. For example, linux/386 and non-cgo linux/amd64 binaries
+will report a version of `go1.8.3b2` but not be using BoringCrypto.
+
+To check whether a given binary is using BoringCrypto, run `go tool nm` on it and check
+that it has symbols named `*_Cfunc__goboringcrypto_*`.
+
+The program [rsc.io/goversion](https://godoc.org/rsc.io/goversion) will report the
+crypto implementation used by a given binary when invoked with the `-crypto` flag.
diff --git a/misc/boring/RELEASES b/misc/boring/RELEASES
new file mode 100644 (file)
index 0000000..ae97e07
--- /dev/null
@@ -0,0 +1,141 @@
+# This file lists published Go+BoringCrypto releases.
+# Each line describes a single release: <version> <git commit> <target> <URL> <sha256sum>
+go1.9rc2b2 91753387bdf7 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.9rc2b2.linux-amd64.tar.gz 59355a45e6970e8013060851ddb3f079afe8db52e90db520a0826a13f1b5ae5b
+go1.8.3b3 f6ff81bac156 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.8.3b3.linux-amd64.tar.gz 6287ad971cd268bb2684fb8b1275dea928ad527823062bc057e73036c419e7af
+go1.9rc2b4 c339bc4e07a6 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.9rc2b4.linux-amd64.tar.gz a8f677d48dc93920065fca4dca1a55bf7110aba132489c47e25d26d55c67eb32
+go1.9b4 e6ad24cde71e linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.9b4.linux-amd64.tar.gz 6592e36a05df8e7c59812328a3a4bfa6c4eed72132fc31245951c3ade3ef2a8a
+go1.9b4 e6ad24cde71e src https://go-boringcrypto.storage.googleapis.com/go1.9b4.src.tar.gz c85f31dc743fee0e8ce0c6ffc286e27c1f51b66c9b923afafb43cdc378a41091
+go1.8.3b4 42cb4dcdb59a linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.8.3b4.linux-amd64.tar.gz 4011c86e6175925e1c63dc7c19a51f825be53bbe7b08260918e5107b0fbd4f85
+go1.8.3b4 42cb4dcdb59a src https://go-boringcrypto.storage.googleapis.com/go1.8.3b4.src.tar.gz 2531ca8918aa024aed8f4a6c9e5c3b25bc8777623f1efa66aec7214601d474e4
+go1.9.2b4 cda3c6f91d7c linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.9.2b4.linux-amd64.tar.gz 7c5e9a033ddc3ab36646e3bac7fd16962742710c70c18122e44a9ab56cdd3cf7
+go1.9.2b4 cda3c6f91d7c src https://go-boringcrypto.storage.googleapis.com/go1.9.2b4.src.tar.gz 38a2260b64a6a5ab20f8972d08b4765bad116721356433f39aebd29c7598218c
+go1.9.3b4 f4e5ebdf35c8 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.9.3b4.linux-amd64.tar.gz db1997b2454a2f27669b849d2d2cafb247a55128d53da678f06cb409310d6660
+go1.9.3b4 f4e5ebdf35c8 src https://go-boringcrypto.storage.googleapis.com/go1.9.3b4.src.tar.gz 7485e1fc53a9fab9cf34f71de74d69f4c50f9d11a449647de40ee04b59bf8a5b
+go1.9.7b4 0bad1bef406e linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.9.7b4.linux-amd64.tar.gz 9e33a0deb8fed3bd7fa3d122bb5143be9e0a974a422ab4ddac5e765fa1310a6f
+go1.9.7b4 0bad1bef406e src https://go-boringcrypto.storage.googleapis.com/go1.9.7b4.src.tar.gz ad9fb6e22a27382c468467ecade4937f725b33818852f1c1da0d09b471e7486c
+go1.10.3b4 35ba5284935c linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.10.3b4.linux-amd64.tar.gz 6754729d78a375bd1debd980b1e3e7fd49198a980d0bbd8f39e89569aa001942
+go1.10.3b4 35ba5284935c src https://go-boringcrypto.storage.googleapis.com/go1.10.3b4.src.tar.gz f3e75c60a835c11b97e30429b63917ceb31f799b2ba7e2001d99db908fb8e28f
+go1.10.4b4 2e2a04a605b6 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.10.4b4.linux-amd64.tar.gz 17c275ff448686fe1908ecbea5d11ad6f4f7caa288d1786b756439703b12b8b2
+go1.10.4b4 2e2a04a605b6 src https://go-boringcrypto.storage.googleapis.com/go1.10.4b4.src.tar.gz f9cc38e194edabebf338fb74c22f597dc847560618d5d7d4d6cdc28139efa772
+go1.11b4 685dc1638240 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.11b4.linux-amd64.tar.gz d53417b2071af0104fbc15a957000bccdcb5bbc094df0401f67d51968f7f2e4e
+go1.11b4 685dc1638240 src https://go-boringcrypto.storage.googleapis.com/go1.11b4.src.tar.gz 39896f0decd6721e81324cb2bb19540706ca97152c6800a6c8ad15a4e4162184
+go1.11.2b4 35cf0d9f6bbd linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.11.2b4.linux-amd64.tar.gz a9ceb6d0b4413d81ccc94c6460f60ca0c4f36b5dcbf659e1be582cd40c0edfbd
+go1.11.2b4 35cf0d9f6bbd src https://go-boringcrypto.storage.googleapis.com/go1.11.2b4.src.tar.gz 8e12a8df1428f00239dc67dd438a81f72c9925982e90b6899f66270971bddc1c
+go1.10.7b4 8b246fe0f595 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.10.7b4.linux-amd64.tar.gz 31917ab96004b9b482399b46928f5c10cdadefed5fda6f4de262efe2c3c7533e
+go1.10.7b4 8b246fe0f595 src https://go-boringcrypto.storage.googleapis.com/go1.10.7b4.src.tar.gz 323a184c77e3a377f5ed993b04946ee7b1a8e3350aba2894c0944f1e313636f1
+go1.11.4b4 572c4bce6792 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.11.4b4.linux-amd64.tar.gz e708ef7ecaf17a3e8e6deceadfa167cc1162f710f97ea4bc124d3837d6e2eaa1
+go1.11.4b4 572c4bce6792 src https://go-boringcrypto.storage.googleapis.com/go1.11.4b4.src.tar.gz ea963b80e218a34470e14e6e997fe06b8c5bf3f9c9bb0c801f7d8ef63b9bcb73
+go1.10.8b4 4b76b996cb0a linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.10.8b4.linux-amd64.tar.gz 6d7d3323030851b595ba7ed66931c352b63de6dfe1ab3e6d6243987765d09819
+go1.10.8b4 4b76b996cb0a src https://go-boringcrypto.storage.googleapis.com/go1.10.8b4.src.tar.gz c1f5df50a4be3d0cb3aed7b80728f2b23c18deff0383636274742a38c145f939
+go1.11.5b4 3fb9dafacc45 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.11.5b4.linux-amd64.tar.gz 9b5b2972b452da9ba6bba65bab18fb9e8fbda31b5c489275710e5429d76f568c
+go1.11.5b4 3fb9dafacc45 src https://go-boringcrypto.storage.googleapis.com/go1.11.5b4.src.tar.gz 1c5801e2af25c9299d9fd94c64f9ec11fd35777c45d5d0f398c0a9884b1cfbbf
+go1.12.1b4 88e20e81a61f linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.12.1b4.linux-amd64.tar.gz b71886e0d65e5efea2e0a3cbd0c3cd0daf84c437078e755ecde25f4ac0bbed2f
+go1.12.1b4 88e20e81a61f src https://go-boringcrypto.storage.googleapis.com/go1.12.1b4.src.tar.gz d44be1396eb2854b5d9c4d8e8ed0cf9fea1e9dc5a02d8f53b41ba571951a329f
+go1.11.6b4 7be8a5843a9b linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.11.6b4.linux-amd64.tar.gz b704f61b8979e64a46da8884c90cd2b0e2d54e802d55e5f56d7c93752334c197
+go1.11.6b4 7be8a5843a9b src https://go-boringcrypto.storage.googleapis.com/go1.11.6b4.src.tar.gz a56b45e24b61ad7b3c90dfd906cd22426a4de9e2e697b4c9ef07a2af047bcb0d
+go1.12.5b4 ad495d31d908 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.12.5b4.linux-amd64.tar.gz df0e64958cf90f27a65b2175eb80bc34a601136eed8e5559bed2a9e349e33707
+go1.12.5b4 ad495d31d908 src https://go-boringcrypto.storage.googleapis.com/go1.12.5b4.src.tar.gz 054d482896a77ae2d7d24c7adf08da5a4401b938871e61a5cdabc735c54cea9f
+go1.11.11b4 346babe6a67f linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.11.11b4.linux-amd64.tar.gz c4dd44fa00f491b3d2ea808af8a6c234f915adb27c014512d725bafc4784d75f
+go1.11.11b4 346babe6a67f src https://go-boringcrypto.storage.googleapis.com/go1.11.11b4.src.tar.gz 57a724a72f0ba8620cbb48288f39c86ed513c241509ddf73231f4c8cd2a983ac
+go1.12.6b4 6b86b09ad4d3 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.12.6b4.linux-amd64.tar.gz eebc2e7f37555760adb361985b861d0cd34f9401cf7456d8d2f2f3082a60eee1
+go1.12.6b4 6b86b09ad4d3 src https://go-boringcrypto.storage.googleapis.com/go1.12.6b4.src.tar.gz 0e6e9aaf2c72a7e61280ce1e77b2ea24f01a59f4c1e6f0aa72b753206724fd3a
+go1.11.12b4 845e947ae34f linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.11.12b4.linux-amd64.tar.gz 91808261fc357855fba920df01a933d6104e907793014317de00b92802d494d9
+go1.11.12b4 845e947ae34f src https://go-boringcrypto.storage.googleapis.com/go1.11.12b4.src.tar.gz 7b64d9e56ea627138d87c7533df8f9932a79ff900f150a8d8e6a3edc2d0066ec
+go1.12.7b4 bd126d0ad256 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.12.7b4.linux-amd64.tar.gz 7f0c73cd397bccad48ab4df4188d3651c25bf33102275848c6e67b882e11f680
+go1.12.7b4 bd126d0ad256 src https://go-boringcrypto.storage.googleapis.com/go1.12.7b4.src.tar.gz 0c48d7b81ef2b948980011fad1d176d6b10636a4016e3aed7438d86e046d816b
+go1.11.13b4 4f8e7223f936 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.11.13b4.linux-amd64.tar.gz eeb232577065732f5d57a4c77b7d73aa60231ee6fd6496daf7558993e92e403f
+go1.11.13b4 4f8e7223f936 src https://go-boringcrypto.storage.googleapis.com/go1.11.13b4.src.tar.gz 107da8846803a0a735766ca0947de6cd15cd23d8c584002f06e7ac5f81ecb114
+go1.12.8b4 55186ba70c1a linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.12.8b4.linux-amd64.tar.gz 63f278abfc1e98546bc0ffc87f000d9aae2b06c0700212cb55ffd17d059fb8e1
+go1.12.8b4 55186ba70c1a src https://go-boringcrypto.storage.googleapis.com/go1.12.8b4.src.tar.gz c12b1d56ba4e0572f85a08681e05c66293ad53f04b11ce74c688d78fcb882061
+go1.12.9b4 ee88e5b118b5 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.12.9b4.linux-amd64.tar.gz d90989cba1db647b795400a9520eab2fa30f8dea50f4189b18d53f757a4bac44
+go1.12.9b4 ee88e5b118b5 src https://go-boringcrypto.storage.googleapis.com/go1.12.9b4.src.tar.gz 9d4efed8e13fa5ebdadd4fc22f9e35e67bfb34322570c83a15a0879472412e13
+go1.13b4 28e8a0c21e00 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.13b4.linux-amd64.tar.gz 4a909f34bc487badb5ec11646c471ae690393d3f7835b8fbef8466d04ee23cba
+go1.13b4 28e8a0c21e00 src https://go-boringcrypto.storage.googleapis.com/go1.13b4.src.tar.gz 3c2dbe1bfcd7299b5be4b75529425c0a67b8d6b76f81f993b84ae0d173934257
+go1.12.10b4 5827153a1db7 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.12.10b4.linux-amd64.tar.gz 20963fde89fd20eebee9d89003e52702f0379fdb04a68754f9fadf2c302166e3
+go1.12.10b4 5827153a1db7 src https://go-boringcrypto.storage.googleapis.com/go1.12.10b4.src.tar.gz f5cfe73cfeaaa67619ff4a4bbc587e622d63a6aaa7145253e6583bd59072b323
+go1.13.1b4 2da1832ad494 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.13.1b4.linux-amd64.tar.gz 70be1bae05feb67d0560f39767e80707343d96554c5a611fbb93b04ce5913693
+go1.13.1b4 2da1832ad494 src https://go-boringcrypto.storage.googleapis.com/go1.13.1b4.src.tar.gz cf94520325f376ecaf420b7d25756cdecbed52510a1a079eca67c2c86c3cf39b
+go1.12.11b4 c5a4ae8c8c1b linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.12.11b4.linux-amd64.tar.gz a2d90aa130d45b36dd94a7e70accc94e2585eb45823fb7b07ae182ac8bc4a8ca
+go1.12.11b4 c5a4ae8c8c1b src https://go-boringcrypto.storage.googleapis.com/go1.12.11b4.src.tar.gz c334b70c9af0380fb9d397e89af1e2e2ac03380b5cc7c3327f56536c2f68bf8d
+go1.13.2b4 6a1c22797f9c linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.13.2b4.linux-amd64.tar.gz 888c1f6331862af388e730fab4926aa1cb2d4ffc5417e32f9e6d2af7953f0e29
+go1.13.2b4 6a1c22797f9c src https://go-boringcrypto.storage.googleapis.com/go1.13.2b4.src.tar.gz fc44c7713fcd84fe0587594ae5ee1a1d318a0da18b1156e1f9645c6ffa0335bc
+go1.12.12b4 cab2e4707a42 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.12.12b4.linux-amd64.tar.gz 983e996e8f60c78a400fed0edfd16c1718d704e15389c48b4a8b2d835c0d00f2
+go1.12.12b4 cab2e4707a42 src https://go-boringcrypto.storage.googleapis.com/go1.12.12b4.src.tar.gz 2d653a74c14cde1e414ac558e0bdd182ccbe1198bbff8cd22c8e423552d5e24d
+go1.13.3b4 cba6efa89376 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.13.3b4.linux-amd64.tar.gz 9ba0b7696f14dc7ecc912aae6587491853637fab30c4c005339fe36751bfd185
+go1.13.3b4 cba6efa89376 src https://go-boringcrypto.storage.googleapis.com/go1.13.3b4.src.tar.gz ba83d7e18fa49dc6e4319806e7b5cdee5eb046eb8e9fb38f3034378c4f80944a
+go1.12.13b4 5d9d84d037da linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.12.13b4.linux-amd64.tar.gz af3e0d2b9996c632b010da6700b7b8ec52bd3065b3facc478709209a854664eb
+go1.12.13b4 5d9d84d037da src https://go-boringcrypto.storage.googleapis.com/go1.12.13b4.src.tar.gz d1bae336ea076a0b2bfc984477f4a216a475e134068227e6d9b44faf239bcfb8
+go1.13.4b4 fa3f24e5c294 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.13.4b4.linux-amd64.tar.gz 23579d1bea65b2510e507bb0698ec66777bd34674c91dfe617ed130728791dc7
+go1.13.4b4 fa3f24e5c294 src https://go-boringcrypto.storage.googleapis.com/go1.13.4b4.src.tar.gz 8d82df5b4332acd5a274ac029ee5b5ff073b2a4247e2325610986221858b819d
+go1.12.16b4 f74e68136cf1 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.12.16b4.linux-amd64.tar.gz fd70cee8ca9438f99cc71b3586b11a03a36239a5bccbf1c4d06e7206b88bd77d
+go1.12.16b4 f74e68136cf1 src https://go-boringcrypto.storage.googleapis.com/go1.12.16b4.src.tar.gz 2ae0823cefc34f280d4f4ba0d665ff247ba1429cb43198d10e3bc316d3f29a8d
+go1.13.7b4 71468339f763 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.13.7b4.linux-amd64.tar.gz 85945502ad43f506902927f69b514b34a85a20e2bd1020cce87c551645194aa3
+go1.13.7b4 71468339f763 src https://go-boringcrypto.storage.googleapis.com/go1.13.7b4.src.tar.gz d30fa252de75763adb5886125e19e8bab68dbe8dbad33b0faf09a6be98b12d96
+go1.12.17b4 9e5b1367cb45 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.12.17b4.linux-amd64.tar.gz ee3a72dc1cfd8a34f32aaa5ddb05076fcb39434fd1bd25aa318234f72b462e31
+go1.12.17b4 9e5b1367cb45 src https://go-boringcrypto.storage.googleapis.com/go1.12.17b4.src.tar.gz ffb653ec8f4cc33e1e7c308d89c695f322a76f3107e0fc8c639affc6148261bf
+go1.13.8b4 fdf5e5b5905f linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.13.8b4.linux-amd64.tar.gz eac505df92aa6d6b76041f4b485d230f839159b8567c96d7980a06ef476ab3df
+go1.13.8b4 fdf5e5b5905f src https://go-boringcrypto.storage.googleapis.com/go1.13.8b4.src.tar.gz 1aa28fe37a704e94bb34e23578fd07ebbc6a025e9be9b45a898967b84405c41b
+go1.14b4 99da8fa53467 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.14b4.linux-amd64.tar.gz a617e03a6c8813c53b813b865a2e185e12dbfaa76c703c1c48e57ad89651556b
+go1.14b4 99da8fa53467 src https://go-boringcrypto.storage.googleapis.com/go1.14b4.src.tar.gz ee292639b24923f519f1f0fe1ceaeca8d46feb8c15cf88e228346398c5848380
+go1.13.9b4 bb8a1014a32c linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.13.9b4.linux-amd64.tar.gz 565e1a3c62dfc2586471b6ae189ada053a86fc51d88d2eac883a03731071bf77
+go1.13.9b4 bb8a1014a32c src https://go-boringcrypto.storage.googleapis.com/go1.13.9b4.src.tar.gz 536f0549e7bbdad32270a17d8a282667560b6da2d27a5e3580714338e70185ad
+go1.14.1b4 e784c3f4d925 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.14.1b4.linux-amd64.tar.gz 6570991396d531fb628e4c01d697eeee395104147d406aec5a8ba00a213ef63f
+go1.14.1b4 e784c3f4d925 src https://go-boringcrypto.storage.googleapis.com/go1.14.1b4.src.tar.gz 2c267c3114fa4683f51c281d216d3754b38d5d08144c3acc318cf37165b1b2da
+go1.13.10b4 b129f40bb33f linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.13.10b4.linux-amd64.tar.gz a511b2e6ee7b71ca1411d6e4bb07ec33bb5b6974fd1dded77e00520d24d9d000
+go1.13.10b4 b129f40bb33f src https://go-boringcrypto.storage.googleapis.com/go1.13.10b4.src.tar.gz 5dfa44eea19b0be0c9c394fbbf89b2a14f84380a9d7b87e21eacba3ba030c44b
+go1.14.2b4 2b0d842f4b24 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.14.2b4.linux-amd64.tar.gz 82449a7ce57733c0cd3fa7feac89214706ff2b04e387b62619b8e2b8b388ffd9
+go1.14.2b4 2b0d842f4b24 src https://go-boringcrypto.storage.googleapis.com/go1.14.2b4.src.tar.gz bfcb44fa329d6a2eb5c4ef58bfa114d65b078bf69a361bb77e3ea52ec8975d14
+go1.13.12b4 488ca930b24a linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.13.12b4.linux-amd64.tar.gz 63193aa2290af5d65d2d6bbddcd11d835d437a4e835954d605863f5b27a7661d
+go1.13.12b4 488ca930b24a src https://go-boringcrypto.storage.googleapis.com/go1.13.12b4.src.tar.gz 5b0aefb44ba2a08fedb5be0144810bc47559d7d8a6e61638c09dd261706d650e
+go1.14.4b4 fcdb6aa6ee5d linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.14.4b4.linux-amd64.tar.gz 682f2167b3d619690b1385196776822b1d2c497607f67e2d19d92faf2bea0b4a
+go1.14.4b4 fcdb6aa6ee5d src https://go-boringcrypto.storage.googleapis.com/go1.14.4b4.src.tar.gz 2fb759023360f0d42ba434f0409da2460ff4386cab062557f97fe15122b4b4cd
+go1.13.14b4 852ccd9de7d1 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.13.14b4.linux-amd64.tar.gz 49c67d3a67fac60e18a264555392aa5925126a75ef0ba152ec315cc874eccb43
+go1.13.14b4 852ccd9de7d1 src https://go-boringcrypto.storage.googleapis.com/go1.13.14b4.src.tar.gz 7b7dfc62286a07d438370b09f38845acae99c592c6e147722b8f3c098ab8756a
+go1.14.6b4 8f53ffb15fd5 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.14.6b4.linux-amd64.tar.gz 953322287806a42d4a73e096aea45511a51a0a323086e98119edcb0dae866c9d
+go1.14.6b4 8f53ffb15fd5 src https://go-boringcrypto.storage.googleapis.com/go1.14.6b4.src.tar.gz 75fea7a60da4ca225473b500b2d5ce7c302ca7d22eedfdbd3444cd01e6b9f392
+go1.15b5 a15df605fc4a linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.15b5.linux-amd64.tar.gz ebcb2212bdb645a16ffc05a1d9b77c94553ed19a6ccbbc73e4868c64777eb70a
+go1.15b5 a15df605fc4a src https://go-boringcrypto.storage.googleapis.com/go1.15b5.src.tar.gz 7107665853228b2c18f56fec73e217fa3494ccf52c609be839cf6945d501c0f0
+go1.13.15b4 5622128a77b4 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.13.15b4.linux-amd64.tar.gz 8b45ec0e578dc0a0bc483c2d12c08fee5adbfb39f0854fbe9d45f7d628ed1697
+go1.13.15b4 5622128a77b4 src https://go-boringcrypto.storage.googleapis.com/go1.13.15b4.src.tar.gz 21eab29a61a43078cd8bcdbbbb4c82ca049a7e2e211aca0c95f6a306e288db4f
+go1.14.9b4 62cd3338eed7 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.14.9b4.linux-amd64.tar.gz c81946294cbefa7a3abdf47733c720c3454418d6881c137a2e28f18ea40977aa
+go1.14.9b4 62cd3338eed7 src https://go-boringcrypto.storage.googleapis.com/go1.14.9b4.src.tar.gz e9c13c4daa10f6aac80b703f61f7e931af92e92146c8b140ae79e20e4af6bccd
+go1.15.2b5 dbc5602d1839 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.15.2b5.linux-amd64.tar.gz 30c04d854fc8990017ee8c180c1407a4f26c016e3a4134161bbf41c9d16452e3
+go1.15.2b5 dbc5602d1839 src https://go-boringcrypto.storage.googleapis.com/go1.15.2b5.src.tar.gz 67432c0b0a02aa6cc0c49ab285f1c6935a16dadfebd77dfabca7e31907240bc9
+go1.14.10b4 b5fc12785be4 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.14.10b4.linux-amd64.tar.gz d3aa38fb5108b43b155c21529190e73789df6ca0b37feafd43438aefe42f936e
+go1.14.10b4 b5fc12785be4 src https://go-boringcrypto.storage.googleapis.com/go1.14.10b4.src.tar.gz daf7603babc49935efdea5befb2ecad823771523a84d1ba6c0e8c10fac982d59
+go1.15.3b5 ed9dc25d693c linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.15.3b5.linux-amd64.tar.gz 34ec7ec094f5e9349f1612b5f6d8f014b3a7b37b6986aeedcd0fe7cf2dc76a62
+go1.15.3b5 ed9dc25d693c src https://go-boringcrypto.storage.googleapis.com/go1.15.3b5.src.tar.gz bc37727287366aabb47594717cebd0a759147d8b2eb4cd3a45a19317af199fe9
+go1.14.12b4 21ba30ad409a linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.14.12b4.linux-amd64.tar.gz 7f9fb67a3c59fff24e3c51fa2a7435f4195cfb33844c9c2def27c162cc23604b
+go1.14.12b4 21ba30ad409a src https://go-boringcrypto.storage.googleapis.com/go1.14.12b4.src.tar.gz 948d7a77a4a890a7258102bcc7b63890f238061dfb6a4c06033660e727e87fcf
+go1.15.5b5 11087322f85d linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.15.5b5.linux-amd64.tar.gz 9c97488137f1f560b3fff0d8a2a9c45d2de8790fb8952a42b46cc4633528fc48
+go1.15.5b5 11087322f85d src https://go-boringcrypto.storage.googleapis.com/go1.15.5b5.src.tar.gz ee933cb1a4b591794dbcce99740032506af25ee202765dcc6979feb5abc114fc
+go1.14.13b4 2bb8e5a94e8a linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.14.13b4.linux-amd64.tar.gz 8fb6e1cefe5535ab704e1b4e26725095dcca0060490842a54dd93e7cd8b206cd
+go1.14.13b4 2bb8e5a94e8a src https://go-boringcrypto.storage.googleapis.com/go1.14.13b4.src.tar.gz 02e0c4871d12813aee1019bf189b77ccec99dab3a1d5b95ce6abdf85b1810703
+go1.15.6b5 f78276931172 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.15.6b5.linux-amd64.tar.gz 245c500f7da70fb2abd1a6021436ed48e2b97dbbdb394a759b0601dc69cf4e77
+go1.15.6b5 f78276931172 src https://go-boringcrypto.storage.googleapis.com/go1.15.6b5.src.tar.gz 6576a29d019405b14fdc98883fed33c766de2028fbbd3a743a241275275cc7e5
+go1.14.14b4 9cf003256bc3 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.14.14b4.linux-amd64.tar.gz 7df65366d26a13c5be16f87f64e832e86db3b8b9ca1b5c6385e0e20bf79dc82f
+go1.14.14b4 9cf003256bc3 src https://go-boringcrypto.storage.googleapis.com/go1.14.14b4.src.tar.gz aaeda57e2b68ac72783c7aacded814ec660a91c1010c3139156c8e7def86f145
+go1.15.7b5 79ea7a16d7e3 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.15.7b5.linux-amd64.tar.gz cb08962897e3802cda96f4ee915ed20fbde7d5d85e688759ef523d2e6ae44851
+go1.15.7b5 79ea7a16d7e3 src https://go-boringcrypto.storage.googleapis.com/go1.15.7b5.src.tar.gz aa7cb4beff82881cbff4a66e9e07a4004e49384a8fcc95204db9b2f48c12a235
+go1.15.8b5 2a0dd053ecfa linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.15.8b5.linux-amd64.tar.gz 9d897bf42a962b064cfc9bed182c18ade0a3f5857d6a075d93b73ca8fe3b1f3a
+go1.15.8b5 2a0dd053ecfa src https://go-boringcrypto.storage.googleapis.com/go1.15.8b5.src.tar.gz 57964e7762ab03f0ad17bc787585b1709decccf095b7f7d2e9fca61a71e09010
+go1.14.15b4 47419f9cac61 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.14.15b4.linux-amd64.tar.gz 82ba7297d26afcdade439de5621bdcb16e5261877f204aa60d03b5e07223a5c8
+go1.14.15b4 47419f9cac61 src https://go-boringcrypto.storage.googleapis.com/go1.14.15b4.src.tar.gz bf77b15f1d905753648db2d91e39c3a740b67b03dfff511aa25a360a78f9742a
+go1.16b7 67a0be0b437e linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.16b7.linux-amd64.tar.gz 56d4e41d55baece6b98bc66bdf772b0eb17518dd287f27c533225cd154ee0a38
+go1.16b7 67a0be0b437e src https://go-boringcrypto.storage.googleapis.com/go1.16b7.src.tar.gz 7d063cf1cbd252da8b2db54947e5f2f1402ac792e1ea6de76e05ab233f5badbd
+go1.15.9b5 055f1da6e6b9 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.15.9b5.linux-amd64.tar.gz 8e44de7d9d36d68e01c0454841f1becb93d4932bb16a623ed6d4de15ecba1239
+go1.15.9b5 055f1da6e6b9 src https://go-boringcrypto.storage.googleapis.com/go1.15.9b5.src.tar.gz dba0290da6ae46df8d68c6d027b7d6b4775d6dcf8ff9f3cb8a26dbd5b757e696
+go1.16.1b7 b9bd851b1452 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.16.1b7.linux-amd64.tar.gz 963f6a4fb8c5ff7668fb17ba52c3d905466058266556844aee79139f7e3c9521
+go1.16.1b7 b9bd851b1452 src https://go-boringcrypto.storage.googleapis.com/go1.16.1b7.src.tar.gz 8e6849010ae5f3280fea0f6fa6e5b07831ac6e6524a636fab41c0e4f77b529ba
+go1.15.10b5 229a39e34717 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.15.10b5.linux-amd64.tar.gz 7533b0307fd995deb9ef68d67899582c336a3c62387d19d03d10202129e9fad3
+go1.15.10b5 229a39e34717 src https://go-boringcrypto.storage.googleapis.com/go1.15.10b5.src.tar.gz adbaff96b2392a9ab5a20d15fec959983861ec6e554c3c9cd14aec586a0928b3
+go1.16.2b7 6d5f0ffc93e5 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.16.2b7.linux-amd64.tar.gz 2871d90630706eba9d3bd2838ec1c0a367c78c2c4f40e74ed75c294e2c5aa358
+go1.16.2b7 6d5f0ffc93e5 src https://go-boringcrypto.storage.googleapis.com/go1.16.2b7.src.tar.gz 8991c28e30bdd9b34076c2871ab69aac7f306dba08d202aa7301f3adb54ad9f3
+go1.15.11b5 be25192f119e linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.15.11b5.linux-amd64.tar.gz c5aa34a83631b3736bc1ab37027bc4fc22eca2353035586a6255be7e29251f43
+go1.15.11b5 be25192f119e src https://go-boringcrypto.storage.googleapis.com/go1.15.11b5.src.tar.gz 05408824d64ac8ebb6c1d895017e605d45a2c4ebee28995136fe12f4833652d2
+go1.16.3b7 fcee6b930a01 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.16.3b7.linux-amd64.tar.gz afe15efce3c1fecc60994d7ba0d41daaa029fa5810c98737121dde7b38a5e2ac
+go1.16.3b7 fcee6b930a01 src https://go-boringcrypto.storage.googleapis.com/go1.16.3b7.src.tar.gz 5c86175ed86e6ae3826eb827cc51bdda770f22ffaf3258b11135a268153b5057
+go1.16.4b7 25aff96f4b49 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.16.4b7.linux-amd64.tar.gz de60f0620f46b1872813f72646fdece76be94f43c1abe84b69033c26f823a31f
+go1.16.4b7 25aff96f4b49 src https://go-boringcrypto.storage.googleapis.com/go1.16.4b7.src.tar.gz 5b537cf5598bc968764885f4d1f9820578d05d104a6cd7107bb3e443217f4983
+go1.15.12b5 03a15201e7e0 linux-amd64 https://go-boringcrypto.storage.googleapis.com/go1.15.12b5.linux-amd64.tar.gz 9fadc65da7df036bfe702b3f9980e2ca2b184f13d09e8094244f58a866a2f6ee
+go1.15.12b5 03a15201e7e0 src https://go-boringcrypto.storage.googleapis.com/go1.15.12b5.src.tar.gz 81ec958d893f4ecf90111d09ceb79b36492266a39d1918a22e80443e1d399561
diff --git a/misc/boring/VERSION b/misc/boring/VERSION
new file mode 100644 (file)
index 0000000..7f8f011
--- /dev/null
@@ -0,0 +1 @@
+7
diff --git a/misc/boring/build.docker b/misc/boring/build.docker
new file mode 100755 (executable)
index 0000000..6bdf29f
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/bash
+# 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.
+
+# build.docker builds and publishes a Docker image for
+# a given Go+BoringCrypto release.
+
+set -e
+
+# With no arguments, use the most recent linux-amd64 release in the RELEASES file.
+case "$#" in
+0)
+       version=$(grep linux-amd64 RELEASES | tail -1 | awk '{print $1}');;
+1)
+       version="$1";;
+*)
+       echo 'usage: build.docker [version]' >&2
+       exit 2
+esac
+
+url="$(grep "^$version .* linux-amd64 " RELEASES | awk '{print $4}')"
+sha256="$(grep "^$version .* linux-amd64 " RELEASES | awk '{print $5}')"
+if [ "$sha256" = "" ]; then
+       echo "cannot find $version in RELEASES file" >&2
+       exit 2
+fi
+
+# Build a temporary directory with a Dockerfile.
+dir=$(mktemp -d)
+trap "rm -rf $dir" EXIT
+
+if echo "$url" | grep '!' >/dev/null; then
+       # ! is sed delimiter below. Should never happen.
+       echo "URL contains an exclamation mark!" >&2
+       exit 2
+fi
+
+dversion=$(echo "$version" | sed 's/^go//')
+sed "s!UUU!$url!; s/SSS/$sha256/; s/VVV/$dversion/" dockerfile.in >$dir/Dockerfile
+
+docker build --pull -t goboring/golang:$dversion $dir
+docker run goboring/golang:$dversion go version
+docker run goboring/golang:$dversion go tool nm /usr/local/go/bin/go >$dir/nm
+if ! grep crypto/internal/boring/sig.BoringCrypto $dir/nm >/dev/null; then
+       echo 'built docker image but did NOT find sig.BoringCrypto in go command!' >&2
+       exit 2
+fi
+if egrep 'crypto/sha256\.\(\*digest\)' $dir/nm >/dev/null; then
+       echo 'built docker image but DID find sha256.(*digest) in go command unexpectedly!' >&2
+       exit 2
+fi
+docker push goboring/golang:$dversion
+
+echo
+echo published as goboring/golang:$dversion
diff --git a/misc/boring/build.release b/misc/boring/build.release
new file mode 100755 (executable)
index 0000000..46922c9
--- /dev/null
@@ -0,0 +1,104 @@
+#!/bin/bash
+# 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.
+
+# build.release builds and publishes a new Go+BoringCrypto release.
+# After running this script, the change to the RELEASES file should be
+# sent out for review and committed to the repository (but the release
+# is already done, so there's not much to review).
+
+set -e
+
+case "$#" in
+0)
+       rev=HEAD;;
+1)
+       rev="$1";;
+*)
+       echo 'usage: build.release [git-rev]' >&2
+       exit 2
+esac
+
+# Determine commit to use.
+commit=$(git rev-parse "$rev" | awk '{print substr($1, 1, 12)}')
+if [ "$commit" = "" ]; then
+       echo 'cannot find commit in git history' >&2
+       exit 2
+fi
+
+# Determine base Go release from tags.
+base=$(git log --decorate=short --oneline "$rev" | grep 'tag: go' | sed 1q | sed 's/[),].*//; s/.*tag: //')
+if [ "$base" = "" ]; then
+       echo "cannot find go release tag in git history for $rev" >&2
+       exit 2
+fi
+
+# Determine boring crypto version from file.
+boring=$(git show "$commit:misc/boring/VERSION")
+if [ "$boring" = "" ]; then
+       echo "missing BORINGVERSION file in $commit" >&2
+       exit 2
+fi
+
+# Make sure we're not redefining a published release.
+version="${base}b${boring}"
+if grep "^$version " RELEASES >/dev/null; then
+       echo "found $version in RELEASES - not rereleasing" >&2
+       exit 2
+fi
+
+# Show what's going on, while the release builds.
+# Good time for user to type ^C if something is wrong.
+echo >&2
+echo "building $version from $commit" >&2
+echo >&2
+git log -n1 "$commit" >&2
+echo >&2
+
+# Build the release tool in a temporary directory.
+dir=$(mktemp -d)
+trap "rm -rf $dir" EXIT
+export GO111MODULE=on
+export GOBIN="$dir"
+(cd "$dir"; go get golang.org/x/build/cmd/release)
+
+# Build the release.
+sha() {
+    if hash sha256sum 2>/dev/null; then
+        sha256sum "$@"
+    else
+        shasum -a 256 "$@"
+    fi
+}
+shortgo=$(echo "$base" | perl -pe 's/(go\d+\.\d+)(\.\d+|rc\d+)/$1/')
+$dir/release -target linux-amd64 -rev "$commit" -version "$version"
+$dir/release -target src -rev "$commit" -version "$version"
+output="$version.linux-amd64.tar.gz"
+ls -l "$output"
+sha256=$(sha "$output" | awk '{print $1}')
+outputsrc="$version.src.tar.gz"
+ls -l "$outputsrc"
+sha256src=$(sha "$outputsrc" | awk '{print $1}')
+
+trap "rm -f /tmp/go.release.$$ /tmp/go.nm.$$" EXIT
+tar -xzf "$output" -O go/bin/go >/tmp/go.release.$$
+go tool nm /tmp/go.release.$$ >/tmp/go.nm.$$
+if ! grep crypto/internal/boring/sig.BoringCrypto /tmp/go.nm.$$ >/dev/null; then
+       echo 'built release but did NOT find sig.BoringCrypto in go command!' >&2
+       exit 2
+fi
+if egrep 'crypto/sha256\.\(\*digest\)' /tmp/go.nm.$$ >/dev/null; then
+       echo 'built release but DID find sha256.(*digest) in go command unexpectedly!' >&2
+       exit 2
+fi
+
+# Publish the release.
+gsutil cp "$output" gs://go-boringcrypto/
+url="https://go-boringcrypto.storage.googleapis.com/$output"
+gsutil cp "$outputsrc" gs://go-boringcrypto/
+urlsrc="https://go-boringcrypto.storage.googleapis.com/$outputsrc"
+
+# Record that it was published.
+echo "$version $commit linux-amd64 $url $sha256" >>RELEASES
+echo "$version $commit src $urlsrc $sha256src" >>RELEASES
diff --git a/misc/boring/dockerfile.in b/misc/boring/dockerfile.in
new file mode 100644 (file)
index 0000000..b439089
--- /dev/null
@@ -0,0 +1,31 @@
+# Template for Dockerfile, used in build.docker script.
+# Based on https://github.com/docker-library/golang/blob/7e3d99a803/1.13/buster/Dockerfile
+FROM buildpack-deps:buster-scm
+
+# gcc for cgo
+RUN apt-get update && apt-get install -y --no-install-recommends \
+               g++ \
+               gcc \
+               libc6-dev \
+               make \
+               pkg-config \
+       && rm -rf /var/lib/apt/lists/*
+
+ENV GOLANG_VERSION VVV
+
+RUN set -eux; \
+       \
+       url="UUU"; \
+       wget -O go.tgz "$url"; \
+       echo "SSS go.tgz" | sha256sum -c -; \
+       tar -C /usr/local -xzf go.tgz; \
+       rm go.tgz; \
+       \
+       export PATH="/usr/local/go/bin:$PATH"; \
+       go version
+
+ENV GOPATH /go
+ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
+
+RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
+WORKDIR $GOPATH
diff --git a/misc/boring/merge.sh b/misc/boring/merge.sh
new file mode 100755 (executable)
index 0000000..b897a5b
--- /dev/null
@@ -0,0 +1,34 @@
+#! /bin/bash
+set -euo pipefail
+
+if [ "$#" -ne 2 ]; then
+    echo "usage: merge.sh <target branch> <source revision>"
+    echo ""
+    echo "example: merge.sh dev.boringcrypto master"
+    echo "         merge.sh dev.boringcrypto.go1.10 go1.10.7"
+    exit 1
+fi
+
+TARGET="$1"
+SOURCE="$2"
+WORKTREE="$(mktemp -d)"
+BRANCH="boring/merge-$TARGET-$(date +%Y%m%d%H%M%S)"
+
+git fetch
+git worktree add --track -b "$BRANCH" "$WORKTREE" "origin/$TARGET"
+
+cd "$WORKTREE"
+export GIT_GOFMT_HOOK=off
+git merge --no-commit --no-stat "$SOURCE" || echo "Ignoring conflict..."
+[[ -f VERSION ]] && git rm -f VERSION
+git checkout --ours codereview.cfg && git add codereview.cfg
+git commit -m "all: merge $SOURCE into $TARGET"
+
+if ! git log --format=%B -n 1 | grep "\[$TARGET\] "; then
+    echo "The commit does not seem to be targeting the BoringCrypto branch."
+    echo "(Or you are missing the git-codereview hooks.)"
+    exit 1
+fi
+
+git codereview mail -r katie@golang.org,roland@golang.org,filippo@golang.org -trybot -trust HEAD
+cd - && git worktree remove "$WORKTREE"
diff --git a/misc/boring/release.sh b/misc/boring/release.sh
new file mode 100755 (executable)
index 0000000..457ab39
--- /dev/null
@@ -0,0 +1,34 @@
+#! /bin/bash
+set -euo pipefail
+
+if [ "$#" -eq 0 ]; then
+    echo "usage: <target branch> [<target branch> ...]"
+    echo ""
+    echo "example: release.sh dev.boringcrypto.go1.11 dev.boringcrypto.go1.12"
+    exit 1
+fi
+
+# Check that the Docker daemon is available.
+docker ps > /dev/null
+
+WORKTREE="$(mktemp -d)"
+BRANCH="boring/release-$(date +%Y%m%d%H%M%S)"
+
+git fetch
+git worktree add --track -b "$BRANCH" "$WORKTREE" origin/dev.boringcrypto
+
+cd "$WORKTREE/src"
+./make.bash
+
+cd ../misc/boring
+for branch in "$@"; do
+    ./build.release "origin/$branch"
+    ./build.docker
+done
+
+git add RELEASES
+git commit -m "misc/boring: add new releases to RELEASES file"
+git codereview mail -r katie@golang.org,roland@golang.org,filippo@golang.org -trust
+
+rm *.tar.gz
+cd - && git worktree remove "$WORKTREE"
index 01eaf26a0a62e905ce8ff79c6402a2870244d8ed..034a092d6ceaac88f05b164b598cc3097a043c15 100644 (file)
@@ -1130,6 +1130,33 @@ func writeType(t *types.Type) *obj.LSym {
        // for security, only the exported fields.
        case types.TSTRUCT:
                fields := t.Fields().Slice()
+
+               // omitFieldForAwfulBoringCryptoKludge reports whether
+               // the field t should be omitted from the reflect data.
+               // In the crypto/... packages we omit an unexported field
+               // named "boring", to keep from breaking client code that
+               // expects rsa.PublicKey etc to have only public fields.
+               // As the name suggests, this is an awful kludge, but it is
+               // limited to the dev.boringcrypto branch and avoids
+               // much more invasive effects elsewhere.
+               omitFieldForAwfulBoringCryptoKludge := func(t *types.Field) bool {
+                       if t.Sym == nil || t.Sym.Name != "boring" || t.Sym.Pkg == nil {
+                               return false
+                       }
+                       path := t.Sym.Pkg.Path
+                       if t.Sym.Pkg == types.LocalPkg {
+                               path = base.Ctxt.Pkgpath
+                       }
+                       return strings.HasPrefix(path, "crypto/")
+               }
+               newFields := fields[:0:0]
+               for _, t1 := range fields {
+                       if !omitFieldForAwfulBoringCryptoKludge(t1) {
+                               newFields = append(newFields, t1)
+                       }
+               }
+               fields = newFields
+
                for _, t1 := range fields {
                        writeType(t1.Type)
                }
diff --git a/src/cmd/go/go_boring_test.go b/src/cmd/go/go_boring_test.go
new file mode 100644 (file)
index 0000000..0000497
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 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.
+
+package main_test
+
+import "testing"
+
+func TestBoringInternalLink(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.parallel()
+       tg.tempFile("main.go", `package main
+               import "crypto/sha1"
+               func main() {
+                       sha1.New()
+               }`)
+       tg.run("build", "-ldflags=-w -extld=false", tg.path("main.go"))
+       tg.run("build", "-ldflags=-extld=false", tg.path("main.go"))
+}
index a059a6dd902a8ee0e7e5832cf8671dbdb5c3aab0..52b11fbb20d3e2c2dda4092daced867baa37a658 100644 (file)
@@ -1843,8 +1843,12 @@ func TestBinaryOnlyPackages(t *testing.T) {
        tg.grepStdout("p2: false", "p2 listed as BinaryOnly")
 }
 
-// Issue 16050.
-func TestAlwaysLinkSysoFiles(t *testing.T) {
+// Issue 16050 and 21884.
+func TestLinkSysoFiles(t *testing.T) {
+       if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+               t.Skip("not linux/amd64")
+       }
+
        tg := testgo(t)
        defer tg.cleanup()
        tg.parallel()
@@ -1863,6 +1867,10 @@ func TestAlwaysLinkSysoFiles(t *testing.T) {
        tg.setenv("CGO_ENABLED", "0")
        tg.run("list", "-f", "{{.SysoFiles}}", "syso")
        tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=0")
+
+       tg.setenv("CGO_ENABLED", "1")
+       tg.run("list", "-msan", "-f", "{{.SysoFiles}}", "syso")
+       tg.grepStdoutNot("a.syso", "unexpected syso file with -msan")
 }
 
 // Issue 16120.
index 153399d83e6ac68412c695cfa0253922713ca546..fa040bf5b11f643faf433a40a0954fd9a8c8cf19 100644 (file)
@@ -381,6 +381,12 @@ func (p *Package) copyBuild(opts PackageOpts, pp *build.Package) {
        p.SwigFiles = pp.SwigFiles
        p.SwigCXXFiles = pp.SwigCXXFiles
        p.SysoFiles = pp.SysoFiles
+       if cfg.BuildMSan {
+               // There's no way for .syso files to be built both with and without
+               // support for memory sanitizer. Assume they are built without,
+               // and drop them.
+               p.SysoFiles = nil
+       }
        p.CgoCFLAGS = pp.CgoCFLAGS
        p.CgoCPPFLAGS = pp.CgoCPPFLAGS
        p.CgoCXXFLAGS = pp.CgoCXXFLAGS
index e8f001ba8ec095f5e3e73a363db3b4537ee025a3..eb85c88fbfbfb1368fed927cdfa27e7b0f9c6373 100644 (file)
@@ -1007,6 +1007,7 @@ var hostobj []Hostobj
 // These packages can use internal linking mode.
 // Others trigger external mode.
 var internalpkg = []string{
+       "crypto/internal/boring",
        "crypto/x509",
        "net",
        "os/user",
index bb93fbb36e289abfff7bf9b6341acf7769e719d3..29d01796eb398fe5842e5696f933b0f91b8a35c9 100644 (file)
@@ -10,6 +10,8 @@ import (
        "strconv"
 )
 
+import "crypto/internal/boring"
+
 // The AES block size in bytes.
 const BlockSize = 16
 
@@ -37,6 +39,9 @@ func NewCipher(key []byte) (cipher.Block, error) {
        case 16, 24, 32:
                break
        }
+       if boring.Enabled {
+               return boring.NewAESCipher(key)
+       }
        return newCipher(key)
 }
 
index 4251805ef9b5a0f67880fdc34abca0091d3fcc06..846f56ab56fd73c10ca6c75ba7d01d6340725596 100644 (file)
@@ -13,6 +13,8 @@ import (
        "internal/cpu"
 )
 
+import "crypto/internal/boring"
+
 // defined in asm_*.s
 
 //go:noescape
@@ -57,6 +59,7 @@ func newCipher(key []byte) (cipher.Block, error) {
 func (c *aesCipherAsm) BlockSize() int { return BlockSize }
 
 func (c *aesCipherAsm) Encrypt(dst, src []byte) {
+       boring.Unreachable()
        if len(src) < BlockSize {
                panic("crypto/aes: input not full block")
        }
@@ -70,6 +73,7 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) {
 }
 
 func (c *aesCipherAsm) Decrypt(dst, src []byte) {
+       boring.Unreachable()
        if len(src) < BlockSize {
                panic("crypto/aes: input not full block")
        }
diff --git a/src/crypto/boring/boring.go b/src/crypto/boring/boring.go
new file mode 100644 (file)
index 0000000..19e2a08
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2020 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.
+
+// Package boring exposes functions that are only available when building with
+// Go+BoringCrypto. This package is available on all targets as long as the
+// Go+BoringCrypto toolchain is used. Use the Enabled function to determine
+// whether the BoringCrypto core is actually in use.
+//
+// Any time the Go+BoringCrypto toolchain is used, the "boringcrypto" build tag
+// is satisfied, so that applications can tag files that use this package.
+package boring
+
+import "crypto/internal/boring"
+
+// Enabled reports whether BoringCrypto handles supported crypto operations.
+func Enabled() bool {
+       return boring.Enabled
+}
diff --git a/src/crypto/boring/boring_test.go b/src/crypto/boring/boring_test.go
new file mode 100644 (file)
index 0000000..ace50de
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2020 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.
+
+package boring_test
+
+import (
+       "crypto/boring"
+       "runtime"
+       "testing"
+)
+
+func TestEnabled(t *testing.T) {
+       supportedPlatform := runtime.GOOS == "linux" && runtime.GOARCH == "amd64"
+       if supportedPlatform && !boring.Enabled() {
+               t.Error("Enabled returned false on a supported platform")
+       } else if !supportedPlatform && boring.Enabled() {
+               t.Error("Enabled returned true on an unsupported platform")
+       }
+}
diff --git a/src/crypto/boring/notboring_test.go b/src/crypto/boring/notboring_test.go
new file mode 100644 (file)
index 0000000..385a384
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2020 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.
+
+// +build !boringcrypto
+
+package boring_test
+
+import "testing"
+
+func TestNotBoring(t *testing.T) {
+       t.Error("a file tagged !boringcrypto should not build under Go+BoringCrypto")
+}
diff --git a/src/crypto/ecdsa/boring.go b/src/crypto/ecdsa/boring.go
new file mode 100644 (file)
index 0000000..fa15ecb
--- /dev/null
@@ -0,0 +1,100 @@
+// 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.
+
+package ecdsa
+
+import (
+       "crypto/internal/boring"
+       "math/big"
+       "sync/atomic"
+       "unsafe"
+)
+
+// Cached conversions from Go PublicKey/PrivateKey to BoringCrypto.
+//
+// A new 'boring atomic.Value' field in both PublicKey and PrivateKey
+// serves as a cache for the most recent conversion. The cache is an
+// atomic.Value because code might reasonably set up a key and then
+// (thinking it immutable) use it from multiple goroutines simultaneously.
+// The first operation initializes the cache; if there are multiple simultaneous
+// first operations, they will do redundant work but not step on each other.
+//
+// We could just assume that once used in a Sign or Verify operation,
+// a particular key is never again modified, but that has not been a
+// stated assumption before. Just in case there is any existing code that
+// does modify the key between operations, we save the original values
+// alongside the cached BoringCrypto key and check that the real key
+// still matches before using the cached key. The theory is that the real
+// operations are significantly more expensive than the comparison.
+
+type boringPub struct {
+       key  *boring.PublicKeyECDSA
+       orig PublicKey
+}
+
+func boringPublicKey(pub *PublicKey) (*boring.PublicKeyECDSA, error) {
+       b := (*boringPub)(atomic.LoadPointer(&pub.boring))
+       if b != nil && publicKeyEqual(&b.orig, pub) {
+               return b.key, nil
+       }
+
+       b = new(boringPub)
+       b.orig = copyPublicKey(pub)
+       key, err := boring.NewPublicKeyECDSA(b.orig.Curve.Params().Name, b.orig.X, b.orig.Y)
+       if err != nil {
+               return nil, err
+       }
+       b.key = key
+       atomic.StorePointer(&pub.boring, unsafe.Pointer(b))
+       return key, nil
+}
+
+type boringPriv struct {
+       key  *boring.PrivateKeyECDSA
+       orig PrivateKey
+}
+
+func boringPrivateKey(priv *PrivateKey) (*boring.PrivateKeyECDSA, error) {
+       b := (*boringPriv)(atomic.LoadPointer(&priv.boring))
+       if b != nil && privateKeyEqual(&b.orig, priv) {
+               return b.key, nil
+       }
+
+       b = new(boringPriv)
+       b.orig = copyPrivateKey(priv)
+       key, err := boring.NewPrivateKeyECDSA(b.orig.Curve.Params().Name, b.orig.X, b.orig.Y, b.orig.D)
+       if err != nil {
+               return nil, err
+       }
+       b.key = key
+       atomic.StorePointer(&priv.boring, unsafe.Pointer(b))
+       return key, nil
+}
+
+func publicKeyEqual(k1, k2 *PublicKey) bool {
+       return k1.X != nil &&
+               k1.Curve.Params() == k2.Curve.Params() &&
+               k1.X.Cmp(k2.X) == 0 &&
+               k1.Y.Cmp(k2.Y) == 0
+}
+
+func privateKeyEqual(k1, k2 *PrivateKey) bool {
+       return publicKeyEqual(&k1.PublicKey, &k2.PublicKey) &&
+               k1.D.Cmp(k2.D) == 0
+}
+
+func copyPublicKey(k *PublicKey) PublicKey {
+       return PublicKey{
+               Curve: k.Curve,
+               X:     new(big.Int).Set(k.X),
+               Y:     new(big.Int).Set(k.Y),
+       }
+}
+
+func copyPrivateKey(k *PrivateKey) PrivateKey {
+       return PrivateKey{
+               PublicKey: copyPublicKey(&k.PublicKey),
+               D:         new(big.Int).Set(k.D),
+       }
+}
index 219436935f2c96f4bcf5c7943b173c7c90f06f44..1a7635ec2be3364981b845f298f989c4c267fb0e 100644 (file)
@@ -41,6 +41,11 @@ import (
        "golang.org/x/crypto/cryptobyte/asn1"
 )
 
+import (
+       "crypto/internal/boring"
+       "unsafe"
+)
+
 // A invertible implements fast inverse mod Curve.Params().N
 type invertible interface {
        // Inverse returns the inverse of k in GF(P)
@@ -60,6 +65,8 @@ const (
 type PublicKey struct {
        elliptic.Curve
        X, Y *big.Int
+
+       boring unsafe.Pointer
 }
 
 // Any methods implemented on PublicKey might need to also be implemented on
@@ -87,6 +94,8 @@ func (pub *PublicKey) Equal(x crypto.PublicKey) bool {
 type PrivateKey struct {
        PublicKey
        D *big.Int
+
+       boring unsafe.Pointer
 }
 
 // Public returns the public key corresponding to priv.
@@ -113,6 +122,15 @@ func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool {
 // where the private part is kept in, for example, a hardware module. Common
 // uses should use the Sign function in this package directly.
 func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
+       if boring.Enabled && rand == boring.RandReader {
+               b, err := boringPrivateKey(priv)
+               if err != nil {
+                       return nil, err
+               }
+               return boring.SignMarshalECDSA(b, digest)
+       }
+       boring.UnreachableExceptTests()
+
        r, s, err := Sign(rand, priv, digest)
        if err != nil {
                return nil, err
@@ -147,6 +165,15 @@ func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error)
 
 // GenerateKey generates a public and private key pair.
 func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
+       if boring.Enabled && rand == boring.RandReader {
+               x, y, d, err := boring.GenerateKeyECDSA(c.Params().Name)
+               if err != nil {
+                       return nil, err
+               }
+               return &PrivateKey{PublicKey: PublicKey{Curve: c, X: x, Y: y}, D: d}, nil
+       }
+       boring.UnreachableExceptTests()
+
        k, err := randFieldElement(c, rand)
        if err != nil {
                return nil, err
@@ -200,6 +227,15 @@ var errZeroParam = errors.New("zero parameter")
 func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
        randutil.MaybeReadByte(rand)
 
+       if boring.Enabled && rand == boring.RandReader {
+               b, err := boringPrivateKey(priv)
+               if err != nil {
+                       return nil, nil, err
+               }
+               return boring.SignECDSA(b, hash)
+       }
+       boring.UnreachableExceptTests()
+
        // Get min(log2(q) / 2, 256) bits of entropy from rand.
        entropylen := (priv.Curve.Params().BitSize + 7) / 16
        if entropylen > 32 {
@@ -289,6 +325,15 @@ func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
 // Verify verifies the signature in r, s of hash using the public key, pub. Its
 // return value records whether the signature is valid.
 func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
+       if boring.Enabled {
+               b, err := boringPublicKey(pub)
+               if err != nil {
+                       return false
+               }
+               return boring.VerifyECDSA(b, hash, r, s)
+       }
+       boring.UnreachableExceptTests()
+
        // See [NSA] 3.4.2
        c := pub.Curve
        N := c.Params().N
index 8a973b36eafb7b3b57923d72e700b97b6062c64f..84fdc3ca8b59fcf219fde18bf6b98c925872b2d8 100644 (file)
@@ -186,6 +186,7 @@ func TestMalleability(t *testing.T) {
 }
 
 func TestAllocations(t *testing.T) {
+       t.Skip("skipping allocations test on Go+BoringCrypto, as cgo causes allocations")
        if strings.HasSuffix(os.Getenv("GO_BUILDER_NAME"), "-noopt") {
                t.Skip("skipping allocations test without relevant optimizations")
        }
index 8031256525a53487fcadfbcfee4f971abe9611d0..69fdcfea7ab22a1c52f18a88de716f3eb2911b69 100644 (file)
@@ -281,6 +281,7 @@ func TestNonCanonicalPoints(t *testing.T) {
 var testAllocationsSink byte
 
 func TestAllocations(t *testing.T) {
+       t.Skip("skipping allocations test on Go+BoringCrypto, as cgo causes allocations")
        if strings.HasSuffix(os.Getenv("GO_BUILDER_NAME"), "-noopt") {
                t.Skip("skipping allocations test without relevant optimizations")
        }
index cdda33c2cbac2dc55c63e71858e01bffda5a8a82..34805765d550c17234bafc0fc7e8215bbb70b81b 100644 (file)
@@ -26,6 +26,8 @@ import (
        "hash"
 )
 
+import "crypto/internal/boring"
+
 // FIPS 198-1:
 // https://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf
 
@@ -126,6 +128,13 @@ func (h *hmac) Reset() {
 // the returned Hash does not implement encoding.BinaryMarshaler
 // or encoding.BinaryUnmarshaler.
 func New(h func() hash.Hash, key []byte) hash.Hash {
+       if boring.Enabled {
+               hm := boring.NewHMAC(h, key)
+               if hm != nil {
+                       return hm
+               }
+               // BoringCrypto did not recognize h, so fall through to standard Go code.
+       }
        hm := new(hmac)
        hm.outer = h()
        hm.inner = h()
index 25e67d7fe5325f72f90a60df452cd6e7d5e25fbe..55415abf020799c4120705d061aac7d6b7e4f3b7 100644 (file)
@@ -5,6 +5,8 @@
 package hmac
 
 import (
+       "bytes"
+       "crypto/internal/boring"
        "crypto/md5"
        "crypto/sha1"
        "crypto/sha256"
@@ -518,6 +520,31 @@ var hmacTests = []hmacTest{
                sha512.Size,
                sha512.BlockSize,
        },
+       // HMAC without key is dumb but should probably not fail.
+       {
+               sha1.New,
+               []byte{},
+               []byte("message"),
+               "d5d1ed05121417247616cfc8378f360a39da7cfa",
+               sha1.Size,
+               sha1.BlockSize,
+       },
+       {
+               sha256.New,
+               []byte{},
+               []byte("message"),
+               "eb08c1f56d5ddee07f7bdf80468083da06b64cf4fac64fe3a90883df5feacae4",
+               sha256.Size,
+               sha256.BlockSize,
+       },
+       {
+               sha512.New,
+               []byte{},
+               []byte("message"),
+               "08fce52f6395d59c2a3fb8abb281d74ad6f112b9a9c787bcea290d94dadbc82b2ca3e5e12bf2277c7fedbb0154d5493e41bb7459f63c8e39554ea3651b812492",
+               sha512.Size,
+               sha512.BlockSize,
+       },
 }
 
 func TestHMAC(t *testing.T) {
@@ -557,6 +584,9 @@ func TestHMAC(t *testing.T) {
 }
 
 func TestNonUniqueHash(t *testing.T) {
+       if boring.Enabled {
+               t.Skip("hash.Hash provided by boringcrypto are not comparable")
+       }
        sha := sha256.New()
        defer func() {
                err := recover()
@@ -591,6 +621,42 @@ func TestEqual(t *testing.T) {
        }
 }
 
+func TestWriteAfterSum(t *testing.T) {
+       h := New(sha1.New, nil)
+       h.Write([]byte("hello"))
+       sumHello := h.Sum(nil)
+
+       h = New(sha1.New, nil)
+       h.Write([]byte("hello world"))
+       sumHelloWorld := h.Sum(nil)
+
+       // Test that Sum has no effect on future Sum or Write operations.
+       // This is a bit unusual as far as usage, but it's allowed
+       // by the definition of Go hash.Hash, and some clients expect it to work.
+       h = New(sha1.New, nil)
+       h.Write([]byte("hello"))
+       if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
+               t.Fatalf("1st Sum after hello = %x, want %x", sum, sumHello)
+       }
+       if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
+               t.Fatalf("2nd Sum after hello = %x, want %x", sum, sumHello)
+       }
+
+       h.Write([]byte(" world"))
+       if sum := h.Sum(nil); !bytes.Equal(sum, sumHelloWorld) {
+               t.Fatalf("1st Sum after hello world = %x, want %x", sum, sumHelloWorld)
+       }
+       if sum := h.Sum(nil); !bytes.Equal(sum, sumHelloWorld) {
+               t.Fatalf("2nd Sum after hello world = %x, want %x", sum, sumHelloWorld)
+       }
+
+       h.Reset()
+       h.Write([]byte("hello"))
+       if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
+               t.Fatalf("Sum after Reset + hello = %x, want %x", sum, sumHello)
+       }
+}
+
 func BenchmarkHMACSHA256_1K(b *testing.B) {
        key := make([]byte, 32)
        buf := make([]byte, 1024)
diff --git a/src/crypto/internal/boring/Dockerfile b/src/crypto/internal/boring/Dockerfile
new file mode 100644 (file)
index 0000000..811a6dc
--- /dev/null
@@ -0,0 +1,42 @@
+# Copyright 2020 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.
+
+# This Docker image builds goboringcrypto_linux_amd64.syso according to the
+# Security Policy. To use it, build the image, run it, and then extract
+# /boring/godriver/goboringcrypto_linux_amd64.syso.
+#
+#   $ docker build -t goboring:140sp3678 .
+#   $ docker run -it --name goboring-140sp3678 goboring:140sp3678
+#   $ docker cp goboring-140sp3678:/boring/godriver/goboringcrypto_linux_amd64.syso .
+#   $ sha256sum goboringcrypto_linux_amd64.syso # compare to docker output
+
+FROM ubuntu:focal
+
+RUN mkdir /boring
+WORKDIR /boring
+
+# Following 140sp3678.pdf [0] page 19, install clang 7.0.1, Go 1.12.7, and
+# Ninja 1.9.0, then download and verify BoringSSL.
+#
+# [0]: https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp3678.pdf
+
+RUN apt-get update && \
+        apt-get install --no-install-recommends -y cmake xz-utils wget unzip ca-certificates clang-7
+RUN wget https://github.com/ninja-build/ninja/releases/download/v1.9.0/ninja-linux.zip && \
+        unzip ninja-linux.zip && \
+        rm ninja-linux.zip && \
+        mv ninja /usr/local/bin/
+RUN wget https://golang.org/dl/go1.12.7.linux-amd64.tar.gz && \
+        tar -C /usr/local -xzf go1.12.7.linux-amd64.tar.gz && \
+        rm go1.12.7.linux-amd64.tar.gz && \
+        ln -s /usr/local/go/bin/go /usr/local/bin/
+
+RUN wget https://commondatastorage.googleapis.com/chromium-boringssl-fips/boringssl-ae223d6138807a13006342edfeef32e813246b39.tar.xz
+RUN [ "$(sha256sum boringssl-ae223d6138807a13006342edfeef32e813246b39.tar.xz | awk '{print $1}')" = \
+        3b5fdf23274d4179c2077b5e8fa625d9debd7a390aac1d165b7e47234f648bb8 ]
+
+ADD goboringcrypto.h /boring/godriver/goboringcrypto.h
+ADD build.sh /boring/build.sh
+
+ENTRYPOINT ["/boring/build.sh"]
diff --git a/src/crypto/internal/boring/LICENSE b/src/crypto/internal/boring/LICENSE
new file mode 100644 (file)
index 0000000..fc103a7
--- /dev/null
@@ -0,0 +1,200 @@
+The Go source code and supporting files in this directory
+are covered by the usual Go license (see ../../../../LICENSE).
+
+The goboringcrypto_linux_amd64.syso object file is built
+from BoringSSL source code by build/build.sh and is covered
+by the BoringSSL license reproduced below and also at
+https://boringssl.googlesource.com/boringssl/+/fips-20190808/LICENSE.
+
+BoringSSL is a fork of OpenSSL. As such, large parts of it fall under OpenSSL
+licensing. Files that are completely new have a Google copyright and an ISC
+license. This license is reproduced at the bottom of this file.
+
+Contributors to BoringSSL are required to follow the CLA rules for Chromium:
+https://cla.developers.google.com/clas
+
+Some files from Intel are under yet another license, which is also included
+underneath.
+
+The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the
+OpenSSL License and the original SSLeay license apply to the toolkit. See below
+for the actual license texts. Actually both licenses are BSD-style Open Source
+licenses. In case of any license issues related to OpenSSL please contact
+openssl-core@openssl.org.
+
+The following are Google-internal bug numbers where explicit permission from
+some authors is recorded for use of their work. (This is purely for our own
+record keeping.)
+  27287199
+  27287880
+  27287883
+
+  OpenSSL License
+  ---------------
+
+/* ====================================================================
+ * Copyright (c) 1998-2011 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+ Original SSLeay License
+ -----------------------
+
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+
+ISC license used for completely new code in BoringSSL:
+
+/* Copyright (c) 2015, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+
+Some files from Intel carry the following license:
+
+# Copyright (c) 2012, Intel Corporation
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# *  Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#
+# *  Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the
+#    distribution.
+#
+# *  Neither the name of the Intel Corporation nor the names of its
+#    contributors may be used to endorse or promote products derived from
+#    this software without specific prior written permission.
+#
+#
+# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/crypto/internal/boring/aes.go b/src/crypto/internal/boring/aes.go
new file mode 100644 (file)
index 0000000..504a841
--- /dev/null
@@ -0,0 +1,391 @@
+// 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.
+
+// +build linux,amd64
+// +build !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boring
+
+/*
+
+#include "goboringcrypto.h"
+
+// These wrappers allocate out_len on the C stack, and check that it matches the expected
+// value, to avoid having to pass a pointer from Go, which would escape to the heap.
+
+int EVP_AEAD_CTX_seal_wrapper(const GO_EVP_AEAD_CTX *ctx, uint8_t *out,
+                                                         size_t exp_out_len,
+                                                         const uint8_t *nonce, size_t nonce_len,
+                                                         const uint8_t *in, size_t in_len,
+                                                         const uint8_t *ad, size_t ad_len) {
+       size_t out_len;
+       int ok = _goboringcrypto_EVP_AEAD_CTX_seal(ctx, out, &out_len, exp_out_len,
+               nonce, nonce_len, in, in_len, ad, ad_len);
+       if (out_len != exp_out_len) {
+               return 0;
+       }
+       return ok;
+};
+
+int EVP_AEAD_CTX_open_wrapper(const GO_EVP_AEAD_CTX *ctx, uint8_t *out,
+                                                         size_t exp_out_len,
+                                                         const uint8_t *nonce, size_t nonce_len,
+                                                         const uint8_t *in, size_t in_len,
+                                                         const uint8_t *ad, size_t ad_len) {
+       size_t out_len;
+       int ok = _goboringcrypto_EVP_AEAD_CTX_open(ctx, out, &out_len, exp_out_len,
+               nonce, nonce_len, in, in_len, ad, ad_len);
+       if (out_len != exp_out_len) {
+               return 0;
+       }
+       return ok;
+};
+
+*/
+import "C"
+import (
+       "crypto/cipher"
+       "errors"
+       "runtime"
+       "strconv"
+       "unsafe"
+)
+
+type aesKeySizeError int
+
+func (k aesKeySizeError) Error() string {
+       return "crypto/aes: invalid key size " + strconv.Itoa(int(k))
+}
+
+const aesBlockSize = 16
+
+type aesCipher struct {
+       key []byte
+       enc C.GO_AES_KEY
+       dec C.GO_AES_KEY
+}
+
+type extraModes interface {
+       // Copied out of crypto/aes/modes.go.
+       NewCBCEncrypter(iv []byte) cipher.BlockMode
+       NewCBCDecrypter(iv []byte) cipher.BlockMode
+       NewCTR(iv []byte) cipher.Stream
+       NewGCM(nonceSize, tagSize int) (cipher.AEAD, error)
+
+       // Invented for BoringCrypto.
+       NewGCMTLS() (cipher.AEAD, error)
+}
+
+var _ extraModes = (*aesCipher)(nil)
+
+func NewAESCipher(key []byte) (cipher.Block, error) {
+       c := &aesCipher{key: make([]byte, len(key))}
+       copy(c.key, key)
+       // Note: 0 is success, contradicting the usual BoringCrypto convention.
+       if C._goboringcrypto_AES_set_decrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.dec) != 0 ||
+               C._goboringcrypto_AES_set_encrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.enc) != 0 {
+               return nil, aesKeySizeError(len(key))
+       }
+       return c, nil
+}
+
+func (c *aesCipher) BlockSize() int { return aesBlockSize }
+
+func (c *aesCipher) Encrypt(dst, src []byte) {
+       if inexactOverlap(dst, src) {
+               panic("crypto/cipher: invalid buffer overlap")
+       }
+       if len(src) < aesBlockSize {
+               panic("crypto/aes: input not full block")
+       }
+       if len(dst) < aesBlockSize {
+               panic("crypto/aes: output not full block")
+       }
+       C._goboringcrypto_AES_encrypt(
+               (*C.uint8_t)(unsafe.Pointer(&src[0])),
+               (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+               &c.enc)
+}
+
+func (c *aesCipher) Decrypt(dst, src []byte) {
+       if inexactOverlap(dst, src) {
+               panic("crypto/cipher: invalid buffer overlap")
+       }
+       if len(src) < aesBlockSize {
+               panic("crypto/aes: input not full block")
+       }
+       if len(dst) < aesBlockSize {
+               panic("crypto/aes: output not full block")
+       }
+       C._goboringcrypto_AES_decrypt(
+               (*C.uint8_t)(unsafe.Pointer(&src[0])),
+               (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+               &c.dec)
+}
+
+type aesCBC struct {
+       key  *C.GO_AES_KEY
+       mode C.int
+       iv   [aesBlockSize]byte
+}
+
+func (x *aesCBC) BlockSize() int { return aesBlockSize }
+
+func (x *aesCBC) CryptBlocks(dst, src []byte) {
+       if inexactOverlap(dst, src) {
+               panic("crypto/cipher: invalid buffer overlap")
+       }
+       if len(src)%aesBlockSize != 0 {
+               panic("crypto/cipher: input not full blocks")
+       }
+       if len(dst) < len(src) {
+               panic("crypto/cipher: output smaller than input")
+       }
+       if len(src) > 0 {
+               C._goboringcrypto_AES_cbc_encrypt(
+                       (*C.uint8_t)(unsafe.Pointer(&src[0])),
+                       (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+                       C.size_t(len(src)), x.key,
+                       (*C.uint8_t)(unsafe.Pointer(&x.iv[0])), x.mode)
+       }
+}
+
+func (x *aesCBC) SetIV(iv []byte) {
+       if len(iv) != aesBlockSize {
+               panic("cipher: incorrect length IV")
+       }
+       copy(x.iv[:], iv)
+}
+
+func (c *aesCipher) NewCBCEncrypter(iv []byte) cipher.BlockMode {
+       x := &aesCBC{key: &c.enc, mode: C.GO_AES_ENCRYPT}
+       copy(x.iv[:], iv)
+       return x
+}
+
+func (c *aesCipher) NewCBCDecrypter(iv []byte) cipher.BlockMode {
+       x := &aesCBC{key: &c.dec, mode: C.GO_AES_DECRYPT}
+       copy(x.iv[:], iv)
+       return x
+}
+
+type aesCTR struct {
+       key        *C.GO_AES_KEY
+       iv         [aesBlockSize]byte
+       num        C.uint
+       ecount_buf [16]C.uint8_t
+}
+
+func (x *aesCTR) XORKeyStream(dst, src []byte) {
+       if inexactOverlap(dst, src) {
+               panic("crypto/cipher: invalid buffer overlap")
+       }
+       if len(dst) < len(src) {
+               panic("crypto/cipher: output smaller than input")
+       }
+       if len(src) == 0 {
+               return
+       }
+       C._goboringcrypto_AES_ctr128_encrypt(
+               (*C.uint8_t)(unsafe.Pointer(&src[0])),
+               (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+               C.size_t(len(src)), x.key, (*C.uint8_t)(unsafe.Pointer(&x.iv[0])),
+               &x.ecount_buf[0], &x.num)
+}
+
+func (c *aesCipher) NewCTR(iv []byte) cipher.Stream {
+       x := &aesCTR{key: &c.enc}
+       copy(x.iv[:], iv)
+       return x
+}
+
+type aesGCM struct {
+       ctx  C.GO_EVP_AEAD_CTX
+       aead *C.GO_EVP_AEAD
+}
+
+const (
+       gcmBlockSize         = 16
+       gcmTagSize           = 16
+       gcmStandardNonceSize = 12
+)
+
+type aesNonceSizeError int
+
+func (n aesNonceSizeError) Error() string {
+       return "crypto/aes: invalid GCM nonce size " + strconv.Itoa(int(n))
+}
+
+type noGCM struct {
+       cipher.Block
+}
+
+func (c *aesCipher) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
+       if nonceSize != gcmStandardNonceSize && tagSize != gcmTagSize {
+               return nil, errors.New("crypto/aes: GCM tag and nonce sizes can't be non-standard at the same time")
+       }
+       // Fall back to standard library for GCM with non-standard nonce or tag size.
+       if nonceSize != gcmStandardNonceSize {
+               return cipher.NewGCMWithNonceSize(&noGCM{c}, nonceSize)
+       }
+       if tagSize != gcmTagSize {
+               return cipher.NewGCMWithTagSize(&noGCM{c}, tagSize)
+       }
+       return c.newGCM(false)
+}
+
+func (c *aesCipher) NewGCMTLS() (cipher.AEAD, error) {
+       return c.newGCM(true)
+}
+
+func (c *aesCipher) newGCM(tls bool) (cipher.AEAD, error) {
+       var aead *C.GO_EVP_AEAD
+       switch len(c.key) * 8 {
+       case 128:
+               if tls {
+                       aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls12()
+               } else {
+                       aead = C._goboringcrypto_EVP_aead_aes_128_gcm()
+               }
+       case 256:
+               if tls {
+                       aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls12()
+               } else {
+                       aead = C._goboringcrypto_EVP_aead_aes_256_gcm()
+               }
+       default:
+               // Fall back to standard library for GCM with non-standard key size.
+               return cipher.NewGCMWithNonceSize(&noGCM{c}, gcmStandardNonceSize)
+       }
+
+       g := &aesGCM{aead: aead}
+       if C._goboringcrypto_EVP_AEAD_CTX_init(&g.ctx, aead, (*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.size_t(len(c.key)), C.GO_EVP_AEAD_DEFAULT_TAG_LENGTH, nil) == 0 {
+               return nil, fail("EVP_AEAD_CTX_init")
+       }
+       // Note: Because of the finalizer, any time g.ctx is passed to cgo,
+       // that call must be followed by a call to runtime.KeepAlive(g),
+       // to make sure g is not collected (and finalized) before the cgo
+       // call returns.
+       runtime.SetFinalizer(g, (*aesGCM).finalize)
+       if g.NonceSize() != gcmStandardNonceSize {
+               panic("boringcrypto: internal confusion about nonce size")
+       }
+       if g.Overhead() != gcmTagSize {
+               panic("boringcrypto: internal confusion about tag size")
+       }
+
+       return g, nil
+}
+
+func (g *aesGCM) finalize() {
+       C._goboringcrypto_EVP_AEAD_CTX_cleanup(&g.ctx)
+}
+
+func (g *aesGCM) NonceSize() int {
+       return int(C._goboringcrypto_EVP_AEAD_nonce_length(g.aead))
+}
+
+func (g *aesGCM) Overhead() int {
+       return int(C._goboringcrypto_EVP_AEAD_max_overhead(g.aead))
+}
+
+// base returns the address of the underlying array in b,
+// being careful not to panic when b has zero length.
+func base(b []byte) *C.uint8_t {
+       if len(b) == 0 {
+               return nil
+       }
+       return (*C.uint8_t)(unsafe.Pointer(&b[0]))
+}
+
+func (g *aesGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+       if len(nonce) != gcmStandardNonceSize {
+               panic("cipher: incorrect nonce length given to GCM")
+       }
+       if uint64(len(plaintext)) > ((1<<32)-2)*aesBlockSize || len(plaintext)+gcmTagSize < len(plaintext) {
+               panic("cipher: message too large for GCM")
+       }
+       if len(dst)+len(plaintext)+gcmTagSize < len(dst) {
+               panic("cipher: message too large for buffer")
+       }
+
+       // Make room in dst to append plaintext+overhead.
+       n := len(dst)
+       for cap(dst) < n+len(plaintext)+gcmTagSize {
+               dst = append(dst[:cap(dst)], 0)
+       }
+       dst = dst[:n+len(plaintext)+gcmTagSize]
+
+       // Check delayed until now to make sure len(dst) is accurate.
+       if inexactOverlap(dst[n:], plaintext) {
+               panic("cipher: invalid buffer overlap")
+       }
+
+       outLen := C.size_t(len(plaintext) + gcmTagSize)
+       ok := C.EVP_AEAD_CTX_seal_wrapper(
+               &g.ctx,
+               (*C.uint8_t)(unsafe.Pointer(&dst[n])), outLen,
+               base(nonce), C.size_t(len(nonce)),
+               base(plaintext), C.size_t(len(plaintext)),
+               base(additionalData), C.size_t(len(additionalData)))
+       runtime.KeepAlive(g)
+       if ok == 0 {
+               panic(fail("EVP_AEAD_CTX_seal"))
+       }
+       return dst[:n+int(outLen)]
+}
+
+var errOpen = errors.New("cipher: message authentication failed")
+
+func (g *aesGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+       if len(nonce) != gcmStandardNonceSize {
+               panic("cipher: incorrect nonce length given to GCM")
+       }
+       if len(ciphertext) < gcmTagSize {
+               return nil, errOpen
+       }
+       if uint64(len(ciphertext)) > ((1<<32)-2)*aesBlockSize+gcmTagSize {
+               return nil, errOpen
+       }
+
+       // Make room in dst to append ciphertext without tag.
+       n := len(dst)
+       for cap(dst) < n+len(ciphertext)-gcmTagSize {
+               dst = append(dst[:cap(dst)], 0)
+       }
+       dst = dst[:n+len(ciphertext)-gcmTagSize]
+
+       // Check delayed until now to make sure len(dst) is accurate.
+       if inexactOverlap(dst[n:], ciphertext) {
+               panic("cipher: invalid buffer overlap")
+       }
+
+       outLen := C.size_t(len(ciphertext) - gcmTagSize)
+       ok := C.EVP_AEAD_CTX_open_wrapper(
+               &g.ctx,
+               base(dst[n:]), outLen,
+               base(nonce), C.size_t(len(nonce)),
+               base(ciphertext), C.size_t(len(ciphertext)),
+               base(additionalData), C.size_t(len(additionalData)))
+       runtime.KeepAlive(g)
+       if ok == 0 {
+               return nil, errOpen
+       }
+       return dst[:n+int(outLen)], nil
+}
+
+func anyOverlap(x, y []byte) bool {
+       return len(x) > 0 && len(y) > 0 &&
+               uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
+               uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
+}
+
+func inexactOverlap(x, y []byte) bool {
+       if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
+               return false
+       }
+       return anyOverlap(x, y)
+}
diff --git a/src/crypto/internal/boring/boring.go b/src/crypto/internal/boring/boring.go
new file mode 100644 (file)
index 0000000..9ccad7e
--- /dev/null
@@ -0,0 +1,83 @@
+// 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.
+
+// +build linux,amd64
+// +build !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+       "crypto/internal/boring/sig"
+       "math/big"
+)
+
+const available = true
+
+func init() {
+       C._goboringcrypto_BORINGSSL_bcm_power_on_self_test()
+       if C._goboringcrypto_FIPS_mode() != 1 {
+               panic("boringcrypto: not in FIPS mode")
+       }
+       sig.BoringCrypto()
+}
+
+// Unreachable marks code that should be unreachable
+// when BoringCrypto is in use. It panics.
+func Unreachable() {
+       panic("boringcrypto: invalid code execution")
+}
+
+// provided by runtime to avoid os import
+func runtime_arg0() string
+
+func hasSuffix(s, t string) bool {
+       return len(s) > len(t) && s[len(s)-len(t):] == t
+}
+
+// UnreachableExceptTests marks code that should be unreachable
+// when BoringCrypto is in use. It panics.
+func UnreachableExceptTests() {
+       name := runtime_arg0()
+       // If BoringCrypto ran on Windows we'd need to allow _test.exe and .test.exe as well.
+       if !hasSuffix(name, "_test") && !hasSuffix(name, ".test") {
+               println("boringcrypto: unexpected code execution in", name)
+               panic("boringcrypto: invalid code execution")
+       }
+}
+
+type fail string
+
+func (e fail) Error() string { return "boringcrypto: " + string(e) + " failed" }
+
+func bigToBN(x *big.Int) *C.GO_BIGNUM {
+       raw := x.Bytes()
+       return C._goboringcrypto_BN_bin2bn(base(raw), C.size_t(len(raw)), nil)
+}
+
+func bnToBig(bn *C.GO_BIGNUM) *big.Int {
+       raw := make([]byte, C._goboringcrypto_BN_num_bytes(bn))
+       n := C._goboringcrypto_BN_bn2bin(bn, base(raw))
+       return new(big.Int).SetBytes(raw[:n])
+}
+
+func bigToBn(bnp **C.GO_BIGNUM, b *big.Int) bool {
+       if *bnp != nil {
+               C._goboringcrypto_BN_free(*bnp)
+               *bnp = nil
+       }
+       if b == nil {
+               return true
+       }
+       raw := b.Bytes()
+       bn := C._goboringcrypto_BN_bin2bn(base(raw), C.size_t(len(raw)), nil)
+       if bn == nil {
+               return false
+       }
+       *bnp = bn
+       return true
+}
diff --git a/src/crypto/internal/boring/boring_test.go b/src/crypto/internal/boring/boring_test.go
new file mode 100644 (file)
index 0000000..83bbbd3
--- /dev/null
@@ -0,0 +1,34 @@
+// 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.
+
+// Most functionality in this package is tested by replacing existing code
+// and inheriting that code's tests.
+
+package boring
+
+import "testing"
+
+// Test that func init does not panic.
+func TestInit(t *testing.T) {}
+
+// Test that Unreachable panics.
+func TestUnreachable(t *testing.T) {
+       defer func() {
+               if Enabled {
+                       if err := recover(); err == nil {
+                               t.Fatal("expected Unreachable to panic")
+                       }
+               } else {
+                       if err := recover(); err != nil {
+                               t.Fatalf("expected Unreachable to be a no-op")
+                       }
+               }
+       }()
+       Unreachable()
+}
+
+// Test that UnreachableExceptTests does not panic (this is a test).
+func TestUnreachableExceptTests(t *testing.T) {
+       UnreachableExceptTests()
+}
diff --git a/src/crypto/internal/boring/build.sh b/src/crypto/internal/boring/build.sh
new file mode 100755 (executable)
index 0000000..31e98cb
--- /dev/null
@@ -0,0 +1,196 @@
+#!/bin/bash
+# Copyright 2020 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.
+
+set -e
+id
+date
+export LANG=C
+unset LANGUAGE
+
+# Build BoringCrypto libcrypto.a.
+# Following https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp3678.pdf page 19.
+
+tar xJf boringssl-*z
+
+# Go requires -fPIC for linux/amd64 cgo builds.
+# Setting -fPIC only affects the compilation of the non-module code in libcrypto.a,
+# because the FIPS module itself is already built with -fPIC.
+echo '#!/bin/bash
+exec clang-7 -fPIC "$@"
+' >/usr/local/bin/clang
+echo '#!/bin/bash
+exec clang++-7 -fPIC "$@"
+' >/usr/local/bin/clang++
+chmod +x /usr/local/bin/clang /usr/local/bin/clang++
+
+# The BoringSSL tests use Go, and cgo would look for gcc.
+export CGO_ENABLED=0
+
+# Verbatim instructions from BoringCrypto build docs.
+printf "set(CMAKE_C_COMPILER \"clang\")\nset(CMAKE_CXX_COMPILER \"clang++\")\n" >${HOME}/toolchain
+cd boringssl
+mkdir build && cd build && cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=${HOME}/toolchain -DFIPS=1 -DCMAKE_BUILD_TYPE=Release ..
+ninja
+ninja run_tests
+
+cd ../..
+
+if [ "$(./boringssl/build/tool/bssl isfips)" != 1 ]; then
+       echo "NOT FIPS"
+       exit 2
+fi
+
+# Build and run test C++ program to make sure goboringcrypto.h matches openssl/*.h.
+# Also collect list of checked symbols in syms.txt
+set -x
+set -e
+cd godriver
+cat >goboringcrypto.cc <<'EOF'
+#include <cassert>
+#include "goboringcrypto0.h"
+#include "goboringcrypto1.h"
+#define check_size(t) if(sizeof(t) != sizeof(GO_ ## t)) {printf("sizeof(" #t ")=%d, but sizeof(GO_" #t ")=%d\n", (int)sizeof(t), (int)sizeof(GO_ ## t)); ret=1;}
+#define check_func(f) { auto x = f; x = _goboringcrypto_ ## f ; }
+#define check_value(n, v) if(n != v) {printf(#n "=%d, but goboringcrypto.h defines it as %d\n", (int)n, (int)v); ret=1;}
+int main() {
+int ret = 0;
+#include "goboringcrypto.x"
+return ret;
+}
+EOF
+
+awk '
+BEGIN {
+       exitcode = 0
+}
+
+# Ignore comments, #includes, blank lines.
+/^\/\// || /^#/ || NF == 0 { next }
+
+# Ignore unchecked declarations.
+/\/\*unchecked/ { next }
+
+# Check enum values.
+!enum && $1 == "enum" && $NF == "{" {
+       enum = 1
+       next
+}
+enum && $1 == "};" {
+       enum = 0
+       next
+}
+enum && NF == 3 && $2 == "=" {
+       name = $1
+       sub(/^GO_/, "", name)
+       val = $3
+       sub(/,$/, "", val)
+       print "check_value(" name ", " val ")" > "goboringcrypto.x"
+       next
+}
+enum {
+       print FILENAME ":" NR ": unexpected line in enum: " $0 > "/dev/stderr"
+       exitcode = 1
+       next
+}
+
+# Check struct sizes.
+/^typedef struct / && $NF ~ /^GO_/ {
+       name = $NF
+       sub(/^GO_/, "", name)
+       sub(/;$/, "", name)
+       print "check_size(" name ")" > "goboringcrypto.x"
+       next
+}
+
+# Check function prototypes.
+/^(const )?[^ ]+ \**_goboringcrypto_.*\(/ {
+       name = $2
+       if($1 == "const")
+               name = $3
+       sub(/^\**_goboringcrypto_/, "", name)
+       sub(/\(.*/, "", name)
+       print "check_func(" name ")" > "goboringcrypto.x"
+       print name > "syms.txt"
+       next
+}
+
+{
+       print FILENAME ":" NR ": unexpected line: " $0 > "/dev/stderr"
+       exitcode = 1
+}
+
+END {
+       exit exitcode
+}
+' goboringcrypto.h
+
+cat goboringcrypto.h | awk '
+       /^\/\/ #include/ {sub(/\/\//, ""); print > "goboringcrypto0.h"; next}
+       /typedef struct|enum ([a-z_]+ )?{|^[ \t]/ {print;next}
+       {gsub(/GO_/, ""); gsub(/enum go_/, "enum "); print}
+' >goboringcrypto1.h
+clang++ -std=c++11 -fPIC -I../boringssl/include -O2 -o a.out  goboringcrypto.cc
+./a.out || exit 2
+
+# Prepare copy of libcrypto.a with only the checked functions renamed and exported.
+# All other symbols are left alone and hidden.
+echo BORINGSSL_bcm_power_on_self_test >>syms.txt
+awk '{print "_goboringcrypto_" $0 }' syms.txt >globals.txt
+awk '{print $0 " _goboringcrypto_" $0 }' syms.txt >renames.txt
+objcopy --globalize-symbol=BORINGSSL_bcm_power_on_self_test ../boringssl/build/crypto/libcrypto.a libcrypto.a
+
+# clang implements u128 % u128 -> u128 by calling __umodti3,
+# which is in libgcc. To make the result self-contained even if linking
+# against a different compiler version, link our own __umodti3 into the syso.
+# This one is specialized so it only expects divisors below 2^64,
+# which is all BoringCrypto uses. (Otherwise it will seg fault.)
+cat >umod.s <<'EOF'
+# tu_int __umodti3(tu_int x, tu_int y)
+# x is rsi:rdi, y is rcx:rdx, return result is rdx:rax.
+.globl __umodti3
+__umodti3:
+       # specialized to u128 % u64, so verify that
+       test %rcx,%rcx
+       jne 1f
+
+       # save divisor
+       movq %rdx, %r8
+
+       # reduce top 64 bits mod divisor
+       movq %rsi, %rax
+       xorl %edx, %edx
+       divq %r8
+
+       # reduce full 128-bit mod divisor
+       # quotient fits in 64 bits because top 64 bits have been reduced < divisor.
+       # (even though we only care about the remainder, divq also computes
+       # the quotient, and it will trap if the quotient is too large.)
+       movq %rdi, %rax
+       divq %r8
+
+       # expand remainder to 128 for return
+       movq %rdx, %rax
+       xorl %edx, %edx
+       ret
+
+1:
+       # crash - only want 64-bit divisor
+       xorl %ecx, %ecx
+       movl %ecx, 0(%ecx)
+       jmp 1b
+
+.section .note.GNU-stack,"",@progbits
+EOF
+clang -c -o umod.o umod.s
+
+ld -r -nostdlib --whole-archive -o goboringcrypto.o libcrypto.a umod.o
+echo __umodti3 _goboringcrypto___umodti3 >>renames.txt
+objcopy --remove-section=.llvm_addrsig goboringcrypto.o goboringcrypto1.o # b/179161016
+objcopy --redefine-syms=renames.txt goboringcrypto1.o goboringcrypto2.o
+objcopy --keep-global-symbols=globals.txt goboringcrypto2.o goboringcrypto_linux_amd64.syso
+
+# Done!
+ls -l goboringcrypto_linux_amd64.syso
+sha256sum goboringcrypto_linux_amd64.syso
diff --git a/src/crypto/internal/boring/doc.go b/src/crypto/internal/boring/doc.go
new file mode 100644 (file)
index 0000000..64f41e3
--- /dev/null
@@ -0,0 +1,14 @@
+// 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.
+
+// Package boring provides access to BoringCrypto implementation functions.
+// Check the constant Enabled to find out whether BoringCrypto is available.
+// If BoringCrypto is not available, the functions in this package all panic.
+package boring
+
+// Enabled reports whether BoringCrypto is available.
+// When enabled is false, all functions in this package panic.
+//
+// BoringCrypto is only available on linux/amd64 systems.
+const Enabled = available
diff --git a/src/crypto/internal/boring/ecdsa.go b/src/crypto/internal/boring/ecdsa.go
new file mode 100644 (file)
index 0000000..4fcba4b
--- /dev/null
@@ -0,0 +1,201 @@
+// 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.
+
+// +build linux,amd64
+// +build !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+       "encoding/asn1"
+       "errors"
+       "math/big"
+       "runtime"
+       "unsafe"
+)
+
+type ecdsaSignature struct {
+       R, S *big.Int
+}
+
+type PrivateKeyECDSA struct {
+       key *C.GO_EC_KEY
+}
+
+func (k *PrivateKeyECDSA) finalize() {
+       C._goboringcrypto_EC_KEY_free(k.key)
+}
+
+type PublicKeyECDSA struct {
+       key *C.GO_EC_KEY
+}
+
+func (k *PublicKeyECDSA) finalize() {
+       C._goboringcrypto_EC_KEY_free(k.key)
+}
+
+var errUnknownCurve = errors.New("boringcrypto: unknown elliptic curve")
+
+func curveNID(curve string) (C.int, error) {
+       switch curve {
+       case "P-224":
+               return C.GO_NID_secp224r1, nil
+       case "P-256":
+               return C.GO_NID_X9_62_prime256v1, nil
+       case "P-384":
+               return C.GO_NID_secp384r1, nil
+       case "P-521":
+               return C.GO_NID_secp521r1, nil
+       }
+       return 0, errUnknownCurve
+}
+
+func NewPublicKeyECDSA(curve string, X, Y *big.Int) (*PublicKeyECDSA, error) {
+       key, err := newECKey(curve, X, Y)
+       if err != nil {
+               return nil, err
+       }
+       k := &PublicKeyECDSA{key}
+       // Note: Because of the finalizer, any time k.key is passed to cgo,
+       // that call must be followed by a call to runtime.KeepAlive(k),
+       // to make sure k is not collected (and finalized) before the cgo
+       // call returns.
+       runtime.SetFinalizer(k, (*PublicKeyECDSA).finalize)
+       return k, nil
+}
+
+func newECKey(curve string, X, Y *big.Int) (*C.GO_EC_KEY, error) {
+       nid, err := curveNID(curve)
+       if err != nil {
+               return nil, err
+       }
+       key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
+       if key == nil {
+               return nil, fail("EC_KEY_new_by_curve_name")
+       }
+       group := C._goboringcrypto_EC_KEY_get0_group(key)
+       pt := C._goboringcrypto_EC_POINT_new(group)
+       if pt == nil {
+               C._goboringcrypto_EC_KEY_free(key)
+               return nil, fail("EC_POINT_new")
+       }
+       bx := bigToBN(X)
+       by := bigToBN(Y)
+       ok := bx != nil && by != nil && C._goboringcrypto_EC_POINT_set_affine_coordinates_GFp(group, pt, bx, by, nil) != 0 &&
+               C._goboringcrypto_EC_KEY_set_public_key(key, pt) != 0
+       if bx != nil {
+               C._goboringcrypto_BN_free(bx)
+       }
+       if by != nil {
+               C._goboringcrypto_BN_free(by)
+       }
+       C._goboringcrypto_EC_POINT_free(pt)
+       if !ok {
+               C._goboringcrypto_EC_KEY_free(key)
+               return nil, fail("EC_POINT_set_affine_coordinates_GFp")
+       }
+       return key, nil
+}
+
+func NewPrivateKeyECDSA(curve string, X, Y *big.Int, D *big.Int) (*PrivateKeyECDSA, error) {
+       key, err := newECKey(curve, X, Y)
+       if err != nil {
+               return nil, err
+       }
+       bd := bigToBN(D)
+       ok := bd != nil && C._goboringcrypto_EC_KEY_set_private_key(key, bd) != 0
+       if bd != nil {
+               C._goboringcrypto_BN_free(bd)
+       }
+       if !ok {
+               C._goboringcrypto_EC_KEY_free(key)
+               return nil, fail("EC_KEY_set_private_key")
+       }
+       k := &PrivateKeyECDSA{key}
+       // Note: Because of the finalizer, any time k.key is passed to cgo,
+       // that call must be followed by a call to runtime.KeepAlive(k),
+       // to make sure k is not collected (and finalized) before the cgo
+       // call returns.
+       runtime.SetFinalizer(k, (*PrivateKeyECDSA).finalize)
+       return k, nil
+}
+
+func SignECDSA(priv *PrivateKeyECDSA, hash []byte) (r, s *big.Int, err error) {
+       // We could use ECDSA_do_sign instead but would need to convert
+       // the resulting BIGNUMs to *big.Int form. If we're going to do a
+       // conversion, converting the ASN.1 form is more convenient and
+       // likely not much more expensive.
+       sig, err := SignMarshalECDSA(priv, hash)
+       if err != nil {
+               return nil, nil, err
+       }
+       var esig ecdsaSignature
+       if _, err := asn1.Unmarshal(sig, &esig); err != nil {
+               return nil, nil, err
+       }
+       return esig.R, esig.S, nil
+}
+
+func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) {
+       size := C._goboringcrypto_ECDSA_size(priv.key)
+       sig := make([]byte, size)
+       var sigLen C.uint
+       if C._goboringcrypto_ECDSA_sign(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), &sigLen, priv.key) == 0 {
+               return nil, fail("ECDSA_sign")
+       }
+       runtime.KeepAlive(priv)
+       return sig[:sigLen], nil
+}
+
+func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, r, s *big.Int) bool {
+       // We could use ECDSA_do_verify instead but would need to convert
+       // r and s to BIGNUM form. If we're going to do a conversion, marshaling
+       // to ASN.1 is more convenient and likely not much more expensive.
+       sig, err := asn1.Marshal(ecdsaSignature{r, s})
+       if err != nil {
+               return false
+       }
+       ok := C._goboringcrypto_ECDSA_verify(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), C.size_t(len(sig)), pub.key) != 0
+       runtime.KeepAlive(pub)
+       return ok
+}
+
+func GenerateKeyECDSA(curve string) (X, Y, D *big.Int, err error) {
+       nid, err := curveNID(curve)
+       if err != nil {
+               return nil, nil, nil, err
+       }
+       key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
+       if key == nil {
+               return nil, nil, nil, fail("EC_KEY_new_by_curve_name")
+       }
+       defer C._goboringcrypto_EC_KEY_free(key)
+       if C._goboringcrypto_EC_KEY_generate_key_fips(key) == 0 {
+               return nil, nil, nil, fail("EC_KEY_generate_key_fips")
+       }
+       group := C._goboringcrypto_EC_KEY_get0_group(key)
+       pt := C._goboringcrypto_EC_KEY_get0_public_key(key)
+       bd := C._goboringcrypto_EC_KEY_get0_private_key(key)
+       if pt == nil || bd == nil {
+               return nil, nil, nil, fail("EC_KEY_get0_private_key")
+       }
+       bx := C._goboringcrypto_BN_new()
+       if bx == nil {
+               return nil, nil, nil, fail("BN_new")
+       }
+       defer C._goboringcrypto_BN_free(bx)
+       by := C._goboringcrypto_BN_new()
+       if by == nil {
+               return nil, nil, nil, fail("BN_new")
+       }
+       defer C._goboringcrypto_BN_free(by)
+       if C._goboringcrypto_EC_POINT_get_affine_coordinates_GFp(group, pt, bx, by, nil) == 0 {
+               return nil, nil, nil, fail("EC_POINT_get_affine_coordinates_GFp")
+       }
+       return bnToBig(bx), bnToBig(by), bnToBig(bd), nil
+}
diff --git a/src/crypto/internal/boring/fipstls/dummy.s b/src/crypto/internal/boring/fipstls/dummy.s
new file mode 100644 (file)
index 0000000..53bb7d9
--- /dev/null
@@ -0,0 +1,10 @@
+// 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.
+
+// runtime_arg0 is declared in tls.go without a body.
+// It's provided by package runtime,
+// but the go command doesn't know that.
+// Having this assembly file keeps the go command
+// from complaining about the missing body
+// (because the implementation might be here).
diff --git a/src/crypto/internal/boring/fipstls/tls.go b/src/crypto/internal/boring/fipstls/tls.go
new file mode 100644 (file)
index 0000000..4127533
--- /dev/null
@@ -0,0 +1,49 @@
+// 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.
+
+// Package fipstls allows control over whether crypto/tls requires FIPS-approved settings.
+// This package's effects are independent of the use of the BoringCrypto implementation.
+package fipstls
+
+import "sync/atomic"
+
+var required uint32
+
+// Force forces crypto/tls to restrict TLS configurations to FIPS-approved settings.
+// By design, this call is impossible to undo (except in tests).
+//
+// Note that this call has an effect even in programs using
+// standard crypto (that is, even when Enabled = false).
+func Force() {
+       atomic.StoreUint32(&required, 1)
+}
+
+// Abandon allows non-FIPS-approved settings.
+// If called from a non-test binary, it panics.
+func Abandon() {
+       // Note: Not using boring.UnreachableExceptTests because we want
+       // this test to happen even when boring.Enabled = false.
+       name := runtime_arg0()
+       // Allow _test for Go command, .test for Bazel,
+       // NaClMain for NaCl (where all binaries run as NaClMain),
+       // and empty string for Windows (where runtime_arg0 can't easily find the name).
+       // Since this is an internal package, testing that this isn't used on the
+       // other operating systems should suffice to catch any mistakes.
+       if !hasSuffix(name, "_test") && !hasSuffix(name, ".test") && name != "NaClMain" && name != "" {
+               panic("fipstls: invalid use of Abandon in " + name)
+       }
+       atomic.StoreUint32(&required, 0)
+}
+
+// provided by runtime
+func runtime_arg0() string
+
+func hasSuffix(s, t string) bool {
+       return len(s) > len(t) && s[len(s)-len(t):] == t
+}
+
+// Required reports whether FIPS-approved settings are required.
+func Required() bool {
+       return atomic.LoadUint32(&required) != 0
+}
diff --git a/src/crypto/internal/boring/goboringcrypto.h b/src/crypto/internal/boring/goboringcrypto.h
new file mode 100644 (file)
index 0000000..37b7917
--- /dev/null
@@ -0,0 +1,237 @@
+// 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.
+
+// This header file describes the BoringCrypto ABI as built for use in Go.
+// The BoringCrypto build for Go (which generates goboringcrypto_*.syso)
+// takes the standard libcrypto.a from BoringCrypto and adds the prefix
+// _goboringcrypto_ to every symbol, to avoid possible conflicts with
+// code wrapping a different BoringCrypto or OpenSSL.
+//
+// To make this header standalone (so that building Go does not require
+// having a full set of BoringCrypto headers), the struct details are not here.
+// Instead, while building the syso, we compile and run a C++ program
+// that checks that the sizes match. The program also checks (during compilation)
+// that all the function prototypes match the BoringCrypto equivalents.
+// The generation of the checking program depends on the declaration
+// forms used below (one line for most, multiline for enums).
+
+#include <stdlib.h> // size_t
+#include <stdint.h> // uint8_t
+
+// This symbol is hidden in BoringCrypto and marked as a constructor,
+// but cmd/link's internal linking mode doesn't handle constructors.
+// Until it does, we've exported the symbol and can call it explicitly.
+// (If using external linking mode, it will therefore be called twice,
+// once explicitly and once as a constructor, but that's OK.)
+/*unchecked*/ void _goboringcrypto_BORINGSSL_bcm_power_on_self_test(void);
+
+// #include <openssl/crypto.h>
+int _goboringcrypto_FIPS_mode(void);
+void* _goboringcrypto_OPENSSL_malloc(size_t);
+
+// #include <openssl/rand.h>
+int _goboringcrypto_RAND_bytes(uint8_t*, size_t);
+
+// #include <openssl/nid.h>
+enum {
+       GO_NID_md5_sha1 = 114,
+
+       GO_NID_secp224r1 = 713,
+       GO_NID_X9_62_prime256v1 = 415,
+       GO_NID_secp384r1 = 715,
+       GO_NID_secp521r1 = 716,
+
+       GO_NID_sha224 = 675,
+       GO_NID_sha256 = 672,
+       GO_NID_sha384 = 673,
+       GO_NID_sha512 = 674,
+};
+
+// #include <openssl/sha.h>
+typedef struct GO_SHA_CTX { char data[96]; } GO_SHA_CTX;
+int _goboringcrypto_SHA1_Init(GO_SHA_CTX*);
+int _goboringcrypto_SHA1_Update(GO_SHA_CTX*, const void*, size_t);
+int _goboringcrypto_SHA1_Final(uint8_t*, GO_SHA_CTX*);
+
+typedef struct GO_SHA256_CTX { char data[48+64]; } GO_SHA256_CTX;
+int _goboringcrypto_SHA224_Init(GO_SHA256_CTX*);
+int _goboringcrypto_SHA224_Update(GO_SHA256_CTX*, const void*, size_t);
+int _goboringcrypto_SHA224_Final(uint8_t*, GO_SHA256_CTX*);
+int _goboringcrypto_SHA256_Init(GO_SHA256_CTX*);
+int _goboringcrypto_SHA256_Update(GO_SHA256_CTX*, const void*, size_t);
+int _goboringcrypto_SHA256_Final(uint8_t*, GO_SHA256_CTX*);
+
+typedef struct GO_SHA512_CTX { char data[88+128]; } GO_SHA512_CTX;
+int _goboringcrypto_SHA384_Init(GO_SHA512_CTX*);
+int _goboringcrypto_SHA384_Update(GO_SHA512_CTX*, const void*, size_t);
+int _goboringcrypto_SHA384_Final(uint8_t*, GO_SHA512_CTX*);
+int _goboringcrypto_SHA512_Init(GO_SHA512_CTX*);
+int _goboringcrypto_SHA512_Update(GO_SHA512_CTX*, const void*, size_t);
+int _goboringcrypto_SHA512_Final(uint8_t*, GO_SHA512_CTX*);
+
+// #include <openssl/digest.h>
+/*unchecked (opaque)*/ typedef struct GO_EVP_MD { char data[1]; } GO_EVP_MD;
+const GO_EVP_MD* _goboringcrypto_EVP_md4(void);
+const GO_EVP_MD* _goboringcrypto_EVP_md5(void);
+const GO_EVP_MD* _goboringcrypto_EVP_md5_sha1(void);
+const GO_EVP_MD* _goboringcrypto_EVP_sha1(void);
+const GO_EVP_MD* _goboringcrypto_EVP_sha224(void);
+const GO_EVP_MD* _goboringcrypto_EVP_sha256(void);
+const GO_EVP_MD* _goboringcrypto_EVP_sha384(void);
+const GO_EVP_MD* _goboringcrypto_EVP_sha512(void);
+int _goboringcrypto_EVP_MD_type(const GO_EVP_MD*);
+size_t _goboringcrypto_EVP_MD_size(const GO_EVP_MD*);
+
+// #include <openssl/hmac.h>
+typedef struct GO_HMAC_CTX { char data[104]; } GO_HMAC_CTX;
+void _goboringcrypto_HMAC_CTX_init(GO_HMAC_CTX*);
+void _goboringcrypto_HMAC_CTX_cleanup(GO_HMAC_CTX*);
+int _goboringcrypto_HMAC_Init(GO_HMAC_CTX*, const void*, int, const GO_EVP_MD*);
+int _goboringcrypto_HMAC_Update(GO_HMAC_CTX*, const uint8_t*, size_t);
+int _goboringcrypto_HMAC_Final(GO_HMAC_CTX*, uint8_t*, unsigned int*);
+size_t _goboringcrypto_HMAC_size(const GO_HMAC_CTX*);
+int _goboringcrypto_HMAC_CTX_copy_ex(GO_HMAC_CTX *dest, const GO_HMAC_CTX *src);
+
+// #include <openssl/aes.h>
+typedef struct GO_AES_KEY { char data[244]; } GO_AES_KEY;
+int _goboringcrypto_AES_set_encrypt_key(const uint8_t*, unsigned int, GO_AES_KEY*);
+int _goboringcrypto_AES_set_decrypt_key(const uint8_t*, unsigned int, GO_AES_KEY*);
+void _goboringcrypto_AES_encrypt(const uint8_t*, uint8_t*, const GO_AES_KEY*);
+void _goboringcrypto_AES_decrypt(const uint8_t*, uint8_t*, const GO_AES_KEY*);
+void _goboringcrypto_AES_ctr128_encrypt(const uint8_t*, uint8_t*, size_t, const GO_AES_KEY*, uint8_t*, uint8_t*, unsigned int*);
+enum {
+       GO_AES_ENCRYPT = 1,
+       GO_AES_DECRYPT = 0
+};
+void _goboringcrypto_AES_cbc_encrypt(const uint8_t*, uint8_t*, size_t, const GO_AES_KEY*, uint8_t*, const int);
+
+// #include <openssl/aead.h>
+/*unchecked (opaque)*/ typedef struct GO_EVP_AEAD { char data[1]; } GO_EVP_AEAD;
+/*unchecked (opaque)*/ typedef struct GO_ENGINE { char data[1]; } GO_ENGINE;
+const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_128_gcm(void);
+const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_256_gcm(void);
+enum {
+       GO_EVP_AEAD_DEFAULT_TAG_LENGTH = 0
+};
+size_t _goboringcrypto_EVP_AEAD_key_length(const GO_EVP_AEAD*);
+size_t _goboringcrypto_EVP_AEAD_nonce_length(const GO_EVP_AEAD*);
+size_t _goboringcrypto_EVP_AEAD_max_overhead(const GO_EVP_AEAD*);
+size_t _goboringcrypto_EVP_AEAD_max_tag_len(const GO_EVP_AEAD*);
+typedef struct GO_EVP_AEAD_CTX { char data[600]; } GO_EVP_AEAD_CTX;
+void _goboringcrypto_EVP_AEAD_CTX_zero(GO_EVP_AEAD_CTX*);
+int _goboringcrypto_EVP_AEAD_CTX_init(GO_EVP_AEAD_CTX*, const GO_EVP_AEAD*, const uint8_t*, size_t, size_t, GO_ENGINE*);
+void _goboringcrypto_EVP_AEAD_CTX_cleanup(GO_EVP_AEAD_CTX*);
+int _goboringcrypto_EVP_AEAD_CTX_seal(const GO_EVP_AEAD_CTX*, uint8_t*, size_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t);
+int _goboringcrypto_EVP_AEAD_CTX_open(const GO_EVP_AEAD_CTX*, uint8_t*, size_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t);
+const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_128_gcm_tls12(void);
+const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_256_gcm_tls12(void);
+enum go_evp_aead_direction_t {
+       go_evp_aead_open = 0,
+       go_evp_aead_seal = 1
+};
+int _goboringcrypto_EVP_AEAD_CTX_init_with_direction(GO_EVP_AEAD_CTX*, const GO_EVP_AEAD*, const uint8_t*, size_t, size_t, enum go_evp_aead_direction_t);
+
+// #include <openssl/bn.h>
+/*unchecked (opaque)*/ typedef struct GO_BN_CTX { char data[1]; } GO_BN_CTX;
+typedef struct GO_BIGNUM { char data[24]; } GO_BIGNUM;
+GO_BIGNUM* _goboringcrypto_BN_new(void);
+void _goboringcrypto_BN_free(GO_BIGNUM*);
+unsigned _goboringcrypto_BN_num_bits(const GO_BIGNUM*);
+unsigned _goboringcrypto_BN_num_bytes(const GO_BIGNUM*);
+int _goboringcrypto_BN_is_negative(const GO_BIGNUM*);
+GO_BIGNUM* _goboringcrypto_BN_bin2bn(const uint8_t*, size_t, GO_BIGNUM*);
+size_t _goboringcrypto_BN_bn2bin(const GO_BIGNUM*, uint8_t*);
+
+// #include <openssl/ec.h>
+/*unchecked (opaque)*/ typedef struct GO_EC_GROUP { char data[1]; } GO_EC_GROUP;
+GO_EC_GROUP* _goboringcrypto_EC_GROUP_new_by_curve_name(int);
+void _goboringcrypto_EC_GROUP_free(GO_EC_GROUP*);
+
+/*unchecked (opaque)*/ typedef struct GO_EC_POINT { char data[1]; } GO_EC_POINT;
+GO_EC_POINT* _goboringcrypto_EC_POINT_new(const GO_EC_GROUP*);
+void _goboringcrypto_EC_POINT_free(GO_EC_POINT*);
+int _goboringcrypto_EC_POINT_get_affine_coordinates_GFp(const GO_EC_GROUP*, const GO_EC_POINT*, GO_BIGNUM*, GO_BIGNUM*, GO_BN_CTX*);
+int _goboringcrypto_EC_POINT_set_affine_coordinates_GFp(const GO_EC_GROUP*, GO_EC_POINT*, const GO_BIGNUM*, const GO_BIGNUM*, GO_BN_CTX*);
+
+// #include <openssl/ec_key.h>
+/*unchecked (opaque)*/ typedef struct GO_EC_KEY { char data[1]; } GO_EC_KEY;
+GO_EC_KEY* _goboringcrypto_EC_KEY_new(void);
+GO_EC_KEY* _goboringcrypto_EC_KEY_new_by_curve_name(int);
+void _goboringcrypto_EC_KEY_free(GO_EC_KEY*);
+const GO_EC_GROUP* _goboringcrypto_EC_KEY_get0_group(const GO_EC_KEY*);
+int _goboringcrypto_EC_KEY_generate_key_fips(GO_EC_KEY*);
+int _goboringcrypto_EC_KEY_set_private_key(GO_EC_KEY*, const GO_BIGNUM*);
+int _goboringcrypto_EC_KEY_set_public_key(GO_EC_KEY*, const GO_EC_POINT*);
+int _goboringcrypto_EC_KEY_is_opaque(const GO_EC_KEY*);
+const GO_BIGNUM* _goboringcrypto_EC_KEY_get0_private_key(const GO_EC_KEY*);
+const GO_EC_POINT* _goboringcrypto_EC_KEY_get0_public_key(const GO_EC_KEY*);
+// TODO: EC_KEY_check_fips?
+
+// #include <openssl/ecdsa.h>
+typedef struct GO_ECDSA_SIG { char data[16]; } GO_ECDSA_SIG;
+GO_ECDSA_SIG* _goboringcrypto_ECDSA_SIG_new(void);
+void _goboringcrypto_ECDSA_SIG_free(GO_ECDSA_SIG*);
+GO_ECDSA_SIG* _goboringcrypto_ECDSA_do_sign(const uint8_t*, size_t, const GO_EC_KEY*);
+int _goboringcrypto_ECDSA_do_verify(const uint8_t*, size_t, const GO_ECDSA_SIG*, const GO_EC_KEY*);
+int _goboringcrypto_ECDSA_sign(int, const uint8_t*, size_t, uint8_t*, unsigned int*, const GO_EC_KEY*);
+size_t _goboringcrypto_ECDSA_size(const GO_EC_KEY*);
+int _goboringcrypto_ECDSA_verify(int, const uint8_t*, size_t, const uint8_t*, size_t, const GO_EC_KEY*);
+
+// #include <openssl/rsa.h>
+
+// Note: order of struct fields here is unchecked.
+typedef struct GO_RSA { void *meth; GO_BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; char data[160]; } GO_RSA;
+/*unchecked (opaque)*/ typedef struct GO_BN_GENCB { char data[1]; } GO_BN_GENCB;
+GO_RSA* _goboringcrypto_RSA_new(void);
+void _goboringcrypto_RSA_free(GO_RSA*);
+void _goboringcrypto_RSA_get0_key(const GO_RSA*, const GO_BIGNUM **n, const GO_BIGNUM **e, const GO_BIGNUM **d);
+void _goboringcrypto_RSA_get0_factors(const GO_RSA*, const GO_BIGNUM **p, const GO_BIGNUM **q);
+void _goboringcrypto_RSA_get0_crt_params(const GO_RSA*, const GO_BIGNUM **dmp1, const GO_BIGNUM **dmp2, const GO_BIGNUM **iqmp);
+int _goboringcrypto_RSA_generate_key_ex(GO_RSA*, int, const GO_BIGNUM*, GO_BN_GENCB*);
+int _goboringcrypto_RSA_generate_key_fips(GO_RSA*, int, GO_BN_GENCB*);
+enum {
+       GO_RSA_PKCS1_PADDING = 1,
+       GO_RSA_NO_PADDING = 3,
+       GO_RSA_PKCS1_OAEP_PADDING = 4,
+       GO_RSA_PKCS1_PSS_PADDING = 6,
+};
+int _goboringcrypto_RSA_encrypt(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding);
+int _goboringcrypto_RSA_decrypt(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding);
+int _goboringcrypto_RSA_sign(int hash_nid, const uint8_t* in, unsigned int in_len, uint8_t *out, unsigned int *out_len, GO_RSA*);
+int _goboringcrypto_RSA_sign_pss_mgf1(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, const GO_EVP_MD *md, const GO_EVP_MD *mgf1_md, int salt_len);
+int _goboringcrypto_RSA_sign_raw(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding);
+int _goboringcrypto_RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len, const uint8_t *sig, size_t sig_len, GO_RSA*);
+int _goboringcrypto_RSA_verify_pss_mgf1(GO_RSA*, const uint8_t *msg, size_t msg_len, const GO_EVP_MD *md, const GO_EVP_MD *mgf1_md, int salt_len, const uint8_t *sig, size_t sig_len);
+int _goboringcrypto_RSA_verify_raw(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding);
+unsigned _goboringcrypto_RSA_size(const GO_RSA*);
+int _goboringcrypto_RSA_is_opaque(const GO_RSA*);
+int _goboringcrypto_RSA_check_key(const GO_RSA*);
+int _goboringcrypto_RSA_check_fips(GO_RSA*);
+GO_RSA* _goboringcrypto_RSA_public_key_from_bytes(const uint8_t*, size_t);
+GO_RSA* _goboringcrypto_RSA_private_key_from_bytes(const uint8_t*, size_t);
+int _goboringcrypto_RSA_public_key_to_bytes(uint8_t**, size_t*, const GO_RSA*);
+int _goboringcrypto_RSA_private_key_to_bytes(uint8_t**, size_t*, const GO_RSA*);
+
+// #include <openssl/evp.h>
+/*unchecked (opaque)*/ typedef struct GO_EVP_PKEY { char data[1]; } GO_EVP_PKEY;
+GO_EVP_PKEY* _goboringcrypto_EVP_PKEY_new(void);
+void _goboringcrypto_EVP_PKEY_free(GO_EVP_PKEY*);
+int _goboringcrypto_EVP_PKEY_set1_RSA(GO_EVP_PKEY*, GO_RSA*);
+
+/*unchecked (opaque)*/ typedef struct GO_EVP_PKEY_CTX { char data[1]; } GO_EVP_PKEY_CTX;
+
+GO_EVP_PKEY_CTX* _goboringcrypto_EVP_PKEY_CTX_new(GO_EVP_PKEY*, GO_ENGINE*);
+void _goboringcrypto_EVP_PKEY_CTX_free(GO_EVP_PKEY_CTX*);
+int _goboringcrypto_EVP_PKEY_CTX_set0_rsa_oaep_label(GO_EVP_PKEY_CTX*, uint8_t*, size_t);
+int _goboringcrypto_EVP_PKEY_CTX_set_rsa_oaep_md(GO_EVP_PKEY_CTX*, const GO_EVP_MD*);
+int _goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(GO_EVP_PKEY_CTX*, int padding);
+int _goboringcrypto_EVP_PKEY_decrypt(GO_EVP_PKEY_CTX*, uint8_t*, size_t*, const uint8_t*, size_t);
+int _goboringcrypto_EVP_PKEY_encrypt(GO_EVP_PKEY_CTX*, uint8_t*, size_t*, const uint8_t*, size_t);
+int _goboringcrypto_EVP_PKEY_decrypt_init(GO_EVP_PKEY_CTX*);
+int _goboringcrypto_EVP_PKEY_encrypt_init(GO_EVP_PKEY_CTX*);
+int _goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(GO_EVP_PKEY_CTX*, const GO_EVP_MD*);
+int _goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(GO_EVP_PKEY_CTX*, int);
+int _goboringcrypto_EVP_PKEY_sign_init(GO_EVP_PKEY_CTX*);
+int _goboringcrypto_EVP_PKEY_verify_init(GO_EVP_PKEY_CTX*);
+int _goboringcrypto_EVP_PKEY_sign(GO_EVP_PKEY_CTX*, uint8_t*, size_t*, const uint8_t*, size_t);
diff --git a/src/crypto/internal/boring/goboringcrypto_linux_amd64.syso b/src/crypto/internal/boring/goboringcrypto_linux_amd64.syso
new file mode 100644 (file)
index 0000000..2459dd7
Binary files /dev/null and b/src/crypto/internal/boring/goboringcrypto_linux_amd64.syso differ
diff --git a/src/crypto/internal/boring/hmac.go b/src/crypto/internal/boring/hmac.go
new file mode 100644 (file)
index 0000000..01b5844
--- /dev/null
@@ -0,0 +1,156 @@
+// 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.
+
+// +build linux,amd64
+// +build !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+       "crypto"
+       "hash"
+       "runtime"
+       "unsafe"
+)
+
+// hashToMD converts a hash.Hash implementation from this package
+// to a BoringCrypto *C.GO_EVP_MD.
+func hashToMD(h hash.Hash) *C.GO_EVP_MD {
+       switch h.(type) {
+       case *sha1Hash:
+               return C._goboringcrypto_EVP_sha1()
+       case *sha224Hash:
+               return C._goboringcrypto_EVP_sha224()
+       case *sha256Hash:
+               return C._goboringcrypto_EVP_sha256()
+       case *sha384Hash:
+               return C._goboringcrypto_EVP_sha384()
+       case *sha512Hash:
+               return C._goboringcrypto_EVP_sha512()
+       }
+       return nil
+}
+
+// cryptoHashToMD converts a crypto.Hash
+// to a BoringCrypto *C.GO_EVP_MD.
+func cryptoHashToMD(ch crypto.Hash) *C.GO_EVP_MD {
+       switch ch {
+       case crypto.MD5:
+               return C._goboringcrypto_EVP_md5()
+       case crypto.MD5SHA1:
+               return C._goboringcrypto_EVP_md5_sha1()
+       case crypto.SHA1:
+               return C._goboringcrypto_EVP_sha1()
+       case crypto.SHA224:
+               return C._goboringcrypto_EVP_sha224()
+       case crypto.SHA256:
+               return C._goboringcrypto_EVP_sha256()
+       case crypto.SHA384:
+               return C._goboringcrypto_EVP_sha384()
+       case crypto.SHA512:
+               return C._goboringcrypto_EVP_sha512()
+       }
+       return nil
+}
+
+// NewHMAC returns a new HMAC using BoringCrypto.
+// The function h must return a hash implemented by
+// BoringCrypto (for example, h could be boring.NewSHA256).
+// If h is not recognized, NewHMAC returns nil.
+func NewHMAC(h func() hash.Hash, key []byte) hash.Hash {
+       ch := h()
+       md := hashToMD(ch)
+       if md == nil {
+               return nil
+       }
+
+       // Note: Could hash down long keys here using EVP_Digest.
+       hkey := make([]byte, len(key))
+       copy(hkey, key)
+       hmac := &boringHMAC{
+               md:        md,
+               size:      ch.Size(),
+               blockSize: ch.BlockSize(),
+               key:       hkey,
+       }
+       hmac.Reset()
+       return hmac
+}
+
+type boringHMAC struct {
+       md          *C.GO_EVP_MD
+       ctx         C.GO_HMAC_CTX
+       ctx2        C.GO_HMAC_CTX
+       size        int
+       blockSize   int
+       key         []byte
+       sum         []byte
+       needCleanup bool
+}
+
+func (h *boringHMAC) Reset() {
+       if h.needCleanup {
+               C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx)
+       } else {
+               h.needCleanup = true
+               // Note: Because of the finalizer, any time h.ctx is passed to cgo,
+               // that call must be followed by a call to runtime.KeepAlive(h),
+               // to make sure h is not collected (and finalized) before the cgo
+               // call returns.
+               runtime.SetFinalizer(h, (*boringHMAC).finalize)
+       }
+       C._goboringcrypto_HMAC_CTX_init(&h.ctx)
+
+       if C._goboringcrypto_HMAC_Init(&h.ctx, unsafe.Pointer(base(h.key)), C.int(len(h.key)), h.md) == 0 {
+               panic("boringcrypto: HMAC_Init failed")
+       }
+       if int(C._goboringcrypto_HMAC_size(&h.ctx)) != h.size {
+               println("boringcrypto: HMAC size:", C._goboringcrypto_HMAC_size(&h.ctx), "!=", h.size)
+               panic("boringcrypto: HMAC size mismatch")
+       }
+       runtime.KeepAlive(h) // Next line will keep h alive too; just making doubly sure.
+       h.sum = nil
+}
+
+func (h *boringHMAC) finalize() {
+       C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx)
+}
+
+func (h *boringHMAC) Write(p []byte) (int, error) {
+       if len(p) > 0 {
+               C._goboringcrypto_HMAC_Update(&h.ctx, (*C.uint8_t)(unsafe.Pointer(&p[0])), C.size_t(len(p)))
+       }
+       runtime.KeepAlive(h)
+       return len(p), nil
+}
+
+func (h *boringHMAC) Size() int {
+       return h.size
+}
+
+func (h *boringHMAC) BlockSize() int {
+       return h.blockSize
+}
+
+func (h *boringHMAC) Sum(in []byte) []byte {
+       if h.sum == nil {
+               size := h.Size()
+               h.sum = make([]byte, size)
+       }
+       // Make copy of context because Go hash.Hash mandates
+       // that Sum has no effect on the underlying stream.
+       // In particular it is OK to Sum, then Write more, then Sum again,
+       // and the second Sum acts as if the first didn't happen.
+       C._goboringcrypto_HMAC_CTX_init(&h.ctx2)
+       if C._goboringcrypto_HMAC_CTX_copy_ex(&h.ctx2, &h.ctx) == 0 {
+               panic("boringcrypto: HMAC_CTX_copy_ex failed")
+       }
+       C._goboringcrypto_HMAC_Final(&h.ctx2, (*C.uint8_t)(unsafe.Pointer(&h.sum[0])), nil)
+       C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx2)
+       return append(in, h.sum...)
+}
diff --git a/src/crypto/internal/boring/notboring.go b/src/crypto/internal/boring/notboring.go
new file mode 100644 (file)
index 0000000..c21cb3c
--- /dev/null
@@ -0,0 +1,109 @@
+// 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.
+
+// +build !linux !amd64 !cgo android cmd_go_bootstrap msan
+
+package boring
+
+import (
+       "crypto"
+       "crypto/cipher"
+       "crypto/internal/boring/sig"
+       "hash"
+       "math/big"
+)
+
+const available = false
+
+// Unreachable marks code that should be unreachable
+// when BoringCrypto is in use. It is a no-op without BoringCrypto.
+func Unreachable() {
+       // Code that's unreachable when using BoringCrypto
+       // is exactly the code we want to detect for reporting
+       // standard Go crypto.
+       sig.StandardCrypto()
+}
+
+// UnreachableExceptTests marks code that should be unreachable
+// when BoringCrypto is in use. It is a no-op without BoringCrypto.
+func UnreachableExceptTests() {}
+
+type randReader int
+
+func (randReader) Read(b []byte) (int, error) { panic("boringcrypto: not available") }
+
+const RandReader = randReader(0)
+
+func NewSHA1() hash.Hash   { panic("boringcrypto: not available") }
+func NewSHA224() hash.Hash { panic("boringcrypto: not available") }
+func NewSHA256() hash.Hash { panic("boringcrypto: not available") }
+func NewSHA384() hash.Hash { panic("boringcrypto: not available") }
+func NewSHA512() hash.Hash { panic("boringcrypto: not available") }
+
+func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { panic("boringcrypto: not available") }
+
+func NewAESCipher(key []byte) (cipher.Block, error) { panic("boringcrypto: not available") }
+
+type PublicKeyECDSA struct{ _ int }
+type PrivateKeyECDSA struct{ _ int }
+
+func GenerateKeyECDSA(curve string) (X, Y, D *big.Int, err error) {
+       panic("boringcrypto: not available")
+}
+func NewPrivateKeyECDSA(curve string, X, Y, D *big.Int) (*PrivateKeyECDSA, error) {
+       panic("boringcrypto: not available")
+}
+func NewPublicKeyECDSA(curve string, X, Y *big.Int) (*PublicKeyECDSA, error) {
+       panic("boringcrypto: not available")
+}
+func SignECDSA(priv *PrivateKeyECDSA, hash []byte) (r, s *big.Int, err error) {
+       panic("boringcrypto: not available")
+}
+func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) {
+       panic("boringcrypto: not available")
+}
+func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, r, s *big.Int) bool {
+       panic("boringcrypto: not available")
+}
+
+type PublicKeyRSA struct{ _ int }
+type PrivateKeyRSA struct{ _ int }
+
+func DecryptRSAOAEP(h hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) {
+       panic("boringcrypto: not available")
+}
+func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) {
+       panic("boringcrypto: not available")
+}
+func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) {
+       panic("boringcrypto: not available")
+}
+func EncryptRSAOAEP(h hash.Hash, pub *PublicKeyRSA, msg, label []byte) ([]byte, error) {
+       panic("boringcrypto: not available")
+}
+func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) ([]byte, error) {
+       panic("boringcrypto: not available")
+}
+func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) ([]byte, error) {
+       panic("boringcrypto: not available")
+}
+func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) {
+       panic("boringcrypto: not available")
+}
+func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv *big.Int) (*PrivateKeyRSA, error) {
+       panic("boringcrypto: not available")
+}
+func NewPublicKeyRSA(N, E *big.Int) (*PublicKeyRSA, error) { panic("boringcrypto: not available") }
+func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) {
+       panic("boringcrypto: not available")
+}
+func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) {
+       panic("boringcrypto: not available")
+}
+func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error {
+       panic("boringcrypto: not available")
+}
+func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error {
+       panic("boringcrypto: not available")
+}
diff --git a/src/crypto/internal/boring/rand.go b/src/crypto/internal/boring/rand.go
new file mode 100644 (file)
index 0000000..c3fc27c
--- /dev/null
@@ -0,0 +1,27 @@
+// 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.
+
+// +build linux,amd64
+// +build !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import "unsafe"
+
+type randReader int
+
+func (randReader) Read(b []byte) (int, error) {
+       // Note: RAND_bytes should never fail; the return value exists only for historical reasons.
+       // We check it even so.
+       if len(b) > 0 && C._goboringcrypto_RAND_bytes((*C.uint8_t)(unsafe.Pointer(&b[0])), C.size_t(len(b))) == 0 {
+               return 0, fail("RAND_bytes")
+       }
+       return len(b), nil
+}
+
+const RandReader = randReader(0)
diff --git a/src/crypto/internal/boring/rsa.go b/src/crypto/internal/boring/rsa.go
new file mode 100644 (file)
index 0000000..a10831d
--- /dev/null
@@ -0,0 +1,350 @@
+// 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.
+
+// +build linux,amd64
+// +build !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+       "crypto"
+       "crypto/subtle"
+       "errors"
+       "hash"
+       "math/big"
+       "runtime"
+       "strconv"
+       "unsafe"
+)
+
+func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) {
+       bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) {
+               return nil, nil, nil, nil, nil, nil, nil, nil, e
+       }
+
+       key := C._goboringcrypto_RSA_new()
+       if key == nil {
+               return bad(fail("RSA_new"))
+       }
+       defer C._goboringcrypto_RSA_free(key)
+
+       if C._goboringcrypto_RSA_generate_key_fips(key, C.int(bits), nil) == 0 {
+               return bad(fail("RSA_generate_key_fips"))
+       }
+
+       var n, e, d, p, q, dp, dq, qinv *C.GO_BIGNUM
+       C._goboringcrypto_RSA_get0_key(key, &n, &e, &d)
+       C._goboringcrypto_RSA_get0_factors(key, &p, &q)
+       C._goboringcrypto_RSA_get0_crt_params(key, &dp, &dq, &qinv)
+       return bnToBig(n), bnToBig(e), bnToBig(d), bnToBig(p), bnToBig(q), bnToBig(dp), bnToBig(dq), bnToBig(qinv), nil
+}
+
+type PublicKeyRSA struct {
+       // _key MUST NOT be accessed directly. Instead, use the withKey method.
+       _key *C.GO_RSA
+}
+
+func NewPublicKeyRSA(N, E *big.Int) (*PublicKeyRSA, error) {
+       key := C._goboringcrypto_RSA_new()
+       if key == nil {
+               return nil, fail("RSA_new")
+       }
+       if !bigToBn(&key.n, N) ||
+               !bigToBn(&key.e, E) {
+               return nil, fail("BN_bin2bn")
+       }
+       k := &PublicKeyRSA{_key: key}
+       runtime.SetFinalizer(k, (*PublicKeyRSA).finalize)
+       return k, nil
+}
+
+func (k *PublicKeyRSA) finalize() {
+       C._goboringcrypto_RSA_free(k._key)
+}
+
+func (k *PublicKeyRSA) withKey(f func(*C.GO_RSA) C.int) C.int {
+       // Because of the finalizer, any time _key is passed to cgo, that call must
+       // be followed by a call to runtime.KeepAlive, to make sure k is not
+       // collected (and finalized) before the cgo call returns.
+       defer runtime.KeepAlive(k)
+       return f(k._key)
+}
+
+type PrivateKeyRSA struct {
+       // _key MUST NOT be accessed directly. Instead, use the withKey method.
+       _key *C.GO_RSA
+}
+
+func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv *big.Int) (*PrivateKeyRSA, error) {
+       key := C._goboringcrypto_RSA_new()
+       if key == nil {
+               return nil, fail("RSA_new")
+       }
+       if !bigToBn(&key.n, N) ||
+               !bigToBn(&key.e, E) ||
+               !bigToBn(&key.d, D) ||
+               !bigToBn(&key.p, P) ||
+               !bigToBn(&key.q, Q) ||
+               !bigToBn(&key.dmp1, Dp) ||
+               !bigToBn(&key.dmq1, Dq) ||
+               !bigToBn(&key.iqmp, Qinv) {
+               return nil, fail("BN_bin2bn")
+       }
+       k := &PrivateKeyRSA{_key: key}
+       runtime.SetFinalizer(k, (*PrivateKeyRSA).finalize)
+       return k, nil
+}
+
+func (k *PrivateKeyRSA) finalize() {
+       C._goboringcrypto_RSA_free(k._key)
+}
+
+func (k *PrivateKeyRSA) withKey(f func(*C.GO_RSA) C.int) C.int {
+       // Because of the finalizer, any time _key is passed to cgo, that call must
+       // be followed by a call to runtime.KeepAlive, to make sure k is not
+       // collected (and finalized) before the cgo call returns.
+       defer runtime.KeepAlive(k)
+       return f(k._key)
+}
+
+func setupRSA(withKey func(func(*C.GO_RSA) C.int) C.int,
+       padding C.int, h hash.Hash, label []byte, saltLen int, ch crypto.Hash,
+       init func(*C.GO_EVP_PKEY_CTX) C.int) (pkey *C.GO_EVP_PKEY, ctx *C.GO_EVP_PKEY_CTX, err error) {
+       defer func() {
+               if err != nil {
+                       if pkey != nil {
+                               C._goboringcrypto_EVP_PKEY_free(pkey)
+                               pkey = nil
+                       }
+                       if ctx != nil {
+                               C._goboringcrypto_EVP_PKEY_CTX_free(ctx)
+                               ctx = nil
+                       }
+               }
+       }()
+
+       pkey = C._goboringcrypto_EVP_PKEY_new()
+       if pkey == nil {
+               return nil, nil, fail("EVP_PKEY_new")
+       }
+       if withKey(func(key *C.GO_RSA) C.int {
+               return C._goboringcrypto_EVP_PKEY_set1_RSA(pkey, key)
+       }) == 0 {
+               return nil, nil, fail("EVP_PKEY_set1_RSA")
+       }
+       ctx = C._goboringcrypto_EVP_PKEY_CTX_new(pkey, nil)
+       if ctx == nil {
+               return nil, nil, fail("EVP_PKEY_CTX_new")
+       }
+       if init(ctx) == 0 {
+               return nil, nil, fail("EVP_PKEY_operation_init")
+       }
+       if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, padding) == 0 {
+               return nil, nil, fail("EVP_PKEY_CTX_set_rsa_padding")
+       }
+       if padding == C.GO_RSA_PKCS1_OAEP_PADDING {
+               md := hashToMD(h)
+               if md == nil {
+                       return nil, nil, errors.New("crypto/rsa: unsupported hash function")
+               }
+               if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) == 0 {
+                       return nil, nil, fail("EVP_PKEY_set_rsa_oaep_md")
+               }
+               // ctx takes ownership of label, so malloc a copy for BoringCrypto to free.
+               clabel := (*C.uint8_t)(C._goboringcrypto_OPENSSL_malloc(C.size_t(len(label))))
+               if clabel == nil {
+                       return nil, nil, fail("OPENSSL_malloc")
+               }
+               copy((*[1 << 30]byte)(unsafe.Pointer(clabel))[:len(label)], label)
+               if C._goboringcrypto_EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, clabel, C.size_t(len(label))) == 0 {
+                       return nil, nil, fail("EVP_PKEY_CTX_set0_rsa_oaep_label")
+               }
+       }
+       if padding == C.GO_RSA_PKCS1_PSS_PADDING {
+               if saltLen != 0 {
+                       if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, C.int(saltLen)) == 0 {
+                               return nil, nil, fail("EVP_PKEY_set_rsa_pss_saltlen")
+                       }
+               }
+               md := cryptoHashToMD(ch)
+               if md == nil {
+                       return nil, nil, errors.New("crypto/rsa: unsupported hash function")
+               }
+               if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) == 0 {
+                       return nil, nil, fail("EVP_PKEY_set_rsa_mgf1_md")
+               }
+       }
+
+       return pkey, ctx, nil
+}
+
+func cryptRSA(withKey func(func(*C.GO_RSA) C.int) C.int,
+       padding C.int, h hash.Hash, label []byte, saltLen int, ch crypto.Hash,
+       init func(*C.GO_EVP_PKEY_CTX) C.int,
+       crypt func(*C.GO_EVP_PKEY_CTX, *C.uint8_t, *C.size_t, *C.uint8_t, C.size_t) C.int,
+       in []byte) ([]byte, error) {
+
+       pkey, ctx, err := setupRSA(withKey, padding, h, label, saltLen, ch, init)
+       if err != nil {
+               return nil, err
+       }
+       defer C._goboringcrypto_EVP_PKEY_free(pkey)
+       defer C._goboringcrypto_EVP_PKEY_CTX_free(ctx)
+
+       var outLen C.size_t
+       if crypt(ctx, nil, &outLen, base(in), C.size_t(len(in))) == 0 {
+               return nil, fail("EVP_PKEY_decrypt/encrypt")
+       }
+       out := make([]byte, outLen)
+       if crypt(ctx, base(out), &outLen, base(in), C.size_t(len(in))) == 0 {
+               return nil, fail("EVP_PKEY_decrypt/encrypt")
+       }
+       return out[:outLen], nil
+}
+
+func DecryptRSAOAEP(h hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) {
+       return cryptRSA(priv.withKey, C.GO_RSA_PKCS1_OAEP_PADDING, h, label, 0, 0, decryptInit, decrypt, ciphertext)
+}
+
+func EncryptRSAOAEP(h hash.Hash, pub *PublicKeyRSA, msg, label []byte) ([]byte, error) {
+       return cryptRSA(pub.withKey, C.GO_RSA_PKCS1_OAEP_PADDING, h, label, 0, 0, encryptInit, encrypt, msg)
+}
+
+func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) {
+       return cryptRSA(priv.withKey, C.GO_RSA_PKCS1_PADDING, nil, nil, 0, 0, decryptInit, decrypt, ciphertext)
+}
+
+func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) ([]byte, error) {
+       return cryptRSA(pub.withKey, C.GO_RSA_PKCS1_PADDING, nil, nil, 0, 0, encryptInit, encrypt, msg)
+}
+
+func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) {
+       return cryptRSA(priv.withKey, C.GO_RSA_NO_PADDING, nil, nil, 0, 0, decryptInit, decrypt, ciphertext)
+}
+
+func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) ([]byte, error) {
+       return cryptRSA(pub.withKey, C.GO_RSA_NO_PADDING, nil, nil, 0, 0, encryptInit, encrypt, msg)
+}
+
+// These dumb wrappers work around the fact that cgo functions cannot be used as values directly.
+
+func decryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int {
+       return C._goboringcrypto_EVP_PKEY_decrypt_init(ctx)
+}
+
+func decrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int {
+       return C._goboringcrypto_EVP_PKEY_decrypt(ctx, out, outLen, in, inLen)
+}
+
+func encryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int {
+       return C._goboringcrypto_EVP_PKEY_encrypt_init(ctx)
+}
+
+func encrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int {
+       return C._goboringcrypto_EVP_PKEY_encrypt(ctx, out, outLen, in, inLen)
+}
+
+func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) {
+       md := cryptoHashToMD(h)
+       if md == nil {
+               return nil, errors.New("crypto/rsa: unsupported hash function")
+       }
+       if saltLen == 0 {
+               saltLen = -1
+       }
+       var out []byte
+       var outLen C.size_t
+       if priv.withKey(func(key *C.GO_RSA) C.int {
+               out = make([]byte, C._goboringcrypto_RSA_size(key))
+               return C._goboringcrypto_RSA_sign_pss_mgf1(key, &outLen, base(out), C.size_t(len(out)),
+                       base(hashed), C.size_t(len(hashed)), md, nil, C.int(saltLen))
+       }) == 0 {
+               return nil, fail("RSA_sign_pss_mgf1")
+       }
+
+       return out[:outLen], nil
+}
+
+func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error {
+       md := cryptoHashToMD(h)
+       if md == nil {
+               return errors.New("crypto/rsa: unsupported hash function")
+       }
+       if saltLen == 0 {
+               saltLen = -2 // auto-recover
+       }
+       if pub.withKey(func(key *C.GO_RSA) C.int {
+               return C._goboringcrypto_RSA_verify_pss_mgf1(key, base(hashed), C.size_t(len(hashed)),
+                       md, nil, C.int(saltLen), base(sig), C.size_t(len(sig)))
+       }) == 0 {
+               return fail("RSA_verify_pss_mgf1")
+       }
+       return nil
+}
+
+func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) {
+       if h == 0 {
+               // No hashing.
+               var out []byte
+               var outLen C.size_t
+               if priv.withKey(func(key *C.GO_RSA) C.int {
+                       out = make([]byte, C._goboringcrypto_RSA_size(key))
+                       return C._goboringcrypto_RSA_sign_raw(key, &outLen, base(out), C.size_t(len(out)),
+                               base(hashed), C.size_t(len(hashed)), C.GO_RSA_PKCS1_PADDING)
+               }) == 0 {
+                       return nil, fail("RSA_sign_raw")
+               }
+               return out[:outLen], nil
+       }
+
+       md := cryptoHashToMD(h)
+       if md == nil {
+               return nil, errors.New("crypto/rsa: unsupported hash function: " + strconv.Itoa(int(h)))
+       }
+       nid := C._goboringcrypto_EVP_MD_type(md)
+       var out []byte
+       var outLen C.uint
+       if priv.withKey(func(key *C.GO_RSA) C.int {
+               out = make([]byte, C._goboringcrypto_RSA_size(key))
+               return C._goboringcrypto_RSA_sign(nid, base(hashed), C.uint(len(hashed)),
+                       base(out), &outLen, key)
+       }) == 0 {
+               return nil, fail("RSA_sign")
+       }
+       return out[:outLen], nil
+}
+
+func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error {
+       if h == 0 {
+               var out []byte
+               var outLen C.size_t
+               if pub.withKey(func(key *C.GO_RSA) C.int {
+                       out = make([]byte, C._goboringcrypto_RSA_size(key))
+                       return C._goboringcrypto_RSA_verify_raw(key, &outLen, base(out),
+                               C.size_t(len(out)), base(sig), C.size_t(len(sig)), C.GO_RSA_PKCS1_PADDING)
+               }) == 0 {
+                       return fail("RSA_verify")
+               }
+               if subtle.ConstantTimeCompare(hashed, out[:outLen]) != 1 {
+                       return fail("RSA_verify")
+               }
+               return nil
+       }
+       md := cryptoHashToMD(h)
+       if md == nil {
+               return errors.New("crypto/rsa: unsupported hash function")
+       }
+       nid := C._goboringcrypto_EVP_MD_type(md)
+       if pub.withKey(func(key *C.GO_RSA) C.int {
+               return C._goboringcrypto_RSA_verify(nid, base(hashed), C.size_t(len(hashed)),
+                       base(sig), C.size_t(len(sig)), key)
+       }) == 0 {
+               return fail("RSA_verify")
+       }
+       return nil
+}
diff --git a/src/crypto/internal/boring/sha.go b/src/crypto/internal/boring/sha.go
new file mode 100644 (file)
index 0000000..5ca158c
--- /dev/null
@@ -0,0 +1,480 @@
+// 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.
+
+// +build linux,amd64
+// +build !android
+// +build !cmd_go_bootstrap
+// +build !msan
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+       "errors"
+       "hash"
+       "unsafe"
+)
+
+// NewSHA1 returns a new SHA1 hash.
+func NewSHA1() hash.Hash {
+       h := new(sha1Hash)
+       h.Reset()
+       return h
+}
+
+type sha1Hash struct {
+       ctx C.GO_SHA_CTX
+       out [20]byte
+}
+
+type sha1Ctx struct {
+       h      [5]uint32
+       nl, nh uint32
+       x      [64]byte
+       nx     uint32
+}
+
+func (h *sha1Hash) Reset()               { C._goboringcrypto_SHA1_Init(&h.ctx) }
+func (h *sha1Hash) Size() int            { return 20 }
+func (h *sha1Hash) BlockSize() int       { return 64 }
+func (h *sha1Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
+
+func (h *sha1Hash) Write(p []byte) (int, error) {
+       if len(p) > 0 && C._goboringcrypto_SHA1_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
+               panic("boringcrypto: SHA1_Update failed")
+       }
+       return len(p), nil
+}
+
+func (h0 *sha1Hash) sum() []byte {
+       h := *h0 // make copy so future Write+Sum is valid
+       if C._goboringcrypto_SHA1_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
+               panic("boringcrypto: SHA1_Final failed")
+       }
+       return h.out[:]
+}
+
+const (
+       sha1Magic         = "sha\x01"
+       sha1MarshaledSize = len(sha1Magic) + 5*4 + 64 + 8
+)
+
+func (h *sha1Hash) MarshalBinary() ([]byte, error) {
+       d := (*sha1Ctx)(unsafe.Pointer(&h.ctx))
+       b := make([]byte, 0, sha1MarshaledSize)
+       b = append(b, sha1Magic...)
+       b = appendUint32(b, d.h[0])
+       b = appendUint32(b, d.h[1])
+       b = appendUint32(b, d.h[2])
+       b = appendUint32(b, d.h[3])
+       b = appendUint32(b, d.h[4])
+       b = append(b, d.x[:d.nx]...)
+       b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+       b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
+       return b, nil
+}
+
+func (h *sha1Hash) UnmarshalBinary(b []byte) error {
+       if len(b) < len(sha1Magic) || string(b[:len(sha1Magic)]) != sha1Magic {
+               return errors.New("crypto/sha1: invalid hash state identifier")
+       }
+       if len(b) != sha1MarshaledSize {
+               return errors.New("crypto/sha1: invalid hash state size")
+       }
+       d := (*sha1Ctx)(unsafe.Pointer(&h.ctx))
+       b = b[len(sha1Magic):]
+       b, d.h[0] = consumeUint32(b)
+       b, d.h[1] = consumeUint32(b)
+       b, d.h[2] = consumeUint32(b)
+       b, d.h[3] = consumeUint32(b)
+       b, d.h[4] = consumeUint32(b)
+       b = b[copy(d.x[:], b):]
+       b, n := consumeUint64(b)
+       d.nl = uint32(n << 3)
+       d.nh = uint32(n >> 29)
+       d.nx = uint32(n) % 64
+       return nil
+}
+
+// NewSHA224 returns a new SHA224 hash.
+func NewSHA224() hash.Hash {
+       h := new(sha224Hash)
+       h.Reset()
+       return h
+}
+
+type sha224Hash struct {
+       ctx C.GO_SHA256_CTX
+       out [224 / 8]byte
+}
+
+func (h *sha224Hash) Reset()               { C._goboringcrypto_SHA224_Init(&h.ctx) }
+func (h *sha224Hash) Size() int            { return 224 / 8 }
+func (h *sha224Hash) BlockSize() int       { return 64 }
+func (h *sha224Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
+
+func (h *sha224Hash) Write(p []byte) (int, error) {
+       if len(p) > 0 && C._goboringcrypto_SHA224_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
+               panic("boringcrypto: SHA224_Update failed")
+       }
+       return len(p), nil
+}
+
+func (h0 *sha224Hash) sum() []byte {
+       h := *h0 // make copy so future Write+Sum is valid
+       if C._goboringcrypto_SHA224_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
+               panic("boringcrypto: SHA224_Final failed")
+       }
+       return h.out[:]
+}
+
+// NewSHA256 returns a new SHA256 hash.
+func NewSHA256() hash.Hash {
+       h := new(sha256Hash)
+       h.Reset()
+       return h
+}
+
+type sha256Hash struct {
+       ctx C.GO_SHA256_CTX
+       out [256 / 8]byte
+}
+
+func (h *sha256Hash) Reset()               { C._goboringcrypto_SHA256_Init(&h.ctx) }
+func (h *sha256Hash) Size() int            { return 256 / 8 }
+func (h *sha256Hash) BlockSize() int       { return 64 }
+func (h *sha256Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
+
+func (h *sha256Hash) Write(p []byte) (int, error) {
+       if len(p) > 0 && C._goboringcrypto_SHA256_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
+               panic("boringcrypto: SHA256_Update failed")
+       }
+       return len(p), nil
+}
+
+func (h0 *sha256Hash) sum() []byte {
+       h := *h0 // make copy so future Write+Sum is valid
+       if C._goboringcrypto_SHA256_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
+               panic("boringcrypto: SHA256_Final failed")
+       }
+       return h.out[:]
+}
+
+const (
+       magic224         = "sha\x02"
+       magic256         = "sha\x03"
+       marshaledSize256 = len(magic256) + 8*4 + 64 + 8
+)
+
+type sha256Ctx struct {
+       h      [8]uint32
+       nl, nh uint32
+       x      [64]byte
+       nx     uint32
+}
+
+func (h *sha224Hash) MarshalBinary() ([]byte, error) {
+       d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
+       b := make([]byte, 0, marshaledSize256)
+       b = append(b, magic224...)
+       b = appendUint32(b, d.h[0])
+       b = appendUint32(b, d.h[1])
+       b = appendUint32(b, d.h[2])
+       b = appendUint32(b, d.h[3])
+       b = appendUint32(b, d.h[4])
+       b = appendUint32(b, d.h[5])
+       b = appendUint32(b, d.h[6])
+       b = appendUint32(b, d.h[7])
+       b = append(b, d.x[:d.nx]...)
+       b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+       b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
+       return b, nil
+}
+
+func (h *sha256Hash) MarshalBinary() ([]byte, error) {
+       d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
+       b := make([]byte, 0, marshaledSize256)
+       b = append(b, magic256...)
+       b = appendUint32(b, d.h[0])
+       b = appendUint32(b, d.h[1])
+       b = appendUint32(b, d.h[2])
+       b = appendUint32(b, d.h[3])
+       b = appendUint32(b, d.h[4])
+       b = appendUint32(b, d.h[5])
+       b = appendUint32(b, d.h[6])
+       b = appendUint32(b, d.h[7])
+       b = append(b, d.x[:d.nx]...)
+       b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+       b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
+       return b, nil
+}
+
+func (h *sha224Hash) UnmarshalBinary(b []byte) error {
+       if len(b) < len(magic224) || string(b[:len(magic224)]) != magic224 {
+               return errors.New("crypto/sha256: invalid hash state identifier")
+       }
+       if len(b) != marshaledSize256 {
+               return errors.New("crypto/sha256: invalid hash state size")
+       }
+       d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
+       b = b[len(magic224):]
+       b, d.h[0] = consumeUint32(b)
+       b, d.h[1] = consumeUint32(b)
+       b, d.h[2] = consumeUint32(b)
+       b, d.h[3] = consumeUint32(b)
+       b, d.h[4] = consumeUint32(b)
+       b, d.h[5] = consumeUint32(b)
+       b, d.h[6] = consumeUint32(b)
+       b, d.h[7] = consumeUint32(b)
+       b = b[copy(d.x[:], b):]
+       b, n := consumeUint64(b)
+       d.nl = uint32(n << 3)
+       d.nh = uint32(n >> 29)
+       d.nx = uint32(n) % 64
+       return nil
+}
+
+func (h *sha256Hash) UnmarshalBinary(b []byte) error {
+       if len(b) < len(magic256) || string(b[:len(magic256)]) != magic256 {
+               return errors.New("crypto/sha256: invalid hash state identifier")
+       }
+       if len(b) != marshaledSize256 {
+               return errors.New("crypto/sha256: invalid hash state size")
+       }
+       d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
+       b = b[len(magic256):]
+       b, d.h[0] = consumeUint32(b)
+       b, d.h[1] = consumeUint32(b)
+       b, d.h[2] = consumeUint32(b)
+       b, d.h[3] = consumeUint32(b)
+       b, d.h[4] = consumeUint32(b)
+       b, d.h[5] = consumeUint32(b)
+       b, d.h[6] = consumeUint32(b)
+       b, d.h[7] = consumeUint32(b)
+       b = b[copy(d.x[:], b):]
+       b, n := consumeUint64(b)
+       d.nl = uint32(n << 3)
+       d.nh = uint32(n >> 29)
+       d.nx = uint32(n) % 64
+       return nil
+}
+
+// NewSHA384 returns a new SHA384 hash.
+func NewSHA384() hash.Hash {
+       h := new(sha384Hash)
+       h.Reset()
+       return h
+}
+
+type sha384Hash struct {
+       ctx C.GO_SHA512_CTX
+       out [384 / 8]byte
+}
+
+func (h *sha384Hash) Reset()               { C._goboringcrypto_SHA384_Init(&h.ctx) }
+func (h *sha384Hash) Size() int            { return 384 / 8 }
+func (h *sha384Hash) BlockSize() int       { return 128 }
+func (h *sha384Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
+
+func (h *sha384Hash) Write(p []byte) (int, error) {
+       if len(p) > 0 && C._goboringcrypto_SHA384_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
+               panic("boringcrypto: SHA384_Update failed")
+       }
+       return len(p), nil
+}
+
+func (h0 *sha384Hash) sum() []byte {
+       h := *h0 // make copy so future Write+Sum is valid
+       if C._goboringcrypto_SHA384_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
+               panic("boringcrypto: SHA384_Final failed")
+       }
+       return h.out[:]
+}
+
+// NewSHA512 returns a new SHA512 hash.
+func NewSHA512() hash.Hash {
+       h := new(sha512Hash)
+       h.Reset()
+       return h
+}
+
+type sha512Hash struct {
+       ctx C.GO_SHA512_CTX
+       out [512 / 8]byte
+}
+
+func (h *sha512Hash) Reset()               { C._goboringcrypto_SHA512_Init(&h.ctx) }
+func (h *sha512Hash) Size() int            { return 512 / 8 }
+func (h *sha512Hash) BlockSize() int       { return 128 }
+func (h *sha512Hash) Sum(in []byte) []byte { return append(in, h.sum()...) }
+
+func (h *sha512Hash) Write(p []byte) (int, error) {
+       if len(p) > 0 && C._goboringcrypto_SHA512_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 {
+               panic("boringcrypto: SHA512_Update failed")
+       }
+       return len(p), nil
+}
+
+func (h0 *sha512Hash) sum() []byte {
+       h := *h0 // make copy so future Write+Sum is valid
+       if C._goboringcrypto_SHA512_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 {
+               panic("boringcrypto: SHA512_Final failed")
+       }
+       return h.out[:]
+}
+
+type sha512Ctx struct {
+       h      [8]uint64
+       nl, nh uint64
+       x      [128]byte
+       nx     uint32
+}
+
+const (
+       magic384         = "sha\x04"
+       magic512_224     = "sha\x05"
+       magic512_256     = "sha\x06"
+       magic512         = "sha\x07"
+       marshaledSize512 = len(magic512) + 8*8 + 128 + 8
+)
+
+var zero [128]byte
+
+func (h *sha384Hash) MarshalBinary() ([]byte, error) {
+       d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
+       b := make([]byte, 0, marshaledSize512)
+       b = append(b, magic384...)
+       b = appendUint64(b, d.h[0])
+       b = appendUint64(b, d.h[1])
+       b = appendUint64(b, d.h[2])
+       b = appendUint64(b, d.h[3])
+       b = appendUint64(b, d.h[4])
+       b = appendUint64(b, d.h[5])
+       b = appendUint64(b, d.h[6])
+       b = appendUint64(b, d.h[7])
+       b = append(b, d.x[:d.nx]...)
+       b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+       b = appendUint64(b, d.nl>>3|d.nh<<61)
+       return b, nil
+}
+
+func (h *sha512Hash) MarshalBinary() ([]byte, error) {
+       d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
+       b := make([]byte, 0, marshaledSize512)
+       b = append(b, magic512...)
+       b = appendUint64(b, d.h[0])
+       b = appendUint64(b, d.h[1])
+       b = appendUint64(b, d.h[2])
+       b = appendUint64(b, d.h[3])
+       b = appendUint64(b, d.h[4])
+       b = appendUint64(b, d.h[5])
+       b = appendUint64(b, d.h[6])
+       b = appendUint64(b, d.h[7])
+       b = append(b, d.x[:d.nx]...)
+       b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+       b = appendUint64(b, d.nl>>3|d.nh<<61)
+       return b, nil
+}
+
+func (h *sha384Hash) UnmarshalBinary(b []byte) error {
+       if len(b) < len(magic512) {
+               return errors.New("crypto/sha512: invalid hash state identifier")
+       }
+       if string(b[:len(magic384)]) != magic384 {
+               return errors.New("crypto/sha512: invalid hash state identifier")
+       }
+       if len(b) != marshaledSize512 {
+               return errors.New("crypto/sha512: invalid hash state size")
+       }
+       d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
+       b = b[len(magic512):]
+       b, d.h[0] = consumeUint64(b)
+       b, d.h[1] = consumeUint64(b)
+       b, d.h[2] = consumeUint64(b)
+       b, d.h[3] = consumeUint64(b)
+       b, d.h[4] = consumeUint64(b)
+       b, d.h[5] = consumeUint64(b)
+       b, d.h[6] = consumeUint64(b)
+       b, d.h[7] = consumeUint64(b)
+       b = b[copy(d.x[:], b):]
+       b, n := consumeUint64(b)
+       d.nl = n << 3
+       d.nh = n >> 61
+       d.nx = uint32(n) % 128
+       return nil
+}
+
+func (h *sha512Hash) UnmarshalBinary(b []byte) error {
+       if len(b) < len(magic512) {
+               return errors.New("crypto/sha512: invalid hash state identifier")
+       }
+       if string(b[:len(magic512)]) != magic512 {
+               return errors.New("crypto/sha512: invalid hash state identifier")
+       }
+       if len(b) != marshaledSize512 {
+               return errors.New("crypto/sha512: invalid hash state size")
+       }
+       d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
+       b = b[len(magic512):]
+       b, d.h[0] = consumeUint64(b)
+       b, d.h[1] = consumeUint64(b)
+       b, d.h[2] = consumeUint64(b)
+       b, d.h[3] = consumeUint64(b)
+       b, d.h[4] = consumeUint64(b)
+       b, d.h[5] = consumeUint64(b)
+       b, d.h[6] = consumeUint64(b)
+       b, d.h[7] = consumeUint64(b)
+       b = b[copy(d.x[:], b):]
+       b, n := consumeUint64(b)
+       d.nl = n << 3
+       d.nh = n >> 61
+       d.nx = uint32(n) % 128
+       return nil
+}
+
+func appendUint64(b []byte, x uint64) []byte {
+       var a [8]byte
+       putUint64(a[:], x)
+       return append(b, a[:]...)
+}
+
+func appendUint32(b []byte, x uint32) []byte {
+       var a [4]byte
+       putUint32(a[:], x)
+       return append(b, a[:]...)
+}
+
+func consumeUint64(b []byte) ([]byte, uint64) {
+       _ = b[7]
+       x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+               uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+       return b[8:], x
+}
+
+func consumeUint32(b []byte) ([]byte, uint32) {
+       _ = b[3]
+       x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+       return b[4:], x
+}
+
+func putUint64(x []byte, s uint64) {
+       _ = x[7]
+       x[0] = byte(s >> 56)
+       x[1] = byte(s >> 48)
+       x[2] = byte(s >> 40)
+       x[3] = byte(s >> 32)
+       x[4] = byte(s >> 24)
+       x[5] = byte(s >> 16)
+       x[6] = byte(s >> 8)
+       x[7] = byte(s)
+}
+
+func putUint32(x []byte, s uint32) {
+       _ = x[3]
+       x[0] = byte(s >> 24)
+       x[1] = byte(s >> 16)
+       x[2] = byte(s >> 8)
+       x[3] = byte(s)
+}
diff --git a/src/crypto/internal/boring/sig/sig.go b/src/crypto/internal/boring/sig/sig.go
new file mode 100644 (file)
index 0000000..716c03c
--- /dev/null
@@ -0,0 +1,17 @@
+// 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.
+
+// Package sig holds “code signatures” that can be called
+// and will result in certain code sequences being linked into
+// the final binary. The functions themselves are no-ops.
+package sig
+
+// BoringCrypto indicates that the BoringCrypto module is present.
+func BoringCrypto()
+
+// FIPSOnly indicates that package crypto/tls/fipsonly is present.
+func FIPSOnly()
+
+// StandardCrypto indicates that standard Go crypto is present.
+func StandardCrypto()
diff --git a/src/crypto/internal/boring/sig/sig_amd64.s b/src/crypto/internal/boring/sig/sig_amd64.s
new file mode 100644 (file)
index 0000000..64e3462
--- /dev/null
@@ -0,0 +1,54 @@
+// 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.
+
+#include "textflag.h"
+
+// These functions are no-ops, but you can search for their implementations
+// to find out whether they are linked into a particular binary.
+//
+// Each function consists of a two-byte jump over the next 29-bytes,
+// then a 5-byte indicator sequence unlikely to occur in real x86 instructions,
+// then a randomly-chosen 24-byte sequence, and finally a return instruction
+// (the target of the jump).
+//
+// These sequences are known to rsc.io/goversion.
+
+#define START \
+       BYTE $0xEB; BYTE $0x1D; BYTE $0xF4; BYTE $0x48; BYTE $0xF4; BYTE $0x4B; BYTE $0xF4
+
+#define END \
+       BYTE $0xC3
+
+// BoringCrypto indicates that BoringCrypto (in particular, its func init) is present.
+TEXT ·BoringCrypto(SB),NOSPLIT,$0
+       START
+       BYTE $0xB3; BYTE $0x32; BYTE $0xF5; BYTE $0x28;
+       BYTE $0x13; BYTE $0xA3; BYTE $0xB4; BYTE $0x50;
+       BYTE $0xD4; BYTE $0x41; BYTE $0xCC; BYTE $0x24;
+       BYTE $0x85; BYTE $0xF0; BYTE $0x01; BYTE $0x45;
+       BYTE $0x4E; BYTE $0x92; BYTE $0x10; BYTE $0x1B;
+       BYTE $0x1D; BYTE $0x2F; BYTE $0x19; BYTE $0x50;
+       END
+
+// StandardCrypto indicates that standard Go crypto is present.
+TEXT ·StandardCrypto(SB),NOSPLIT,$0
+       START
+       BYTE $0xba; BYTE $0xee; BYTE $0x4d; BYTE $0xfa;
+       BYTE $0x98; BYTE $0x51; BYTE $0xca; BYTE $0x56;
+       BYTE $0xa9; BYTE $0x11; BYTE $0x45; BYTE $0xe8;
+       BYTE $0x3e; BYTE $0x99; BYTE $0xc5; BYTE $0x9c;
+       BYTE $0xf9; BYTE $0x11; BYTE $0xcb; BYTE $0x8e;
+       BYTE $0x80; BYTE $0xda;  BYTE $0xf1; BYTE $0x2f;
+       END
+
+// FIPSOnly indicates that crypto/tls/fipsonly is present.
+TEXT ·FIPSOnly(SB),NOSPLIT,$0
+       START
+       BYTE $0x36; BYTE $0x3C; BYTE $0xB9; BYTE $0xCE;
+       BYTE $0x9D; BYTE $0x68; BYTE $0x04; BYTE $0x7D;
+       BYTE $0x31; BYTE $0xF2; BYTE $0x8D; BYTE $0x32;
+       BYTE $0x5D; BYTE $0x5C; BYTE $0xA5; BYTE $0x87;
+       BYTE $0x3F; BYTE $0x5D; BYTE $0x80; BYTE $0xCA;
+       BYTE $0xF6; BYTE $0xD6; BYTE $0x15; BYTE $0x1B;
+       END
diff --git a/src/crypto/internal/boring/sig/sig_other.s b/src/crypto/internal/boring/sig/sig_other.s
new file mode 100644 (file)
index 0000000..2eb3173
--- /dev/null
@@ -0,0 +1,19 @@
+// 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.
+
+// These functions are no-ops.
+// On amd64 they have recognizable implementations, so that you can
+// search a particular binary to see if they are present.
+// On other platforms (those using this source file), they don't.
+
+// +build !amd64
+
+TEXT ·BoringCrypto(SB),$0
+       RET
+
+TEXT ·FIPSOnly(SB),$0
+       RET
+
+TEXT ·StandardCrypto(SB),$0
+       RET
index b4276df4e1100d9b1d5a79622162b27a12fbdf67..466208879991e1a12ecf92d34b53d71885ed1b08 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package crypto
+package crypto_test
 
 import (
        "crypto/aes"
index 81277eb6a5dea924896a1fa5f87aab0315f360a2..34f4481a9bd52defd9e639d9667608ad534d16a0 100644 (file)
@@ -23,12 +23,18 @@ import (
        "time"
 )
 
+import "crypto/internal/boring"
+
 const urandomDevice = "/dev/urandom"
 
 // Easy implementation: read from /dev/urandom.
 // This is sufficient on Linux, OS X, and FreeBSD.
 
 func init() {
+       if boring.Enabled {
+               Reader = boring.RandReader
+               return
+       }
        if runtime.GOOS == "plan9" {
                Reader = newReader(nil)
        } else {
@@ -53,6 +59,7 @@ func warnBlocked() {
 }
 
 func (r *devReader) Read(b []byte) (n int, err error) {
+       boring.Unreachable()
        if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
                // First use of randomness. Start timer to warn about
                // being blocked on entropy not being available.
@@ -122,6 +129,7 @@ type reader struct {
 }
 
 func (r *reader) Read(b []byte) (n int, err error) {
+       boring.Unreachable()
        r.mu.Lock()
        defer r.mu.Unlock()
        n = len(b)
diff --git a/src/crypto/rsa/boring.go b/src/crypto/rsa/boring.go
new file mode 100644 (file)
index 0000000..0f362a2
--- /dev/null
@@ -0,0 +1,124 @@
+// 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.
+
+package rsa
+
+import (
+       "crypto/internal/boring"
+       "math/big"
+       "sync/atomic"
+       "unsafe"
+)
+
+// Cached conversions from Go PublicKey/PrivateKey to BoringCrypto.
+//
+// A new 'boring atomic.Value' field in both PublicKey and PrivateKey
+// serves as a cache for the most recent conversion. The cache is an
+// atomic.Value because code might reasonably set up a key and then
+// (thinking it immutable) use it from multiple goroutines simultaneously.
+// The first operation initializes the cache; if there are multiple simultaneous
+// first operations, they will do redundant work but not step on each other.
+//
+// We could just assume that once used in a sign/verify/encrypt/decrypt operation,
+// a particular key is never again modified, but that has not been a
+// stated assumption before. Just in case there is any existing code that
+// does modify the key between operations, we save the original values
+// alongside the cached BoringCrypto key and check that the real key
+// still matches before using the cached key. The theory is that the real
+// operations are significantly more expensive than the comparison.
+
+type boringPub struct {
+       key  *boring.PublicKeyRSA
+       orig PublicKey
+}
+
+func boringPublicKey(pub *PublicKey) (*boring.PublicKeyRSA, error) {
+       b := (*boringPub)(atomic.LoadPointer(&pub.boring))
+       if b != nil && publicKeyEqual(&b.orig, pub) {
+               return b.key, nil
+       }
+
+       b = new(boringPub)
+       b.orig = copyPublicKey(pub)
+       key, err := boring.NewPublicKeyRSA(b.orig.N, big.NewInt(int64(b.orig.E)))
+       if err != nil {
+               return nil, err
+       }
+       b.key = key
+       atomic.StorePointer(&pub.boring, unsafe.Pointer(b))
+       return key, nil
+}
+
+type boringPriv struct {
+       key  *boring.PrivateKeyRSA
+       orig PrivateKey
+}
+
+func boringPrivateKey(priv *PrivateKey) (*boring.PrivateKeyRSA, error) {
+       b := (*boringPriv)(atomic.LoadPointer(&priv.boring))
+       if b != nil && privateKeyEqual(&b.orig, priv) {
+               return b.key, nil
+       }
+
+       b = new(boringPriv)
+       b.orig = copyPrivateKey(priv)
+
+       var N, E, D, P, Q, Dp, Dq, Qinv *big.Int
+       N = b.orig.N
+       E = big.NewInt(int64(b.orig.E))
+       D = b.orig.D
+       if len(b.orig.Primes) == 2 {
+               P = b.orig.Primes[0]
+               Q = b.orig.Primes[1]
+               Dp = b.orig.Precomputed.Dp
+               Dq = b.orig.Precomputed.Dq
+               Qinv = b.orig.Precomputed.Qinv
+       }
+       key, err := boring.NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv)
+       if err != nil {
+               return nil, err
+       }
+       b.key = key
+       atomic.StorePointer(&priv.boring, unsafe.Pointer(b))
+       return key, nil
+}
+
+func publicKeyEqual(k1, k2 *PublicKey) bool {
+       return k1.N != nil &&
+               k1.N.Cmp(k2.N) == 0 &&
+               k1.E == k2.E
+}
+
+func copyPublicKey(k *PublicKey) PublicKey {
+       return PublicKey{
+               N: new(big.Int).Set(k.N),
+               E: k.E,
+       }
+}
+
+func privateKeyEqual(k1, k2 *PrivateKey) bool {
+       return publicKeyEqual(&k1.PublicKey, &k2.PublicKey) &&
+               k1.D.Cmp(k2.D) == 0
+}
+
+func copyPrivateKey(k *PrivateKey) PrivateKey {
+       dst := PrivateKey{
+               PublicKey: copyPublicKey(&k.PublicKey),
+               D:         new(big.Int).Set(k.D),
+       }
+       dst.Primes = make([]*big.Int, len(k.Primes))
+       for i, p := range k.Primes {
+               dst.Primes[i] = new(big.Int).Set(p)
+       }
+       if x := k.Precomputed.Dp; x != nil {
+               dst.Precomputed.Dp = new(big.Int).Set(x)
+       }
+       if x := k.Precomputed.Dq; x != nil {
+               dst.Precomputed.Dq = new(big.Int).Set(x)
+       }
+       if x := k.Precomputed.Qinv; x != nil {
+               dst.Precomputed.Qinv = new(big.Int).Set(x)
+       }
+       return dst
+}
diff --git a/src/crypto/rsa/boring_test.go b/src/crypto/rsa/boring_test.go
new file mode 100644 (file)
index 0000000..11dcdf8
--- /dev/null
@@ -0,0 +1,125 @@
+// 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.
+
+// Note: Can run these tests against the non-BoringCrypto
+// version of the code by using "CGO_ENABLED=0 go test".
+
+package rsa
+
+import (
+       "crypto"
+       "crypto/rand"
+       "encoding/asn1"
+       "reflect"
+       "runtime"
+       "runtime/debug"
+       "sync"
+       "sync/atomic"
+       "testing"
+       "unsafe"
+)
+
+func TestBoringASN1Marshal(t *testing.T) {
+       k, err := GenerateKey(rand.Reader, 128)
+       if err != nil {
+               t.Fatal(err)
+       }
+       // This used to fail, because of the unexported 'boring' field.
+       // Now the compiler hides it [sic].
+       _, err = asn1.Marshal(k.PublicKey)
+       if err != nil {
+               t.Fatal(err)
+       }
+}
+
+func TestBoringDeepEqual(t *testing.T) {
+       k, err := GenerateKey(rand.Reader, 128)
+       if err != nil {
+               t.Fatal(err)
+       }
+       k.boring = nil // probably nil already but just in case
+       k2 := *k
+       k2.boring = unsafe.Pointer(k) // anything not nil, for this test
+       if !reflect.DeepEqual(k, &k2) {
+               // compiler should be hiding the boring field from reflection
+               t.Fatalf("DeepEqual compared boring fields")
+       }
+}
+
+func TestBoringVerify(t *testing.T) {
+       // Check that signatures that lack leading zeroes don't verify.
+       key := &PublicKey{
+               N: bigFromHex("c4fdf7b40a5477f206e6ee278eaef888ca73bf9128a9eef9f2f1ddb8b7b71a4c07cfa241f028a04edb405e4d916c61d6beabc333813dc7b484d2b3c52ee233c6a79b1eea4e9cc51596ba9cd5ac5aeb9df62d86ea051055b79d03f8a4fa9f38386f5bd17529138f3325d46801514ea9047977e0829ed728e68636802796801be1"),
+               E: 65537,
+       }
+
+       hash := fromHex("019c5571724fb5d0e47a4260c940e9803ba05a44")
+       paddedHash := fromHex("3021300906052b0e03021a05000414019c5571724fb5d0e47a4260c940e9803ba05a44")
+
+       // signature is one byte shorter than key.N.
+       sig := fromHex("5edfbeb6a73e7225ad3cc52724e2872e04260d7daf0d693c170d8c4b243b8767bc7785763533febc62ec2600c30603c433c095453ede59ff2fcabeb84ce32e0ed9d5cf15ffcbc816202b64370d4d77c1e9077d74e94a16fb4fa2e5bec23a56d7a73cf275f91691ae1801a976fcde09e981a2f6327ac27ea1fecf3185df0d56")
+
+       err := VerifyPKCS1v15(key, 0, paddedHash, sig)
+       if err == nil {
+               t.Errorf("raw: expected verification error")
+       }
+
+       err = VerifyPKCS1v15(key, crypto.SHA1, hash, sig)
+       if err == nil {
+               t.Errorf("sha1: expected verification error")
+       }
+}
+
+func TestBoringGenerateKey(t *testing.T) {
+       k, err := GenerateKey(rand.Reader, 2048) // 2048 is smallest size BoringCrypto might kick in for
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // Non-Boring GenerateKey always sets CRTValues to a non-nil (possibly empty) slice.
+       if k.Precomputed.CRTValues == nil {
+               t.Fatalf("GenerateKey: Precomputed.CRTValues = nil")
+       }
+}
+
+func TestBoringFinalizers(t *testing.T) {
+       if runtime.GOOS == "nacl" || runtime.GOOS == "js" {
+               // Times out on nacl and js/wasm (without BoringCrypto)
+               // but not clear why - probably consuming rand.Reader too quickly
+               // and being throttled. Also doesn't really matter.
+               t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+       }
+
+       k, err := GenerateKey(rand.Reader, 2048)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // Run test with GOGC=10, to make bug more likely.
+       // Without the KeepAlives, the loop usually dies after
+       // about 30 iterations.
+       defer debug.SetGCPercent(debug.SetGCPercent(10))
+       for n := 0; n < 200; n++ {
+               // Clear the underlying BoringCrypto object.
+               atomic.StorePointer(&k.boring, nil)
+
+               // Race to create the underlying BoringCrypto object.
+               // The ones that lose the race are prime candidates for
+               // being GC'ed too early if the finalizers are not being
+               // used correctly.
+               var wg sync.WaitGroup
+               for i := 0; i < 10; i++ {
+                       wg.Add(1)
+                       go func() {
+                               defer wg.Done()
+                               sum := make([]byte, 32)
+                               _, err := SignPKCS1v15(rand.Reader, k, crypto.SHA256, sum)
+                               if err != nil {
+                                       panic(err) // usually caused by memory corruption, so hard stop
+                               }
+                       }()
+               }
+               wg.Wait()
+       }
+}
index 0cbd6d004561c96fb9e641e0b92d637c49e43c90..213ddb4addbe4ff6860040e0ccb4d15f265183d9 100644 (file)
@@ -14,6 +14,8 @@ import (
        "crypto/internal/randutil"
 )
 
+import "crypto/internal/boring"
+
 // This file implements encryption and decryption using PKCS #1 v1.5 padding.
 
 // PKCS1v15DecrypterOpts is for passing options to PKCS #1 v1.5 decryption using
@@ -36,8 +38,8 @@ type PKCS1v15DecryptOptions struct {
 //
 // WARNING: use of this function to encrypt plaintexts other than
 // session keys is dangerous. Use RSA OAEP in new protocols.
-func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error) {
-       randutil.MaybeReadByte(rand)
+func EncryptPKCS1v15(random io.Reader, pub *PublicKey, msg []byte) ([]byte, error) {
+       randutil.MaybeReadByte(random)
 
        if err := checkPub(pub); err != nil {
                return nil, err
@@ -47,20 +49,37 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error)
                return nil, ErrMessageTooLong
        }
 
+       if boring.Enabled && random == boring.RandReader {
+               bkey, err := boringPublicKey(pub)
+               if err != nil {
+                       return nil, err
+               }
+               return boring.EncryptRSAPKCS1(bkey, msg)
+       }
+       boring.UnreachableExceptTests()
+
        // EM = 0x00 || 0x02 || PS || 0x00 || M
        em := make([]byte, k)
        em[1] = 2
        ps, mm := em[2:len(em)-len(msg)-1], em[len(em)-len(msg):]
-       err := nonZeroRandomBytes(ps, rand)
+       err := nonZeroRandomBytes(ps, random)
        if err != nil {
                return nil, err
        }
        em[len(em)-len(msg)-1] = 0
        copy(mm, msg)
 
+       if boring.Enabled {
+               var bkey *boring.PublicKeyRSA
+               bkey, err = boringPublicKey(pub)
+               if err != nil {
+                       return nil, err
+               }
+               return boring.EncryptRSANoPadding(bkey, em)
+       }
+
        m := new(big.Int).SetBytes(em)
        c := encrypt(new(big.Int), pub, m)
-
        return c.FillBytes(em), nil
 }
 
@@ -76,6 +95,19 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byt
        if err := checkPub(&priv.PublicKey); err != nil {
                return nil, err
        }
+
+       if boring.Enabled {
+               bkey, err := boringPrivateKey(priv)
+               if err != nil {
+                       return nil, err
+               }
+               out, err := boring.DecryptRSAPKCS1(bkey, ciphertext)
+               if err != nil {
+                       return nil, ErrDecryption
+               }
+               return out, nil
+       }
+
        valid, out, index, err := decryptPKCS1v15(rand, priv, ciphertext)
        if err != nil {
                return nil, err
@@ -143,13 +175,26 @@ func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid
                return
        }
 
-       c := new(big.Int).SetBytes(ciphertext)
-       m, err := decrypt(rand, priv, c)
-       if err != nil {
-               return
+       if boring.Enabled {
+               var bkey *boring.PrivateKeyRSA
+               bkey, err = boringPrivateKey(priv)
+               if err != nil {
+                       return
+               }
+               em, err = boring.DecryptRSANoPadding(bkey, ciphertext)
+               if err != nil {
+                       return
+               }
+       } else {
+               c := new(big.Int).SetBytes(ciphertext)
+               var m *big.Int
+               m, err = decrypt(rand, priv, c)
+               if err != nil {
+                       return
+               }
+               em = m.FillBytes(make([]byte, k))
        }
 
-       em = m.FillBytes(make([]byte, k))
        firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0)
        secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2)
 
@@ -228,7 +273,7 @@ var hashPrefixes = map[crypto.Hash][]byte{
 // messages is small, an attacker may be able to build a map from
 // messages to signatures and identify the signed messages. As ever,
 // signatures provide authenticity, not confidentiality.
-func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) {
+func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) {
        hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
        if err != nil {
                return nil, err
@@ -240,6 +285,14 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
                return nil, ErrMessageTooLong
        }
 
+       if boring.Enabled {
+               bkey, err := boringPrivateKey(priv)
+               if err != nil {
+                       return nil, err
+               }
+               return boring.SignRSAPKCS1v15(bkey, hash, hashed)
+       }
+
        // EM = 0x00 || 0x01 || PS || 0x00 || T
        em := make([]byte, k)
        em[1] = 1
@@ -250,7 +303,7 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
        copy(em[k-hashLen:k], hashed)
 
        m := new(big.Int).SetBytes(em)
-       c, err := decryptAndCheck(rand, priv, m)
+       c, err := decryptAndCheck(random, priv, m)
        if err != nil {
                return nil, err
        }
@@ -264,6 +317,17 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
 // returning a nil error. If hash is zero then hashed is used directly. This
 // isn't advisable except for interoperability.
 func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error {
+       if boring.Enabled {
+               bkey, err := boringPublicKey(pub)
+               if err != nil {
+                       return err
+               }
+               if err := boring.VerifyRSAPKCS1v15(bkey, hash, hashed, sig); err != nil {
+                       return ErrVerification
+               }
+               return nil
+       }
+
        hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
        if err != nil {
                return err
index 26b8c5f26fefd249ab2ac03eab1383e2436653ee..c5d825b42a0962db27e3ea570e16ef3d4c6ba2a6 100644 (file)
@@ -65,7 +65,7 @@ func TestDecryptPKCS1v15(t *testing.T) {
                for i, test := range decryptPKCS1v15Tests {
                        out, err := decryptFunc(decodeBase64(test.in))
                        if err != nil {
-                               t.Errorf("#%d error decrypting", i)
+                               t.Errorf("#%d error decrypting: %v", i, err)
                        }
                        want := []byte(test.out)
                        if !bytes.Equal(out, want) {
index 814522de8181fc326d29d925a7d6df8e53af7996..16ebc0e6a7fb251dd9227b486de9dd206a626cf3 100644 (file)
@@ -15,6 +15,8 @@ import (
        "math/big"
 )
 
+import "crypto/internal/boring"
+
 // Per RFC 8017, Section 9.1
 //
 //     EM = MGF1 xor DB || H( 8*0x00 || mHash || salt ) || 0xbc
@@ -213,6 +215,21 @@ func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed,
        if err != nil {
                return nil, err
        }
+
+       if boring.Enabled {
+               bkey, err := boringPrivateKey(priv)
+               if err != nil {
+                       return nil, err
+               }
+               // Note: BoringCrypto takes care of the "AndCheck" part of "decryptAndCheck".
+               // (It's not just decrypt.)
+               s, err := boring.DecryptRSANoPadding(bkey, em)
+               if err != nil {
+                       return nil, err
+               }
+               return s, nil
+       }
+
        m := new(big.Int).SetBytes(em)
        c, err := decryptAndCheck(rand, priv, m)
        if err != nil {
@@ -274,6 +291,14 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte,
                saltLength = hash.Size()
        }
 
+       if boring.Enabled && rand == boring.RandReader {
+               bkey, err := boringPrivateKey(priv)
+               if err != nil {
+                       return nil, err
+               }
+               return boring.SignRSAPSS(bkey, hash, digest, saltLength)
+       }
+
        salt := make([]byte, saltLength)
        if _, err := io.ReadFull(rand, salt); err != nil {
                return nil, err
@@ -288,6 +313,16 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte,
 // argument may be nil, in which case sensible defaults are used. opts.Hash is
 // ignored.
 func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts *PSSOptions) error {
+       if boring.Enabled {
+               bkey, err := boringPublicKey(pub)
+               if err != nil {
+                       return err
+               }
+               if err := boring.VerifyRSAPSS(bkey, hash, digest, sig, opts.saltLength()); err != nil {
+                       return ErrVerification
+               }
+               return nil
+       }
        if len(sig) != pub.Size() {
                return ErrVerification
        }
index c3a6d468497cd44ef38023e3d97a4b2e6dbc38d1..51f97601878e2cf3986986e44f6098dca1ad46ae 100644 (file)
@@ -9,7 +9,6 @@ import (
        "bytes"
        "compress/bzip2"
        "crypto"
-       _ "crypto/md5"
        "crypto/rand"
        "crypto/sha1"
        "crypto/sha256"
@@ -211,7 +210,7 @@ func TestPSSSigning(t *testing.T) {
                {8, 8, true},
        }
 
-       hash := crypto.MD5
+       hash := crypto.SHA1
        h := hash.New()
        h.Write([]byte("testing"))
        hashed := h.Sum(nil)
index 6fd59b39409ca979458b2777899e9fc612356787..eef967f826ea1d99fafc04ff78a330184944b8a0 100644 (file)
@@ -35,6 +35,11 @@ import (
        "crypto/internal/randutil"
 )
 
+import (
+       "crypto/internal/boring"
+       "unsafe"
+)
+
 var bigZero = big.NewInt(0)
 var bigOne = big.NewInt(1)
 
@@ -42,6 +47,8 @@ var bigOne = big.NewInt(1)
 type PublicKey struct {
        N *big.Int // modulus
        E int      // public exponent
+
+       boring unsafe.Pointer
 }
 
 // Any methods implemented on PublicKey might need to also be implemented on
@@ -105,6 +112,8 @@ type PrivateKey struct {
        // Precomputed contains precomputed values that speed up private
        // operations, if available.
        Precomputed PrecomputedValues
+
+       boring unsafe.Pointer
 }
 
 // Public returns the public key corresponding to priv.
@@ -256,6 +265,32 @@ func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) {
 func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey, error) {
        randutil.MaybeReadByte(random)
 
+       if boring.Enabled && random == boring.RandReader && nprimes == 2 && (bits == 2048 || bits == 3072) {
+               N, E, D, P, Q, Dp, Dq, Qinv, err := boring.GenerateKeyRSA(bits)
+               if err != nil {
+                       return nil, err
+               }
+               e64 := E.Int64()
+               if !E.IsInt64() || int64(int(e64)) != e64 {
+                       return nil, errors.New("crypto/rsa: generated key exponent too large")
+               }
+               key := &PrivateKey{
+                       PublicKey: PublicKey{
+                               N: N,
+                               E: int(e64),
+                       },
+                       D:      D,
+                       Primes: []*big.Int{P, Q},
+                       Precomputed: PrecomputedValues{
+                               Dp:        Dp,
+                               Dq:        Dq,
+                               Qinv:      Qinv,
+                               CRTValues: make([]CRTValue, 0), // non-nil, to match Precompute
+                       },
+               }
+               return key, nil
+       }
+
        priv := new(PrivateKey)
        priv.E = 65537
 
@@ -385,6 +420,7 @@ func mgf1XOR(out []byte, hash hash.Hash, seed []byte) {
 var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA public key size")
 
 func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
+       boring.Unreachable()
        e := big.NewInt(int64(pub.E))
        c.Exp(m, e, pub.N)
        return c
@@ -417,6 +453,15 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l
                return nil, ErrMessageTooLong
        }
 
+       if boring.Enabled && random == boring.RandReader {
+               bkey, err := boringPublicKey(pub)
+               if err != nil {
+                       return nil, err
+               }
+               return boring.EncryptRSAOAEP(hash, bkey, msg, label)
+       }
+       boring.UnreachableExceptTests()
+
        hash.Write(label)
        lHash := hash.Sum(nil)
        hash.Reset()
@@ -437,6 +482,15 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l
        mgf1XOR(db, hash, seed)
        mgf1XOR(seed, hash, db)
 
+       if boring.Enabled {
+               var bkey *boring.PublicKeyRSA
+               bkey, err = boringPublicKey(pub)
+               if err != nil {
+                       return nil, err
+               }
+               return boring.EncryptRSANoPadding(bkey, em)
+       }
+
        m := new(big.Int)
        m.SetBytes(em)
        c := encrypt(new(big.Int), pub, m)
@@ -487,6 +541,9 @@ func (priv *PrivateKey) Precompute() {
 // decrypt performs an RSA decryption, resulting in a plaintext integer. If a
 // random source is given, RSA blinding is used.
 func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err error) {
+       if len(priv.Primes) <= 2 {
+               boring.Unreachable()
+       }
        // TODO(agl): can we get away with reusing blinds?
        if c.Cmp(priv.N) > 0 {
                err = ErrDecryption
@@ -603,6 +660,17 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext
                return nil, ErrDecryption
        }
 
+       if boring.Enabled {
+               bkey, err := boringPrivateKey(priv)
+               if err != nil {
+                       return nil, err
+               }
+               out, err := boring.DecryptRSAOAEP(hash, bkey, ciphertext, label)
+               if err != nil {
+                       return nil, ErrDecryption
+               }
+               return out, nil
+       }
        c := new(big.Int).SetBytes(ciphertext)
 
        m, err := decrypt(random, priv, c)
index 84b167455f02f64ddc5ad5efa7df0b5d65954661..766d9a954f8d13f721f786372016990ade2d2a5a 100644 (file)
@@ -10,23 +10,27 @@ import (
        "crypto/rand"
        "crypto/sha1"
        "crypto/sha256"
+       "fmt"
        "math/big"
        "testing"
 )
 
+import "crypto/internal/boring"
+
 func TestKeyGeneration(t *testing.T) {
-       size := 1024
-       if testing.Short() {
-               size = 128
-       }
-       priv, err := GenerateKey(rand.Reader, size)
-       if err != nil {
-               t.Errorf("failed to generate key")
-       }
-       if bits := priv.N.BitLen(); bits != size {
-               t.Errorf("key too short (%d vs %d)", bits, size)
+       for _, size := range []int{128, 1024, 2048, 3072} {
+               priv, err := GenerateKey(rand.Reader, size)
+               if err != nil {
+                       t.Errorf("GenerateKey(%d): %v", size, err)
+               }
+               if bits := priv.N.BitLen(); bits != size {
+                       t.Errorf("key too short (%d vs %d)", bits, size)
+               }
+               testKeyBasics(t, priv)
+               if testing.Short() {
+                       break
+               }
        }
-       testKeyBasics(t, priv)
 }
 
 func Test3PrimeKeyGeneration(t *testing.T) {
@@ -110,6 +114,25 @@ func testKeyBasics(t *testing.T, priv *PrivateKey) {
                t.Errorf("private exponent too large")
        }
 
+       if boring.Enabled {
+               // Cannot call encrypt/decrypt directly. Test via PKCS1v15.
+               msg := []byte("hi!")
+               enc, err := EncryptPKCS1v15(rand.Reader, &priv.PublicKey, msg)
+               if err != nil {
+                       t.Errorf("EncryptPKCS1v15: %v", err)
+                       return
+               }
+               dec, err := DecryptPKCS1v15(rand.Reader, priv, enc)
+               if err != nil {
+                       t.Errorf("DecryptPKCS1v15: %v", err)
+                       return
+               }
+               if !bytes.Equal(dec, msg) {
+                       t.Errorf("got:%x want:%x (%+v)", dec, msg, priv)
+               }
+               return
+       }
+
        pub := &priv.PublicKey
        m := big.NewInt(42)
        c := encrypt(new(big.Int), pub, m)
@@ -158,6 +181,10 @@ func init() {
 }
 
 func BenchmarkRSA2048Decrypt(b *testing.B) {
+       if boring.Enabled {
+               b.Skip("no raw decrypt in BoringCrypto")
+       }
+
        b.StopTimer()
 
        c := fromBase10("8472002792838218989464636159316973636630013835787202418124758118372358261975764365740026024610403138425986214991379012696600761514742817632790916315594342398720903716529235119816755589383377471752116975374952783629225022962092351886861518911824745188989071172097120352727368980275252089141512321893536744324822590480751098257559766328893767334861211872318961900897793874075248286439689249972315699410830094164386544311554704755110361048571142336148077772023880664786019636334369759624917224888206329520528064315309519262325023881707530002540634660750469137117568199824615333883758410040459705787022909848740188613313")
@@ -180,6 +207,10 @@ func BenchmarkRSA2048Sign(b *testing.B) {
 }
 
 func Benchmark3PrimeRSA2048Decrypt(b *testing.B) {
+       if boring.Enabled {
+               b.Skip("no raw decrypt in BoringCrypto")
+       }
+
        b.StopTimer()
        priv := &PrivateKey{
                PublicKey: PublicKey{
@@ -222,7 +253,7 @@ func TestEncryptOAEP(t *testing.T) {
        n := new(big.Int)
        for i, test := range testEncryptOAEPData {
                n.SetString(test.modulus, 16)
-               public := PublicKey{n, test.e}
+               public := PublicKey{N: n, E: test.e}
 
                for j, message := range test.msgs {
                        randomSource := bytes.NewReader(message.seed)
@@ -247,7 +278,7 @@ func TestDecryptOAEP(t *testing.T) {
                n.SetString(test.modulus, 16)
                d.SetString(test.d, 16)
                private := new(PrivateKey)
-               private.PublicKey = PublicKey{n, test.e}
+               private.PublicKey = PublicKey{N: n, E: test.e}
                private.D = d
 
                for j, message := range test.msgs {
@@ -272,6 +303,36 @@ func TestDecryptOAEP(t *testing.T) {
        }
 }
 
+func TestEncryptDecryptOAEP(t *testing.T) {
+       sha256 := sha256.New()
+       n := new(big.Int)
+       d := new(big.Int)
+       for i, test := range testEncryptOAEPData {
+               n.SetString(test.modulus, 16)
+               d.SetString(test.d, 16)
+               priv := new(PrivateKey)
+               priv.PublicKey = PublicKey{N: n, E: test.e}
+               priv.D = d
+
+               for j, message := range test.msgs {
+                       label := []byte(fmt.Sprintf("hi#%d", j))
+                       enc, err := EncryptOAEP(sha256, rand.Reader, &priv.PublicKey, message.in, label)
+                       if err != nil {
+                               t.Errorf("#%d,%d: EncryptOAEP: %v", i, j, err)
+                               continue
+                       }
+                       dec, err := DecryptOAEP(sha256, rand.Reader, priv, enc, label)
+                       if err != nil {
+                               t.Errorf("#%d,%d: DecryptOAEP: %v", i, j, err)
+                               continue
+                       }
+                       if !bytes.Equal(dec, message.in) {
+                               t.Errorf("#%d,%d: round trip %q -> %q", i, j, message.in, dec)
+                       }
+               }
+       }
+}
+
 // testEncryptOAEPData contains a subset of the vectors from RSA's "Test vectors for RSA-OAEP".
 var testEncryptOAEPData = []testEncryptOAEPStruct{
        // Key 1
diff --git a/src/crypto/sha1/boring.go b/src/crypto/sha1/boring.go
new file mode 100644 (file)
index 0000000..44c2609
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2009 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.
+
+// Extra indirection here so that when building go_bootstrap
+// cmd/internal/boring is not even imported, so that we don't
+// have to maintain changes to cmd/dist's deps graph.
+
+// +build !cmd_go_bootstrap
+
+package sha1
+
+import (
+       "crypto/internal/boring"
+       "hash"
+)
+
+const boringEnabled = boring.Enabled
+
+func boringNewSHA1() hash.Hash { return boring.NewSHA1() }
+
+func boringUnreachable() { boring.Unreachable() }
diff --git a/src/crypto/sha1/notboring.go b/src/crypto/sha1/notboring.go
new file mode 100644 (file)
index 0000000..9726fcd
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2009 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.
+
+// +build cmd_go_bootstrap
+
+package sha1
+
+import (
+       "hash"
+)
+
+const boringEnabled = false
+
+func boringNewSHA1() hash.Hash { panic("boringcrypto: not available") }
+
+func boringUnreachable() {}
index 286a59d33d662bfa6fc955dea711f0a3d5eba6a8..329435f282f428c4771ec458e2f1d0e93c1c8ee7 100644 (file)
@@ -119,6 +119,9 @@ func (d *digest) Reset() {
 // implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to
 // marshal and unmarshal the internal state of the hash.
 func New() hash.Hash {
+       if boringEnabled {
+               return boringNewSHA1()
+       }
        d := new(digest)
        d.Reset()
        return d
@@ -129,6 +132,7 @@ func (d *digest) Size() int { return Size }
 func (d *digest) BlockSize() int { return BlockSize }
 
 func (d *digest) Write(p []byte) (nn int, err error) {
+       boringUnreachable()
        nn = len(p)
        d.len += uint64(nn)
        if d.nx > 0 {
@@ -152,6 +156,7 @@ func (d *digest) Write(p []byte) (nn int, err error) {
 }
 
 func (d *digest) Sum(in []byte) []byte {
+       boringUnreachable()
        // Make a copy of d so that caller can keep writing and summing.
        d0 := *d
        hash := d0.checkSum()
@@ -259,6 +264,13 @@ func (d *digest) constSum() [Size]byte {
 
 // Sum returns the SHA-1 checksum of the data.
 func Sum(data []byte) [Size]byte {
+       if boringEnabled {
+               h := New()
+               h.Write(data)
+               var ret [Size]byte
+               h.Sum(ret[:0])
+               return ret
+       }
        var d digest
        d.Reset()
        d.Write(data)
index c3e6010af121928d28227bb4d1095c5437fa14e4..e369c3b7f491eee1e7cc2f30d1b6aa616b202fa9 100644 (file)
@@ -16,6 +16,8 @@ import (
        "testing"
 )
 
+import "crypto/internal/boring"
+
 type sha1Test struct {
        out       string
        in        string
@@ -77,6 +79,9 @@ func TestGolden(t *testing.T) {
                                io.WriteString(c, g.in[len(g.in)/2:])
                                sum = c.Sum(nil)
                        case 3:
+                               if boring.Enabled {
+                                       continue
+                               }
                                io.WriteString(c, g.in[0:len(g.in)/2])
                                c.(*digest).ConstantTimeSum(nil)
                                io.WriteString(c, g.in[len(g.in)/2:])
@@ -141,6 +146,9 @@ func TestBlockSize(t *testing.T) {
 
 // Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match.
 func TestBlockGeneric(t *testing.T) {
+       if boring.Enabled {
+               t.Skip("BoringCrypto doesn't expose digest")
+       }
        for i := 1; i < 30; i++ { // arbitrary factor
                gen, asm := New().(*digest), New().(*digest)
                buf := make([]byte, BlockSize*i)
index e1cccf65a60307517d7adecf7dcefdbd47d88aa5..8b54a427d7d4c8c25cd650fe2703a8cbae0c4306 100644 (file)
@@ -13,6 +13,8 @@ import (
        "hash"
 )
 
+import "crypto/internal/boring"
+
 func init() {
        crypto.RegisterHash(crypto.SHA224, New224)
        crypto.RegisterHash(crypto.SHA256, New)
@@ -159,6 +161,9 @@ func (d *digest) Reset() {
 // encoding.BinaryUnmarshaler to marshal and unmarshal the internal
 // state of the hash.
 func New() hash.Hash {
+       if boring.Enabled {
+               return boring.NewSHA256()
+       }
        d := new(digest)
        d.Reset()
        return d
@@ -166,6 +171,9 @@ func New() hash.Hash {
 
 // New224 returns a new hash.Hash computing the SHA224 checksum.
 func New224() hash.Hash {
+       if boring.Enabled {
+               return boring.NewSHA224()
+       }
        d := new(digest)
        d.is224 = true
        d.Reset()
@@ -182,6 +190,7 @@ func (d *digest) Size() int {
 func (d *digest) BlockSize() int { return BlockSize }
 
 func (d *digest) Write(p []byte) (nn int, err error) {
+       boring.Unreachable()
        nn = len(p)
        d.len += uint64(nn)
        if d.nx > 0 {
@@ -205,6 +214,7 @@ func (d *digest) Write(p []byte) (nn int, err error) {
 }
 
 func (d *digest) Sum(in []byte) []byte {
+       boring.Unreachable()
        // Make a copy of d so that caller can keep writing and summing.
        d0 := *d
        hash := d0.checkSum()
@@ -252,6 +262,13 @@ func (d *digest) checkSum() [Size]byte {
 
 // Sum256 returns the SHA256 checksum of the data.
 func Sum256(data []byte) [Size]byte {
+       if boring.Enabled {
+               h := New()
+               h.Write(data)
+               var ret [Size]byte
+               h.Sum(ret[:0])
+               return ret
+       }
        var d digest
        d.Reset()
        d.Write(data)
@@ -260,6 +277,13 @@ func Sum256(data []byte) [Size]byte {
 
 // Sum224 returns the SHA224 checksum of the data.
 func Sum224(data []byte) (sum224 [Size224]byte) {
+       if boring.Enabled {
+               h := New224()
+               h.Write(data)
+               var ret [Size224]byte
+               h.Sum(ret[:0])
+               return ret
+       }
        var d digest
        d.is224 = true
        d.Reset()
index a2794b015dbc44375cb502afc08fe53d38111b8a..91a4edde047f68bb85ea9f635f746e45bb454ff7 100644 (file)
@@ -16,6 +16,8 @@ import (
        "testing"
 )
 
+import "crypto/internal/boring"
+
 type sha256Test struct {
        out       string
        in        string
@@ -216,6 +218,9 @@ func TestBlockSize(t *testing.T) {
 
 // Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match.
 func TestBlockGeneric(t *testing.T) {
+       if boring.Enabled {
+               t.Skip("BoringCrypto doesn't expose digest")
+       }
        gen, asm := New().(*digest), New().(*digest)
        buf := make([]byte, BlockSize*20) // arbitrary factor
        rand.Read(buf)
index 9c143a2a2817786095b94b2775db18210ff3a7be..1a2cef317c34023325ac805c2365606f1e551fb6 100644 (file)
@@ -17,6 +17,8 @@ import (
        "hash"
 )
 
+import "crypto/internal/boring"
+
 func init() {
        crypto.RegisterHash(crypto.SHA384, New384)
        crypto.RegisterHash(crypto.SHA512, New)
@@ -211,6 +213,9 @@ func consumeUint64(b []byte) ([]byte, uint64) {
 
 // New returns a new hash.Hash computing the SHA-512 checksum.
 func New() hash.Hash {
+       if boring.Enabled {
+               return boring.NewSHA512()
+       }
        d := &digest{function: crypto.SHA512}
        d.Reset()
        return d
@@ -232,6 +237,9 @@ func New512_256() hash.Hash {
 
 // New384 returns a new hash.Hash computing the SHA-384 checksum.
 func New384() hash.Hash {
+       if boring.Enabled {
+               return boring.NewSHA384()
+       }
        d := &digest{function: crypto.SHA384}
        d.Reset()
        return d
@@ -253,6 +261,9 @@ func (d *digest) Size() int {
 func (d *digest) BlockSize() int { return BlockSize }
 
 func (d *digest) Write(p []byte) (nn int, err error) {
+       if d.function != crypto.SHA512_224 && d.function != crypto.SHA512_256 {
+               boring.Unreachable()
+       }
        nn = len(p)
        d.len += uint64(nn)
        if d.nx > 0 {
@@ -276,6 +287,9 @@ func (d *digest) Write(p []byte) (nn int, err error) {
 }
 
 func (d *digest) Sum(in []byte) []byte {
+       if d.function != crypto.SHA512_224 && d.function != crypto.SHA512_256 {
+               boring.Unreachable()
+       }
        // Make a copy of d so that caller can keep writing and summing.
        d0 := new(digest)
        *d0 = *d
@@ -330,6 +344,13 @@ func (d *digest) checkSum() [Size]byte {
 
 // Sum512 returns the SHA512 checksum of the data.
 func Sum512(data []byte) [Size]byte {
+       if boring.Enabled {
+               h := New()
+               h.Write(data)
+               var ret [Size]byte
+               h.Sum(ret[:0])
+               return ret
+       }
        d := digest{function: crypto.SHA512}
        d.Reset()
        d.Write(data)
@@ -338,6 +359,13 @@ func Sum512(data []byte) [Size]byte {
 
 // Sum384 returns the SHA384 checksum of the data.
 func Sum384(data []byte) (sum384 [Size384]byte) {
+       if boring.Enabled {
+               h := New384()
+               h.Write(data)
+               var ret [Size384]byte
+               h.Sum(ret[:0])
+               return ret
+       }
        d := digest{function: crypto.SHA384}
        d.Reset()
        d.Write(data)
index 0e1528fc69f6018162473f9223557a7cfbee9d3a..966cd51d157ae31d3932a670f92586848e7fdc5e 100644 (file)
@@ -17,6 +17,8 @@ import (
        "testing"
 )
 
+import "crypto/internal/boring"
+
 type sha512Test struct {
        out       string
        in        string
@@ -822,6 +824,9 @@ func TestBlockSize(t *testing.T) {
 
 // Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match.
 func TestBlockGeneric(t *testing.T) {
+       if boring.Enabled {
+               t.Skip("BoringCrypto doesn't expose digest")
+       }
        gen, asm := New().(*digest), New().(*digest)
        buf := make([]byte, BlockSize*20) // arbitrary factor
        rand.Read(buf)
index a9df0da6d624b1b39b3b0813a93573e0319e1ac1..7c5675c6d933bb88dc53153f2b94bdf2920b824d 100644 (file)
@@ -169,6 +169,7 @@ var rsaSignatureSchemes = []struct {
 // and optionally filtered by its explicit SupportedSignatureAlgorithms.
 //
 // This function must be kept in sync with supportedSignatureAlgorithms.
+// FIPS filtering is applied in the caller, selectSignatureScheme.
 func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme {
        priv, ok := cert.PrivateKey.(crypto.Signer)
        if !ok {
@@ -241,6 +242,9 @@ func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureSche
        // Pick signature scheme in the peer's preference order, as our
        // preference order is not configurable.
        for _, preferredAlg := range peerAlgs {
+               if needFIPS() && !isSupportedSignatureAlgorithm(preferredAlg, fipsSupportedSignatureAlgorithms) {
+                       continue
+               }
                if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
                        return preferredAlg, nil
                }
index c42e3491e46f16873c2195397bbdd56e9536b2a5..c23d93f3c0855d83c38579d15594c051deb75535 100644 (file)
@@ -153,7 +153,7 @@ func TestLegacyTypeAndHash(t *testing.T) {
 // TestSupportedSignatureAlgorithms checks that all supportedSignatureAlgorithms
 // have valid type and hash information.
 func TestSupportedSignatureAlgorithms(t *testing.T) {
-       for _, sigAlg := range supportedSignatureAlgorithms {
+       for _, sigAlg := range supportedSignatureAlgorithms() {
                sigType, hash, err := typeAndHashFromSignatureScheme(sigAlg)
                if err != nil {
                        t.Errorf("%v: unexpected error: %v", sigAlg, err)
diff --git a/src/crypto/tls/boring.go b/src/crypto/tls/boring.go
new file mode 100644 (file)
index 0000000..09f71c1
--- /dev/null
@@ -0,0 +1,127 @@
+// 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.
+
+package tls
+
+import (
+       "crypto/ecdsa"
+       "crypto/internal/boring/fipstls"
+       "crypto/rsa"
+       "crypto/x509"
+)
+
+// needFIPS returns fipstls.Required(); it avoids a new import in common.go.
+func needFIPS() bool {
+       return fipstls.Required()
+}
+
+// fipsMinVersion replaces c.minVersion in FIPS-only mode.
+func fipsMinVersion(c *Config) uint16 {
+       // FIPS requires TLS 1.2.
+       return VersionTLS12
+}
+
+// fipsMaxVersion replaces c.maxVersion in FIPS-only mode.
+func fipsMaxVersion(c *Config) uint16 {
+       // FIPS requires TLS 1.2.
+       return VersionTLS12
+}
+
+// default defaultFIPSCurvePreferences is the FIPS-allowed curves,
+// in preference order (most preferable first).
+var defaultFIPSCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521}
+
+// fipsCurvePreferences replaces c.curvePreferences in FIPS-only mode.
+func fipsCurvePreferences(c *Config) []CurveID {
+       if c == nil || len(c.CurvePreferences) == 0 {
+               return defaultFIPSCurvePreferences
+       }
+       var list []CurveID
+       for _, id := range c.CurvePreferences {
+               for _, allowed := range defaultFIPSCurvePreferences {
+                       if id == allowed {
+                               list = append(list, id)
+                               break
+                       }
+               }
+       }
+       return list
+}
+
+// defaultCipherSuitesFIPS are the FIPS-allowed cipher suites.
+var defaultCipherSuitesFIPS = []uint16{
+       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+       TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+       TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+       TLS_RSA_WITH_AES_128_GCM_SHA256,
+       TLS_RSA_WITH_AES_256_GCM_SHA384,
+}
+
+// fipsCipherSuites replaces c.cipherSuites in FIPS-only mode.
+func fipsCipherSuites(c *Config) []uint16 {
+       if c == nil || c.CipherSuites == nil {
+               return defaultCipherSuitesFIPS
+       }
+       list := make([]uint16, 0, len(defaultCipherSuitesFIPS))
+       for _, id := range c.CipherSuites {
+               for _, allowed := range defaultCipherSuitesFIPS {
+                       if id == allowed {
+                               list = append(list, id)
+                               break
+                       }
+               }
+       }
+       return list
+}
+
+// isBoringCertificate reports whether a certificate may be used
+// when constructing a verified chain.
+// It is called for each leaf, intermediate, and root certificate.
+func isBoringCertificate(c *x509.Certificate) bool {
+       if !needFIPS() {
+               // Everything is OK if we haven't forced FIPS-only mode.
+               return true
+       }
+
+       // Otherwise the key must be RSA 2048, RSA 3072, or ECDSA P-256.
+       switch k := c.PublicKey.(type) {
+       default:
+               return false
+       case *rsa.PublicKey:
+               if size := k.N.BitLen(); size != 2048 && size != 3072 {
+                       return false
+               }
+       case *ecdsa.PublicKey:
+               if name := k.Curve.Params().Name; name != "P-256" && name != "P-384" {
+                       return false
+               }
+       }
+
+       return true
+}
+
+// fipsSupportedSignatureAlgorithms currently are a subset of
+// defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1.
+var fipsSupportedSignatureAlgorithms = []SignatureScheme{
+       PSSWithSHA256,
+       PSSWithSHA384,
+       PSSWithSHA512,
+       PKCS1WithSHA256,
+       ECDSAWithP256AndSHA256,
+       PKCS1WithSHA384,
+       ECDSAWithP384AndSHA384,
+       PKCS1WithSHA512,
+       ECDSAWithP521AndSHA512,
+}
+
+// supportedSignatureAlgorithms returns the supported signature algorithms.
+func supportedSignatureAlgorithms() []SignatureScheme {
+       if !needFIPS() {
+               return defaultSupportedSignatureAlgorithms
+       }
+       return fipsSupportedSignatureAlgorithms
+}
+
+var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme
diff --git a/src/crypto/tls/boring_test.go b/src/crypto/tls/boring_test.go
new file mode 100644 (file)
index 0000000..6ad72fa
--- /dev/null
@@ -0,0 +1,630 @@
+// 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.
+
+package tls
+
+import (
+       "crypto/ecdsa"
+       "crypto/elliptic"
+       "crypto/internal/boring/fipstls"
+       "crypto/rand"
+       "crypto/rsa"
+       "crypto/x509"
+       "crypto/x509/pkix"
+       "encoding/pem"
+       "fmt"
+       "math/big"
+       "net"
+       "runtime"
+       "strings"
+       "testing"
+       "time"
+)
+
+func TestBoringServerProtocolVersion(t *testing.T) {
+       test := func(name string, v uint16, msg string) {
+               t.Run(name, func(t *testing.T) {
+                       serverConfig := testConfig.Clone()
+                       serverConfig.MinVersion = VersionSSL30
+                       clientHello := &clientHelloMsg{
+                               vers:               v,
+                               random:             make([]byte, 32),
+                               cipherSuites:       allCipherSuites(),
+                               compressionMethods: []uint8{compressionNone},
+                               supportedVersions:  []uint16{v},
+                       }
+                       testClientHelloFailure(t, serverConfig, clientHello, msg)
+               })
+       }
+
+       test("VersionTLS10", VersionTLS10, "")
+       test("VersionTLS11", VersionTLS11, "")
+       test("VersionTLS12", VersionTLS12, "")
+       test("VersionTLS13", VersionTLS13, "")
+
+       fipstls.Force()
+       defer fipstls.Abandon()
+       test("VersionSSL30", VersionSSL30, "client offered only unsupported versions")
+       test("VersionTLS10", VersionTLS10, "client offered only unsupported versions")
+       test("VersionTLS11", VersionTLS11, "client offered only unsupported versions")
+       test("VersionTLS12", VersionTLS12, "")
+       test("VersionTLS13", VersionTLS13, "client offered only unsupported versions")
+}
+
+func isBoringVersion(v uint16) bool {
+       return v == VersionTLS12
+}
+
+func isBoringCipherSuite(id uint16) bool {
+       switch id {
+       case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+               TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+               TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+               TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+               TLS_RSA_WITH_AES_128_GCM_SHA256,
+               TLS_RSA_WITH_AES_256_GCM_SHA384:
+               return true
+       }
+       return false
+}
+
+func isBoringCurve(id CurveID) bool {
+       switch id {
+       case CurveP256, CurveP384, CurveP521:
+               return true
+       }
+       return false
+}
+
+func isECDSA(id uint16) bool {
+       for _, suite := range cipherSuites {
+               if suite.id == id {
+                       return suite.flags&suiteECSign == suiteECSign
+               }
+       }
+       panic(fmt.Sprintf("unknown cipher suite %#x", id))
+}
+
+func isBoringSignatureScheme(alg SignatureScheme) bool {
+       switch alg {
+       default:
+               return false
+       case PKCS1WithSHA256,
+               ECDSAWithP256AndSHA256,
+               PKCS1WithSHA384,
+               ECDSAWithP384AndSHA384,
+               PKCS1WithSHA512,
+               ECDSAWithP521AndSHA512,
+               PSSWithSHA256,
+               PSSWithSHA384,
+               PSSWithSHA512:
+               // ok
+       }
+       return true
+}
+
+func TestBoringServerCipherSuites(t *testing.T) {
+       serverConfig := testConfig.Clone()
+       serverConfig.CipherSuites = allCipherSuites()
+       serverConfig.Certificates = make([]Certificate, 1)
+
+       for _, id := range allCipherSuites() {
+               if isECDSA(id) {
+                       serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+                       serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+               } else {
+                       serverConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
+                       serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey
+               }
+               serverConfig.BuildNameToCertificate()
+               t.Run(fmt.Sprintf("suite=%#x", id), func(t *testing.T) {
+                       clientHello := &clientHelloMsg{
+                               vers:               VersionTLS12,
+                               random:             make([]byte, 32),
+                               cipherSuites:       []uint16{id},
+                               compressionMethods: []uint8{compressionNone},
+                               supportedCurves:    defaultCurvePreferences,
+                               supportedPoints:    []uint8{pointFormatUncompressed},
+                       }
+
+                       testClientHello(t, serverConfig, clientHello)
+                       t.Run("fipstls", func(t *testing.T) {
+                               fipstls.Force()
+                               defer fipstls.Abandon()
+                               msg := ""
+                               if !isBoringCipherSuite(id) {
+                                       msg = "no cipher suite supported by both client and server"
+                               }
+                               testClientHelloFailure(t, serverConfig, clientHello, msg)
+                       })
+               })
+       }
+}
+
+func TestBoringServerCurves(t *testing.T) {
+       serverConfig := testConfig.Clone()
+       serverConfig.Certificates = make([]Certificate, 1)
+       serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+       serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+       serverConfig.BuildNameToCertificate()
+
+       for _, curveid := range defaultCurvePreferences {
+               t.Run(fmt.Sprintf("curve=%d", curveid), func(t *testing.T) {
+                       clientHello := &clientHelloMsg{
+                               vers:               VersionTLS12,
+                               random:             make([]byte, 32),
+                               cipherSuites:       []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+                               compressionMethods: []uint8{compressionNone},
+                               supportedCurves:    []CurveID{curveid},
+                               supportedPoints:    []uint8{pointFormatUncompressed},
+                       }
+
+                       testClientHello(t, serverConfig, clientHello)
+
+                       // With fipstls forced, bad curves should be rejected.
+                       t.Run("fipstls", func(t *testing.T) {
+                               fipstls.Force()
+                               defer fipstls.Abandon()
+                               msg := ""
+                               if !isBoringCurve(curveid) {
+                                       msg = "no cipher suite supported by both client and server"
+                               }
+                               testClientHelloFailure(t, serverConfig, clientHello, msg)
+                       })
+               })
+       }
+}
+
+func boringHandshake(t *testing.T, clientConfig, serverConfig *Config) (clientErr, serverErr error) {
+       c, s := localPipe(t)
+       client := Client(c, clientConfig)
+       server := Server(s, serverConfig)
+       done := make(chan error, 1)
+       go func() {
+               done <- client.Handshake()
+               c.Close()
+       }()
+       serverErr = server.Handshake()
+       s.Close()
+       clientErr = <-done
+       return
+}
+
+func TestBoringServerSignatureAndHash(t *testing.T) {
+       defer func() {
+               testingOnlyForceClientHelloSignatureAlgorithms = nil
+       }()
+
+       for _, sigHash := range defaultSupportedSignatureAlgorithms {
+               t.Run(fmt.Sprintf("%#x", sigHash), func(t *testing.T) {
+                       serverConfig := testConfig.Clone()
+                       serverConfig.Certificates = make([]Certificate, 1)
+
+                       testingOnlyForceClientHelloSignatureAlgorithms = []SignatureScheme{sigHash}
+
+                       sigType, _, _ := typeAndHashFromSignatureScheme(sigHash)
+                       switch sigType {
+                       case signaturePKCS1v15, signatureRSAPSS:
+                               serverConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
+                               serverConfig.Certificates[0].Certificate = [][]byte{testRSA2048Certificate}
+                               serverConfig.Certificates[0].PrivateKey = testRSA2048PrivateKey
+                       case signatureEd25519:
+                               serverConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
+                               serverConfig.Certificates[0].Certificate = [][]byte{testEd25519Certificate}
+                               serverConfig.Certificates[0].PrivateKey = testEd25519PrivateKey
+                       case signatureECDSA:
+                               serverConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
+                               serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+                               serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+                       }
+                       serverConfig.BuildNameToCertificate()
+                       // PKCS#1 v1.5 signature algorithms can't be used standalone in TLS
+                       // 1.3, and the ECDSA ones bind to the curve used.
+                       serverConfig.MaxVersion = VersionTLS12
+
+                       clientErr, serverErr := boringHandshake(t, testConfig, serverConfig)
+                       if clientErr != nil {
+                               t.Fatalf("expected handshake with %#x to succeed; client error: %v; server error: %v", sigHash, clientErr, serverErr)
+                       }
+
+                       // With fipstls forced, bad curves should be rejected.
+                       t.Run("fipstls", func(t *testing.T) {
+                               fipstls.Force()
+                               defer fipstls.Abandon()
+                               clientErr, _ := boringHandshake(t, testConfig, serverConfig)
+                               if isBoringSignatureScheme(sigHash) {
+                                       if clientErr != nil {
+                                               t.Fatalf("expected handshake with %#x to succeed; err=%v", sigHash, clientErr)
+                                       }
+                               } else {
+                                       if clientErr == nil {
+                                               t.Fatalf("expected handshake with %#x to fail, but it succeeded", sigHash)
+                                       }
+                               }
+                       })
+               })
+       }
+}
+
+func TestBoringClientHello(t *testing.T) {
+       // Test that no matter what we put in the client config,
+       // the client does not offer non-FIPS configurations.
+       fipstls.Force()
+       defer fipstls.Abandon()
+
+       c, s := net.Pipe()
+       defer c.Close()
+       defer s.Close()
+
+       clientConfig := testConfig.Clone()
+       // All sorts of traps for the client to avoid.
+       clientConfig.MinVersion = VersionSSL30
+       clientConfig.MaxVersion = VersionTLS13
+       clientConfig.CipherSuites = allCipherSuites()
+       clientConfig.CurvePreferences = defaultCurvePreferences
+
+       go Client(c, testConfig).Handshake()
+       srv := Server(s, testConfig)
+       msg, err := srv.readHandshake()
+       if err != nil {
+               t.Fatal(err)
+       }
+       hello, ok := msg.(*clientHelloMsg)
+       if !ok {
+               t.Fatalf("unexpected message type %T", msg)
+       }
+
+       if !isBoringVersion(hello.vers) {
+               t.Errorf("client vers=%#x, want %#x (TLS 1.2)", hello.vers, VersionTLS12)
+       }
+       for _, v := range hello.supportedVersions {
+               if !isBoringVersion(v) {
+                       t.Errorf("client offered disallowed version %#x", v)
+               }
+       }
+       for _, id := range hello.cipherSuites {
+               if !isBoringCipherSuite(id) {
+                       t.Errorf("client offered disallowed suite %#x", id)
+               }
+       }
+       for _, id := range hello.supportedCurves {
+               if !isBoringCurve(id) {
+                       t.Errorf("client offered disallowed curve %d", id)
+               }
+       }
+       for _, sigHash := range hello.supportedSignatureAlgorithms {
+               if !isBoringSignatureScheme(sigHash) {
+                       t.Errorf("client offered disallowed signature-and-hash %v", sigHash)
+               }
+       }
+}
+
+func TestBoringCertAlgs(t *testing.T) {
+       // NaCl, arm and wasm time out generating keys. Nothing in this test is architecture-specific, so just don't bother on those.
+       if runtime.GOOS == "nacl" || runtime.GOARCH == "arm" || runtime.GOOS == "js" {
+               t.Skipf("skipping on %s/%s because key generation takes too long", runtime.GOOS, runtime.GOARCH)
+       }
+
+       // Set up some roots, intermediate CAs, and leaf certs with various algorithms.
+       // X_Y is X signed by Y.
+       R1 := boringCert(t, "R1", boringRSAKey(t, 2048), nil, boringCertCA|boringCertFIPSOK)
+       R2 := boringCert(t, "R2", boringRSAKey(t, 4096), nil, boringCertCA)
+
+       M1_R1 := boringCert(t, "M1_R1", boringECDSAKey(t, elliptic.P256()), R1, boringCertCA|boringCertFIPSOK)
+       M2_R1 := boringCert(t, "M2_R1", boringECDSAKey(t, elliptic.P224()), R1, boringCertCA)
+
+       I_R1 := boringCert(t, "I_R1", boringRSAKey(t, 3072), R1, boringCertCA|boringCertFIPSOK)
+       I_R2 := boringCert(t, "I_R2", I_R1.key, R2, boringCertCA|boringCertFIPSOK)
+       I_M1 := boringCert(t, "I_M1", I_R1.key, M1_R1, boringCertCA|boringCertFIPSOK)
+       I_M2 := boringCert(t, "I_M2", I_R1.key, M2_R1, boringCertCA|boringCertFIPSOK)
+
+       L1_I := boringCert(t, "L1_I", boringECDSAKey(t, elliptic.P384()), I_R1, boringCertLeaf|boringCertFIPSOK)
+       L2_I := boringCert(t, "L2_I", boringRSAKey(t, 1024), I_R1, boringCertLeaf)
+
+       // boringCert checked that isBoringCertificate matches the caller's boringCertFIPSOK bit.
+       // If not, no point in building bigger end-to-end tests.
+       if t.Failed() {
+               t.Fatalf("isBoringCertificate failures; not continuing")
+       }
+
+       // client verifying server cert
+       testServerCert := func(t *testing.T, desc string, pool *x509.CertPool, key interface{}, list [][]byte, ok bool) {
+               clientConfig := testConfig.Clone()
+               clientConfig.RootCAs = pool
+               clientConfig.InsecureSkipVerify = false
+               clientConfig.ServerName = "example.com"
+
+               serverConfig := testConfig.Clone()
+               serverConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}}
+               serverConfig.BuildNameToCertificate()
+
+               clientErr, _ := boringHandshake(t, clientConfig, serverConfig)
+
+               if (clientErr == nil) == ok {
+                       if ok {
+                               t.Logf("%s: accept", desc)
+                       } else {
+                               t.Logf("%s: reject", desc)
+                       }
+               } else {
+                       if ok {
+                               t.Errorf("%s: BAD reject (%v)", desc, clientErr)
+                       } else {
+                               t.Errorf("%s: BAD accept", desc)
+                       }
+               }
+       }
+
+       // server verifying client cert
+       testClientCert := func(t *testing.T, desc string, pool *x509.CertPool, key interface{}, list [][]byte, ok bool) {
+               clientConfig := testConfig.Clone()
+               clientConfig.ServerName = "example.com"
+               clientConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}}
+
+               serverConfig := testConfig.Clone()
+               serverConfig.ClientCAs = pool
+               serverConfig.ClientAuth = RequireAndVerifyClientCert
+
+               _, serverErr := boringHandshake(t, clientConfig, serverConfig)
+
+               if (serverErr == nil) == ok {
+                       if ok {
+                               t.Logf("%s: accept", desc)
+                       } else {
+                               t.Logf("%s: reject", desc)
+                       }
+               } else {
+                       if ok {
+                               t.Errorf("%s: BAD reject (%v)", desc, serverErr)
+                       } else {
+                               t.Errorf("%s: BAD accept", desc)
+                       }
+               }
+       }
+
+       // Run simple basic test with known answers before proceeding to
+       // exhaustive test with computed answers.
+       r1pool := x509.NewCertPool()
+       r1pool.AddCert(R1.cert)
+       testServerCert(t, "basic", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true)
+       testClientCert(t, "basic (client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true)
+       fipstls.Force()
+       testServerCert(t, "basic (fips)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false)
+       testClientCert(t, "basic (fips, client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false)
+       fipstls.Abandon()
+
+       if t.Failed() {
+               t.Fatal("basic test failed, skipping exhaustive test")
+       }
+
+       if testing.Short() {
+               t.Logf("basic test passed; skipping exhaustive test in -short mode")
+               return
+       }
+
+       for l := 1; l <= 2; l++ {
+               leaf := L1_I
+               if l == 2 {
+                       leaf = L2_I
+               }
+               for i := 0; i < 64; i++ {
+                       reachable := map[string]bool{leaf.parentOrg: true}
+                       reachableFIPS := map[string]bool{leaf.parentOrg: leaf.fipsOK}
+                       list := [][]byte{leaf.der}
+                       listName := leaf.name
+                       addList := func(cond int, c *boringCertificate) {
+                               if cond != 0 {
+                                       list = append(list, c.der)
+                                       listName += "," + c.name
+                                       if reachable[c.org] {
+                                               reachable[c.parentOrg] = true
+                                       }
+                                       if reachableFIPS[c.org] && c.fipsOK {
+                                               reachableFIPS[c.parentOrg] = true
+                                       }
+                               }
+                       }
+                       addList(i&1, I_R1)
+                       addList(i&2, I_R2)
+                       addList(i&4, I_M1)
+                       addList(i&8, I_M2)
+                       addList(i&16, M1_R1)
+                       addList(i&32, M2_R1)
+
+                       for r := 1; r <= 3; r++ {
+                               pool := x509.NewCertPool()
+                               rootName := ","
+                               shouldVerify := false
+                               shouldVerifyFIPS := false
+                               addRoot := func(cond int, c *boringCertificate) {
+                                       if cond != 0 {
+                                               rootName += "," + c.name
+                                               pool.AddCert(c.cert)
+                                               if reachable[c.org] {
+                                                       shouldVerify = true
+                                               }
+                                               if reachableFIPS[c.org] && c.fipsOK {
+                                                       shouldVerifyFIPS = true
+                                               }
+                                       }
+                               }
+                               addRoot(r&1, R1)
+                               addRoot(r&2, R2)
+                               rootName = rootName[1:] // strip leading comma
+                               testServerCert(t, listName+"->"+rootName[1:], pool, leaf.key, list, shouldVerify)
+                               testClientCert(t, listName+"->"+rootName[1:]+"(client cert)", pool, leaf.key, list, shouldVerify)
+                               fipstls.Force()
+                               testServerCert(t, listName+"->"+rootName[1:]+" (fips)", pool, leaf.key, list, shouldVerifyFIPS)
+                               testClientCert(t, listName+"->"+rootName[1:]+" (fips, client cert)", pool, leaf.key, list, shouldVerifyFIPS)
+                               fipstls.Abandon()
+                       }
+               }
+       }
+}
+
+const (
+       boringCertCA = iota
+       boringCertLeaf
+       boringCertFIPSOK = 0x80
+)
+
+func boringRSAKey(t *testing.T, size int) *rsa.PrivateKey {
+       k, err := rsa.GenerateKey(rand.Reader, size)
+       if err != nil {
+               t.Fatal(err)
+       }
+       return k
+}
+
+func boringECDSAKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey {
+       k, err := ecdsa.GenerateKey(curve, rand.Reader)
+       if err != nil {
+               t.Fatal(err)
+       }
+       return k
+}
+
+type boringCertificate struct {
+       name      string
+       org       string
+       parentOrg string
+       der       []byte
+       cert      *x509.Certificate
+       key       interface{}
+       fipsOK    bool
+}
+
+func boringCert(t *testing.T, name string, key interface{}, parent *boringCertificate, mode int) *boringCertificate {
+       org := name
+       parentOrg := ""
+       if i := strings.Index(org, "_"); i >= 0 {
+               org = org[:i]
+               parentOrg = name[i+1:]
+       }
+       tmpl := &x509.Certificate{
+               SerialNumber: big.NewInt(1),
+               Subject: pkix.Name{
+                       Organization: []string{org},
+               },
+               NotBefore: time.Unix(0, 0),
+               NotAfter:  time.Unix(0, 0),
+
+               KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+               ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
+               BasicConstraintsValid: true,
+       }
+       if mode&^boringCertFIPSOK == boringCertLeaf {
+               tmpl.DNSNames = []string{"example.com"}
+       } else {
+               tmpl.IsCA = true
+               tmpl.KeyUsage |= x509.KeyUsageCertSign
+       }
+
+       var pcert *x509.Certificate
+       var pkey interface{}
+       if parent != nil {
+               pcert = parent.cert
+               pkey = parent.key
+       } else {
+               pcert = tmpl
+               pkey = key
+       }
+
+       var pub interface{}
+       var desc string
+       switch k := key.(type) {
+       case *rsa.PrivateKey:
+               pub = &k.PublicKey
+               desc = fmt.Sprintf("RSA-%d", k.N.BitLen())
+       case *ecdsa.PrivateKey:
+               pub = &k.PublicKey
+               desc = "ECDSA-" + k.Curve.Params().Name
+       default:
+               t.Fatalf("invalid key %T", key)
+       }
+
+       der, err := x509.CreateCertificate(rand.Reader, tmpl, pcert, pub, pkey)
+       if err != nil {
+               t.Fatal(err)
+       }
+       cert, err := x509.ParseCertificate(der)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // Tell isBoringCertificate to enforce FIPS restrictions for this check.
+       fipstls.Force()
+       defer fipstls.Abandon()
+
+       fipsOK := mode&boringCertFIPSOK != 0
+       if isBoringCertificate(cert) != fipsOK {
+               t.Errorf("isBoringCertificate(cert with %s key) = %v, want %v", desc, !fipsOK, fipsOK)
+       }
+       return &boringCertificate{name, org, parentOrg, der, cert, key, fipsOK}
+}
+
+// A self-signed test certificate with an RSA key of size 2048, for testing
+// RSA-PSS with SHA512. SAN of example.golang.
+var (
+       testRSA2048Certificate []byte
+       testRSA2048PrivateKey  *rsa.PrivateKey
+)
+
+func init() {
+       block, _ := pem.Decode([]byte(`
+-----BEGIN CERTIFICATE-----
+MIIC/zCCAeegAwIBAgIRALHHX/kh4+4zMU9DarzBEcQwDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xMTAxMDExNTA0MDVaFw0yMDEyMjkxNTA0
+MDVaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCf8fk0N6ieCBX4IOVIfKitt4kGcOQLeimCfsjqqHcysMIVGEtFSM6E
+4Ay141f/7IqdW0UtIqNb4PXhROID7yDxR284xL6XbCuv/t5hP3UcehYc3hmLiyVd
+MkZQiZWtfUUJf/1qOtM+ohNg59LRWp4d+6iX0la1JL3EwCIckkNjJ9hQbF7Pb2CS
++ES9Yo55KAap8KOblpcR8MBSN38bqnwjfQdCXvOEOjam2HUxKzEFX5MA+fA0me4C
+ioCcCRLWKl+GoN9F8fABfoZ+T+2eal4DLuO95rXR8SrOIVBh3XFOr/RVhjtXcNVF
+ZKcvDt6d68V6jAKAYKm5nlj9GPpd4v+rAgMBAAGjUDBOMA4GA1UdDwEB/wQEAwIF
+oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBkGA1UdEQQSMBCC
+DmV4YW1wbGUuZ29sYW5nMA0GCSqGSIb3DQEBCwUAA4IBAQCOoYsVcFCBhboqe3WH
+dC6V7XXXECmnjh01r8h80yv0NR379nSD3cw2M+HKvaXysWqrl5hjGVKw0vtwD81r
+V4JzDu7IfIog5m8+QNC+7LqDZsz88vDKOrsoySVOmUCgmCKFXew+LA+eO/iQEJTr
+7ensddOeXJEp27Ed5vW+kmWW3Qmglc2Gwy8wFrMDIqnrnOzBA4oCnDEgtXJt0zog
+nRwbfEMAWi1aQRy5dT9KA3SP9mo5SeTFSzGGHiE4s4gHUe7jvsAFF2qgtD6+wH6s
+z9b6shxnC7g5IlBKhI7SVB/Uqt2ydJ+kH1YbjMcIq6NAM5eNMKgZuJr3+zwsSgwh
+GNaE
+-----END CERTIFICATE-----`))
+       testRSA2048Certificate = block.Bytes
+
+       block, _ = pem.Decode([]byte(`
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAn/H5NDeonggV+CDlSHyorbeJBnDkC3opgn7I6qh3MrDCFRhL
+RUjOhOAMteNX/+yKnVtFLSKjW+D14UTiA+8g8UdvOMS+l2wrr/7eYT91HHoWHN4Z
+i4slXTJGUImVrX1FCX/9ajrTPqITYOfS0VqeHfuol9JWtSS9xMAiHJJDYyfYUGxe
+z29gkvhEvWKOeSgGqfCjm5aXEfDAUjd/G6p8I30HQl7zhDo2pth1MSsxBV+TAPnw
+NJnuAoqAnAkS1ipfhqDfRfHwAX6Gfk/tnmpeAy7jvea10fEqziFQYd1xTq/0VYY7
+V3DVRWSnLw7enevFeowCgGCpuZ5Y/Rj6XeL/qwIDAQABAoIBAQCNpMZifd/vg42h
+HdCvLuZaYS0R7SunFlpoXEsltGdLFsnp0IfoJZ/ugFQBSAIIfLwMumU6oXA1z7Uv
+98aIYV61DePrTCDVDFBsHbNmP8JAo8WtbusEbwd5zyoB7LYG2+clkJklWE73KqUq
+rmI+UJeyScl2Gin7ZTxBXz1WPBk9VwcnwkeaXpgASIBW23fhECM9gnYEEwaBez5T
+6Me8d1tHtYQv7vsKe7ro9w9/HKrRXejqYKK1LxkhfFriyV+m8LZJZn2nXOa6G3gF
+Nb8Qk1Uk5PUBENBmyMFJhT4M/uuSq4YtMrrO2gi8Q+fPhuGzc5SshYKRBp0W4P5r
+mtVCtEFRAoGBAMENBIFLrV2+HsGj0xYFasKov/QPe6HSTR1Hh2IZONp+oK4oszWE
+jBT4VcnITmpl6tC1Wy4GcrxjNgKIFZAj+1x1LUULdorXkuG8yr0tAhG9zNyfWsSy
+PrSovC0UVbzr8Jxxla+kQVxEQQqWQxPlEVuL8kXaIDA6Lyt1Hpua2LvPAoGBANQZ
+c6Lq2T7+BxLxNdi2m8kZzej5kgzBp/XdVsbFWRlebIX2KrFHsrHzT9PUk3DE1vZK
+M6pzTt94nQhWSkDgCaw1SohElJ3HFIFwcusF1SJAc3pQepd8ug6IYdlpDMLtBj/P
+/5P6BVUtgo05E4+I/T3iYatmglQxTtlZ0RkSV2llAoGBALOXkKFX7ahPvf0WksDh
+uTfuFOTPoowgQG0EpgW0wRdCxeg/JLic3lSD0gsttQV2WsRecryWcxaelRg10RmO
+38BbogmhaF4xvgsSvujOfiZTE8oK1T43M+6NKsIlML3YILbpU/9aJxPWy0s2DqDr
+cQJhZrlk+pzjBA7Bnf/URdwxAoGAKR/CNw14D+mrL3YLbbiCXiydqxVwxv5pdZdz
+8thi3TNcsWC4iGURdcVqbfUinVPdJiXe/Kac3WGCeRJaFVgbKAOxLti1RB5MkIhg
+D8eyupBqk4W1L1gkrxqsdj4TFlxkwMywjl2E2S4YyQ8PBt6V04DoVRZsIKzqz+PF
+UionPq0CgYBCYXvqioJhPewkOq/Y5wrDBeZW1FQK5QD9W5M8/5zxd4rdvJtjhbJp
+oOrtvMdrl6upy9Hz4BJD3FXwVFiPFE7jqeNqi0F21viLxBPMMD3UODF6LL5EyLiR
+9V4xVMS8KXxvg7rxsuqzMPscViaWUL6WNVBhsD2+92dHxSXzz5EJKQ==
+-----END RSA PRIVATE KEY-----`))
+       var err error
+       testRSA2048PrivateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
+       if err != nil {
+               panic(err)
+       }
+}
index 4bf06468c6dae4741d0302b15b77f5219bc054ad..e07d742bd3b2d018c3215f7e0f3354bf6af2403f 100644 (file)
@@ -4,6 +4,8 @@
 
 package tls
 
+import "crypto/internal/boring"
+
 import (
        "crypto"
        "crypto/aes"
@@ -422,7 +424,13 @@ func cipherAES(key, iv []byte, isRead bool) interface{} {
 
 // macSHA1 returns a SHA-1 based constant time MAC.
 func macSHA1(key []byte) hash.Hash {
-       return hmac.New(newConstantTimeHash(sha1.New), key)
+       h := sha1.New
+       // The BoringCrypto SHA1 does not have a constant-time
+       // checksum function, so don't try to use it.
+       if !boring.Enabled {
+               h = newConstantTimeHash(h)
+       }
+       return hmac.New(h, key)
 }
 
 // macSHA256 returns a SHA-256 based MAC. This is only supported in TLS 1.2 and
@@ -510,7 +518,16 @@ func aeadAESGCM(key, noncePrefix []byte) aead {
        if err != nil {
                panic(err)
        }
-       aead, err := cipher.NewGCM(aes)
+       type gcmtls interface {
+               NewGCMTLS() (cipher.AEAD, error)
+       }
+       var aead cipher.AEAD
+       if aesTLS, ok := aes.(gcmtls); ok {
+               aead, err = aesTLS.NewGCMTLS()
+       } else {
+               boring.Unreachable()
+               aead, err = cipher.NewGCM(aes)
+       }
        if err != nil {
                panic(err)
        }
@@ -570,6 +587,7 @@ func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) }
 func (c *cthWrapper) Sum(b []byte) []byte         { return c.h.ConstantTimeSum(b) }
 
 func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
+       boring.Unreachable()
        return func() hash.Hash {
                return &cthWrapper{h().(constantTimeHash)}
        }
index 77957ef82bd9d3752e31a422314be9d932a65d64..ca93d4341d5de5895e69fa45e853bcc66be665d6 100644 (file)
@@ -171,11 +171,11 @@ const (
 // hash function associated with the Ed25519 signature scheme.
 var directSigning crypto.Hash = 0
 
-// supportedSignatureAlgorithms contains the signature and hash algorithms that
+// defaultSupportedSignatureAlgorithms contains the signature and hash algorithms that
 // the code advertises as supported in a TLS 1.2+ ClientHello and in a TLS 1.2+
 // CertificateRequest. The two fields are merged to match with TLS 1.3.
 // Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc.
-var supportedSignatureAlgorithms = []SignatureScheme{
+var defaultSupportedSignatureAlgorithms = []SignatureScheme{
        PSSWithSHA256,
        ECDSAWithP256AndSHA256,
        Ed25519,
@@ -951,6 +951,9 @@ func (c *Config) time() time.Time {
 }
 
 func (c *Config) cipherSuites() []uint16 {
+       if needFIPS() {
+               return fipsCipherSuites(c)
+       }
        if c.CipherSuites != nil {
                return c.CipherSuites
        }
@@ -967,6 +970,9 @@ var supportedVersions = []uint16{
 func (c *Config) supportedVersions() []uint16 {
        versions := make([]uint16, 0, len(supportedVersions))
        for _, v := range supportedVersions {
+               if needFIPS() && (v < fipsMinVersion(c) || v > fipsMaxVersion(c)) {
+                       continue
+               }
                if c != nil && c.MinVersion != 0 && v < c.MinVersion {
                        continue
                }
@@ -1003,6 +1009,9 @@ func supportedVersionsFromMax(maxVersion uint16) []uint16 {
 var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521}
 
 func (c *Config) curvePreferences() []CurveID {
+       if needFIPS() {
+               return fipsCurvePreferences(c)
+       }
        if c == nil || len(c.CurvePreferences) == 0 {
                return defaultCurvePreferences
        }
diff --git a/src/crypto/tls/fipsonly/fipsonly.go b/src/crypto/tls/fipsonly/fipsonly.go
new file mode 100644 (file)
index 0000000..85b3532
--- /dev/null
@@ -0,0 +1,27 @@
+// 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.
+
+// Package fipsonly restricts all TLS configuration to FIPS-approved settings.
+//
+// The effect is triggered by importing the package anywhere in a program, as in:
+//
+//     import _ "crypto/tls/fipsonly"
+//
+// This package only exists in the dev.boringcrypto branch of Go.
+package fipsonly
+
+// This functionality is provided as a side effect of an import to make
+// it trivial to add to an existing program. It requires only a single line
+// added to an existing source file, or it can be done by adding a whole
+// new source file and not modifying any existing source files.
+
+import (
+       "crypto/internal/boring/fipstls"
+       "crypto/internal/boring/sig"
+)
+
+func init() {
+       fipstls.Force()
+       sig.FIPSOnly()
+}
diff --git a/src/crypto/tls/fipsonly/fipsonly_test.go b/src/crypto/tls/fipsonly/fipsonly_test.go
new file mode 100644 (file)
index 0000000..facd248
--- /dev/null
@@ -0,0 +1,16 @@
+// 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.
+
+package fipsonly
+
+import (
+       "crypto/internal/boring/fipstls"
+       "testing"
+)
+
+func Test(t *testing.T) {
+       if !fipstls.Required() {
+               t.Fatal("fipstls.Required() = false, must be true")
+       }
+}
index 13a7f3442c934031e59d2dc64ddf89f4bec3d80e..9582a7f867514d9fedf63b218c08c27c131228bd 100644 (file)
@@ -117,7 +117,10 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
        }
 
        if hello.vers >= VersionTLS12 {
-               hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms
+               hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+       }
+       if testingOnlyForceClientHelloSignatureAlgorithms != nil {
+               hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms
        }
 
        var params ecdheParameters
@@ -845,6 +848,8 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
 
        if !c.config.InsecureSkipVerify {
                opts := x509.VerifyOptions{
+                       IsBoring: isBoringCertificate,
+
                        Roots:         c.config.RootCAs,
                        CurrentTime:   c.config.time(),
                        DNSName:       c.config.ServerName,
index be37c681c6dee92a73e15945c9a7c3063a6dedf9..1405d6811f3e3eb387b83934cbd8d757e7ee7c2d 100644 (file)
@@ -41,6 +41,10 @@ type clientHandshakeStateTLS13 struct {
 func (hs *clientHandshakeStateTLS13) handshake() error {
        c := hs.c
 
+       if needFIPS() {
+               return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
+       }
+
        // The server must not select TLS 1.3 in a renegotiation. See RFC 8446,
        // sections 4.1.2 and 4.1.3.
        if c.handshakes > 0 {
@@ -476,7 +480,7 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
        }
 
        // See RFC 8446, Section 4.4.3.
-       if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms) {
+       if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
                c.sendAlert(alertIllegalParameter)
                return errors.New("tls: certificate used with invalid signature algorithm")
        }
index bb8aea86700509d82222e73ae6f30eedb59ef1f7..8821670e9ae432803fce44b136f502c2aa020d60 100644 (file)
@@ -147,10 +147,10 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
                }
        }
        if rand.Intn(10) > 5 {
-               m.supportedSignatureAlgorithms = supportedSignatureAlgorithms
+               m.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
        }
        if rand.Intn(10) > 5 {
-               m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms
+               m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms()
        }
        for i := 0; i < rand.Intn(5); i++ {
                m.alpnProtocols = append(m.alpnProtocols, randomString(rand.Intn(20)+1, rand))
@@ -369,10 +369,10 @@ func (*certificateRequestMsgTLS13) Generate(rand *rand.Rand, size int) reflect.V
                m.scts = true
        }
        if rand.Intn(10) > 5 {
-               m.supportedSignatureAlgorithms = supportedSignatureAlgorithms
+               m.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
        }
        if rand.Intn(10) > 5 {
-               m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms
+               m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms()
        }
        if rand.Intn(10) > 5 {
                m.certificateAuthorities = make([][]byte, 3)
index b231981e09fff146e06e72b7c9b00cae9aff3fd8..85afad067158e4cd9d1405628dae6f6ad7fd33ed 100644 (file)
@@ -515,7 +515,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
                }
                if c.vers >= VersionTLS12 {
                        certReq.hasSignatureAlgorithm = true
-                       certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms
+                       certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
                }
 
                // An empty list of certificateAuthorities signals to
@@ -786,6 +786,8 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
 
        if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
                opts := x509.VerifyOptions{
+                       IsBoring: isBoringCertificate,
+
                        Roots:         c.config.ClientCAs,
                        CurrentTime:   c.config.time(),
                        Intermediates: x509.NewCertPool(),
index c375ec42466825cfacf454054866a646d9193c5c..742fdc3c05c8eef899c64ea10a0bb69e9fbabb3d 100644 (file)
@@ -45,6 +45,10 @@ type serverHandshakeStateTLS13 struct {
 func (hs *serverHandshakeStateTLS13) handshake() error {
        c := hs.c
 
+       if needFIPS() {
+               return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
+       }
+
        // For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2.
        if err := hs.processClientHello(); err != nil {
                return err
@@ -586,7 +590,7 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
                certReq := new(certificateRequestMsgTLS13)
                certReq.ocspStapling = true
                certReq.scts = true
-               certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms
+               certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
                if c.config.ClientCAs != nil {
                        certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
                }
@@ -805,7 +809,7 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
                }
 
                // See RFC 8446, Section 4.4.3.
-               if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms) {
+               if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
                        c.sendAlert(alertIllegalParameter)
                        return errors.New("tls: client certificate used with invalid signature algorithm")
                }
index 9ef11466a470a3730ea08614a4a0dd8e907d723f..1f9636a550f038eefd466682911d29f27e5e9c67 100644 (file)
@@ -172,6 +172,11 @@ var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificat
 
 // VerifyOptions contains parameters for Certificate.Verify.
 type VerifyOptions struct {
+       // IsBoring is a validity check for BoringCrypto.
+       // If not nil, it will be called to check whether a given certificate
+       // can be used for constructing verification chains.
+       IsBoring func(*Certificate) bool
+
        // DNSName, if set, is checked against the leaf certificate with
        // Certificate.VerifyHostname or the platform verifier.
        DNSName string
@@ -695,6 +700,13 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
                }
        }
 
+       if opts.IsBoring != nil && !opts.IsBoring(c) {
+               // IncompatibleUsage is not quite right here,
+               // but it's also the "no chains found" error
+               // and is close enough.
+               return CertificateInvalidError{c, IncompatibleUsage, ""}
+       }
+
        return nil
 }
 
index 8d1a107c6ea713836407ae143607cf2f8a858348..c5895290e4cd2d73aebb6684eb8ce11ab73de124 100644 (file)
@@ -1871,6 +1871,7 @@ func (ctxt *Context) eval(x constraint.Expr, allTags map[string]bool) bool {
 //     cgo (if cgo is enabled)
 //     $GOOS
 //     $GOARCH
+//     boringcrypto
 //     ctxt.Compiler
 //     linux (if GOOS = android)
 //     solaris (if GOOS = illumos)
@@ -1898,6 +1899,10 @@ func (ctxt *Context) matchTag(name string, allTags map[string]bool) bool {
        if ctxt.GOOS == "ios" && name == "darwin" {
                return true
        }
+       // Let applications know that the Go+BoringCrypto toolchain is in use.
+       if name == "boringcrypto" {
+               return true
+       }
 
        // other tags
        for _, tag := range ctxt.BuildTags {
index bb6d92f89acacf9986d0dbffe47d32c327d119b3..a2423cf0d932435b970a150475506be42174d175 100644 (file)
@@ -332,7 +332,7 @@ var depsRules = `
 
        # Bulk of the standard library must not use cgo.
        # The prohibition stops at net and os/user.
-       C !< fmt, go/types, CRYPTO-MATH;
+       C !< fmt, go/types;
 
        CGO, OS
        < plugin;
@@ -386,38 +386,36 @@ var depsRules = `
        NET, log
        < net/mail;
 
-       # CRYPTO is core crypto algorithms - no cgo, fmt, net.
-       # Unfortunately, stuck with reflect via encoding/binary.
-       encoding/binary, golang.org/x/sys/cpu, hash
+       NONE < crypto/internal/boring/sig;
+       sync/atomic < crypto/internal/boring/fipstls;
+
+       encoding/binary, golang.org/x/sys/cpu, hash,
+       FMT, math/big,
+       CGO, crypto/internal/boring/sig, crypto/internal/boring/fipstls
        < crypto
        < crypto/subtle
        < crypto/internal/subtle
        < crypto/ed25519/internal/edwards25519/field
        < crypto/ed25519/internal/edwards25519
        < crypto/cipher
+       < encoding/asn1
+       < crypto/internal/boring
        < crypto/aes, crypto/des, crypto/hmac, crypto/md5, crypto/rc4,
          crypto/sha1, crypto/sha256, crypto/sha512
-       < CRYPTO;
-
-       CGO, fmt, net !< CRYPTO;
-
-       # CRYPTO-MATH is core bignum-based crypto - no cgo, net; fmt now ok.
-       CRYPTO, FMT, math/big
        < crypto/rand
        < crypto/internal/randutil
        < crypto/ed25519
-       < encoding/asn1
        < golang.org/x/crypto/cryptobyte/asn1
        < golang.org/x/crypto/cryptobyte
        < golang.org/x/crypto/curve25519
        < crypto/dsa, crypto/elliptic, crypto/rsa
        < crypto/ecdsa
-       < CRYPTO-MATH;
+       < CRYPTO-BORING;
 
-       CGO, net !< CRYPTO-MATH;
+       net !< CRYPTO-BORING;
 
        # TLS, Prince of Dependencies.
-       CRYPTO-MATH, NET, container/list, encoding/hex, encoding/pem
+       CRYPTO-BORING, NET, container/list, encoding/hex, encoding/pem
        < golang.org/x/crypto/internal/subtle
        < golang.org/x/crypto/chacha20
        < golang.org/x/crypto/poly1305
@@ -428,6 +426,12 @@ var depsRules = `
        < crypto/x509
        < crypto/tls;
 
+       crypto/internal/boring/sig, crypto/internal/boring/fipstls
+       < crypto/tls/fipsonly;
+
+       crypto/internal/boring
+       < crypto/boring;
+
        # crypto-aware packages
 
        NET, crypto/rand, mime/quotedprintable
diff --git a/src/internal/boringtest/boring.go b/src/internal/boringtest/boring.go
new file mode 100644 (file)
index 0000000..bea1276
--- /dev/null
@@ -0,0 +1,8 @@
+// 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.
+
+// Nothing to see here but the tests.
+// This file keeps 'go install internal/...' working.
+
+package boring
diff --git a/src/internal/boringtest/boring_test.go b/src/internal/boringtest/boring_test.go
new file mode 100644 (file)
index 0000000..a6b07ed
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+// Like crypto/rsa/boring_test.go but outside the crypto/ tree.
+// Tests what happens if a package outside the crypto/ tree
+// "adopts" a struct definition. This happens in golang.org/x/crypto/ssh.
+
+package boring
+
+import (
+       "crypto/rand"
+       "crypto/rsa"
+       "encoding/asn1"
+       "reflect"
+       "testing"
+)
+
+type publicKey rsa.PublicKey
+
+func TestBoringASN1Marshal(t *testing.T) {
+       k, err := rsa.GenerateKey(rand.Reader, 128)
+       if err != nil {
+               t.Fatal(err)
+       }
+       pk := (*publicKey)(&k.PublicKey)
+       // This used to fail, because of the unexported 'boring' field.
+       // Now the compiler hides it [sic].
+       _, err = asn1.Marshal(*pk)
+       if err != nil {
+               t.Fatal(err)
+       }
+}
+
+func TestBoringDeepEqual(t *testing.T) {
+       k0, err := rsa.GenerateKey(rand.Reader, 128)
+       if err != nil {
+               t.Fatal(err)
+       }
+       k := (*publicKey)(&k0.PublicKey)
+       k2 := *k
+       rsa.EncryptPKCS1v15(rand.Reader, (*rsa.PublicKey)(&k2), []byte("hello")) // initialize hidden boring field
+       if !reflect.DeepEqual(k, &k2) {
+               // compiler should be hiding the boring field from reflection
+               t.Fatalf("DeepEqual compared boring fields")
+       }
+}
index 5d25ed4bb64f5f0c039823ea9edba9631ee3d34d..b60cabfe86aacc506efd984b5af6efd3ea0ac220 100644 (file)
@@ -6,9 +6,9 @@ package race_test
 
 import (
        "bytes"
-       "crypto/sha1"
        "errors"
        "fmt"
+       "hash/crc32"
        "io"
        "os"
        "runtime"
@@ -1924,7 +1924,7 @@ func TestRaceIssue5567(t *testing.T) {
                        err = nil
                }
        }()
-       h := sha1.New()
+       h := crc32.New(crc32.MakeTable(0x12345678))
        for b := range in {
                h.Write(b)
        }
diff --git a/src/runtime/runtime_boring.go b/src/runtime/runtime_boring.go
new file mode 100644 (file)
index 0000000..5a98b20
--- /dev/null
@@ -0,0 +1,19 @@
+// 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.
+
+package runtime
+
+import _ "unsafe" // for go:linkname
+
+//go:linkname boring_runtime_arg0 crypto/internal/boring.runtime_arg0
+func boring_runtime_arg0() string {
+       // On Windows, argslice is not set, and it's too much work to find argv0.
+       if len(argslice) == 0 {
+               return ""
+       }
+       return argslice[0]
+}
+
+//go:linkname fipstls_runtime_arg0 crypto/internal/boring/fipstls.runtime_arg0
+func fipstls_runtime_arg0() string { return boring_runtime_arg0() }