Compare commits

...

36 Commits

Author SHA1 Message Date
Russ Cox
42cb4dcdb5 [dev.boringcrypto.go1.8] api: add x509.VerifyOptions.IsBoring
Change-Id: I288938f86937a226071a0375a619afa0c0506b0b
Reviewed-on: https://go-review.googlesource.com/65512
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-09-22 20:08:32 +00:00
Russ Cox
93c869ec16 [dev.boringcrypto.go1.8] misc/boring: update VERSION
Change-Id: I805422f3bc4a8a64e55b7453da25c9d1e18f063f
Reviewed-on: https://go-review.googlesource.com/65394
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-on: https://go-review.googlesource.com/65511
2017-09-22 20:08:30 +00:00
Russ Cox
6201a632a2 [dev.boringcrypto.go1.8] crypto/tls/fipsonly: new package to force FIPS-allowed TLS settings
Change-Id: I3268cab2de8aed9e2424e9c3bc7667083bc5e1ce
Reviewed-on: https://go-review.googlesource.com/65250
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/65510
Reviewed-by: Russ Cox <rsc@golang.org>
2017-09-22 20:08:27 +00:00
Russ Cox
af56294e54 [dev.boringcrypto.go1.8] crypto/internal/boring: fix finalizer-induced crashes
All the finalizer-enabled C wrappers must be careful to use
runtime.KeepAlive to ensure the C wrapper object (a Go object)
lives through the end of every C call using state that the
wrapper's finalizer would free.

This CL makes the wrappers appropriately careful.

The test proves that this is the bug I was chasing in a
separate real program, and that the KeepAlives fix it.
I did not write a test of every possible operation.

Change-Id: I627007e480f16adf8396e7f796b54e5525d9ea80
Reviewed-on: https://go-review.googlesource.com/64870
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/65489
2017-09-22 20:08:25 +00:00
Russ Cox
6e3cb838fc [dev.boringcrypto.go1.8] cmd/go: exclude SysoFiles when using -msan
There's no way for a *.syso file to be compiled to work both in
normal mode and in msan mode. Assume they are compiled in
normal mode and drop them in msan mode.

Packages with syso files currently fail in -msan mode because
the syso file calls out to a routine like memcmp which then
falsely reports uninitialized memory. After this CL, they will fail
in -msan with link errors, because the syso will not be used.
But then it will at least be possible for package authors to write
fallback code in the package that avoids the syso in -msan mode,
so that the package with the syso can at least run in both modes.
Without this CL, that's not possible.

See #21884.

Change-Id: I77340614c4711325032484e65fa9c3f8332741d5
Reviewed-on: https://go-review.googlesource.com/63917
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/65488
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-09-22 20:08:23 +00:00
Russ Cox
39d24b6b6d [dev.boringcrypto.go1.8] crypto/internal/boring: fall back to standard crypto when using -msan
The syso is not compiled with -fsanitize=memory, so don't try to use it.
Otherwise the first time it calls out to memcmp, memcmp complains
that it is being asked to compare uninitialized memory.

Change-Id: I85ab707cfbe64eded8e110d4d6b40d1b75f50541
Reviewed-on: https://go-review.googlesource.com/63916
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/65487
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-09-22 20:08:21 +00:00
Russ Cox
52f2e65060 [dev.boringcrypto.go1.8] crypto/aes: panic on invalid dst, src overlap
I've now debugged multiple mysterious "inability to communicate"
bugs that manifest as a silent unexplained authentication failure but are
really crypto.AEAD.Open being invoked with badly aligned buffers.
In #21624 I suggested using a panic as the consequence of bad alignment,
so that this kind of failure is loud and clearly different from, say, a
corrupted or invalid message signature. Adding the panic here made
my failure very easy to track down, once I realized that was the problem.
I don't want to debug another one of these.

Also using this CL as an experiment to get data about the impact of
maybe applying this change more broadly in the master branch.

Change-Id: Id2e2d8e980439f8acacac985fc2674f7c96c5032
Reviewed-on: https://go-review.googlesource.com/63915
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/65486
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-09-22 20:08:18 +00:00
Russ Cox
0c01487988 [dev.boringcrypto.go1.8] crypto/rsa: fix boring GenerateKey to set non-nil Precomputed.CRTValues
This matches the standard GenerateKey and more importantly Precompute,
so that if you generate a key and then store it, read it back, call Precompute
on the new copy, and then do reflect.DeepEqual on the two copies, they
will match. Before this CL, the original key had CRTValues == nil and the
reconstituted key has CRTValues != nil (but len(CRTValues) == 0).

Change-Id: I1ddc64342a50a1b65a48d827e4d564f1faab1945
Reviewed-on: https://go-review.googlesource.com/63914
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/65485
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-09-22 20:08:16 +00:00
Russ Cox
deabc8dc44 [dev.boringcrypto.go1.8] crypto/internal/boring: fix detection of tests to allow *.test and *_test
When using the go command, test binaries end in .test,
but when using Bazel, test binaries conventionally end in _test.

Change-Id: Ic4cac8722fd93ae316169f87b321f68e0b71f0c3
Reviewed-on: https://go-review.googlesource.com/63913
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/65484
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-09-22 20:08:13 +00:00
Russ Cox
86b7b52729 [dev.boringcrypto.go1.8] crypto/rsa: add test for, fix observable reads from custom randomness
In routines like GenerateKey, where bits from the randomness source have a
visible effect on the output, we bypass BoringCrypto if given a non-standard
randomness source (and also assert that this happens only during tests).

In the decryption paths, the randomness source is only for blinding and has
no effect on the output, so we unconditionally invoke BoringCrypto, letting it
use its own randomness source as it sees fit. This in turn lets us verify that
the non-BoringCrypto decryption function is never called, not even in tests.

Unfortunately, while the randomness source has no visible effect on the
decrypt operation, the decrypt operation does have a visible effect on
the randomness source. If decryption doesn't use the randomness source,
and it's a synthetic stream, then a future operation will read a different
position in the stream and may produce different output. This happens
in tests more often than you'd hope.

To keep behavior of those future operations unchanged while still
ensuring that the original decrypt is never called, this CL adds a
simulation of the blinding preparation, to discard the right amount
from the random source before invoking BoringCrypto.

Change-Id: If2f87b856c811b59b536187c93efa99a97721419
Reviewed-on: https://go-review.googlesource.com/63912
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/65483
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-09-22 20:08:11 +00:00
Russ Cox
0bc83d7aaa [dev.boringcrypto.go1.8] crypto/hmac: add test for Write/Sum after Sum
This is documented to work (in hash.Hash's definition)
and existing code assumes it works. Add a test.

Change-Id: I63546f3b2d66222683a4f268a4eaff835fd836fe
Reviewed-on: https://go-review.googlesource.com/63911
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/65482
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-09-22 20:08:08 +00:00
Russ Cox
f2a2dbe422 [dev.boringcrypto.go1.8] crypto/internal/boring: allow hmac operations after Sum
hmac.New returns a hash.Hash, which defines Sum as:

	// Sum appends the current hash to b and returns the resulting slice.
	// It does not change the underlying hash state.
	Sum(b []byte) []byte

I've now seen two different pieces of code that make
use of the assumption that Sum has no effect on the
internal state, so make it so.

Test in next CL in stack, so that it can be cherry-picked
to master.

Change-Id: Iad84ab3e2cc12dbecef25c3fc8f2662d157b0d0b
Reviewed-on: https://go-review.googlesource.com/63910
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/65481
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-09-22 20:08:05 +00:00
Russ Cox
eb32dbc4f6 [dev.boringcrypto.go1.8] crypto/internal/boring: handle RSA verification of short signatures
The standard Go crypto/rsa allows signatures to be shorter
than the RSA modulus and assumes leading zeros.
BoringCrypto does not, so supply the leading zeros explicitly.

This fixes the golang.org/x/crypto/openpgp tests.

Change-Id: Ic8b18d6beb0e02992a0474f5fdb2b73ccf7098cf
Reviewed-on: https://go-review.googlesource.com/62170
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/65480
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-09-22 20:08:03 +00:00
Russ Cox
11e083e44b [dev.boringcrypto.go1.8] cmd/compile: refine BoringCrypto kludge
Did not consider these fields being embedded or adopted
into structs defined in other packages, but that's possible too.
Refine the import path check to account for that.

Fixes 'go test -short golang.org/x/crypto/ssh' but also
adds a new test in internal/boring for the same problem.

Change-Id: Ied2d04fe2b0ac3b0a34f07bc8dfc50fc203abb9f
Reviewed-on: https://go-review.googlesource.com/62152
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/65479
Run-TryBot: Russ Cox <rsc@golang.org>
2017-09-22 20:08:00 +00:00
Russ Cox
043302c56d [dev.boringcrypto.go1.8] cmd/compile: hide new boring fields from reflection
This is terrible but much simpler, cleaner, and more effective
than all the alternatives I have come up with.

Lots of code assumes that reflect.DeepEqual is meaningful
on rsa.PublicKey etc, because previously they consisted only of
exported meaningful fields.

Worse, there exists code that assumes asn1.Marshal can be
passed an rsa.PublicKey, because that struct has historically
matched exactly the form that would be needed to produce
the official ASN.1 DER encoding of an RSA public key.

Instead of tracking down and fixing all of that code
(and probably more), we can limit the BoringCrypto-induced
damage by ensliting the compiler to hide the new field
from reflection. Then nothing can get at it and nothing can
be disrupted by it.

Kill two birds with one cannon ball.

I'm very sorry.

Change-Id: I0ca4d6047c7e98f880cbb81904048c1952e278cc
Reviewed-on: https://go-review.googlesource.com/60271
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/65478
Run-TryBot: Russ Cox <rsc@golang.org>
2017-09-22 20:07:58 +00:00
Russ Cox
20cf471364 [dev.boringcrypto.go1.8] crypto/internal/boring: fix NewHMAC with empty key
Test is in a separate CL for easier cherry-picking to master branch.

Change-Id: Ia4a9032892d2896332010fe18a3216f8c4a58d1c
Reviewed-on: https://go-review.googlesource.com/59770
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/65477
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-09-22 20:07:55 +00:00
Russ Cox
f2ab41b02d [dev.boringcrypto.go1.8] crypto/internal/cipherhw: fix AESGCMSupport for BoringCrypto
The override was not commented and was in the wrong file.

Change-Id: I739db561acff6d91b0f3559c8bb45437f11c0b04
Reviewed-on: https://go-review.googlesource.com/59250
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/65476
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-09-22 20:07:52 +00:00
Russ Cox
2f048bcaf9 [dev.boringcrypto.go1.8] misc/boring: increment VERSION to 3
This includes the new tags to fix non-cgo builds.

Change-Id: Id2a0dbcf2a229b9e2c0bc35a51312ac1031ce651
Reviewed-on: https://go-review.googlesource.com/58770
Reviewed-by: Adam Langley <agl@golang.org>
2017-08-26 00:52:45 +00:00
Russ Cox
a6fa239225 [dev.boringcrypto.go1.8] crypto/internal/boring: clear "executable stack" bit from syso
Change-Id: Ie9dd13f3ae78a423a231f47e746a38f96768b93c
Reviewed-on: https://go-review.googlesource.com/58830
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/58971
Reviewed-by: Adam Langley <agl@golang.org>
2017-08-26 00:52:42 +00:00
Russ Cox
d5efcb1ead [dev.boringcrypto.go1.8] cmd/link: allow internal linking for crypto/internal/boring
Change-Id: I5b122ad23f75296dab8cec89a4e50dcca7fa9b3f
Reviewed-on: https://go-review.googlesource.com/57944
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/58071
Reviewed-by: Adam Langley <agl@golang.org>
2017-08-26 00:52:40 +00:00
Russ Cox
4aff713ddb [dev.boringcrypto.go1.8] cmd/link: work around DWARF symbol bug
The DWARF code is mishandling the case when the host object files
define multiple (distinct) symbols with the same name. They are mapped
to the same DWARF debug symbol, which then appears on the dwarfp
list multiple times, which then breaks the code that processes the list.
Detect duplicates and skip them, because that's trivial, instead of fixing
the underlying problem.

See #21566.

Change-Id: Ib5a34c891d7c15f4c7bb6239d8f31a1ec767b8bc
Reviewed-on: https://go-review.googlesource.com/57943
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/58070
Reviewed-by: Adam Langley <agl@golang.org>
2017-08-26 00:52:37 +00:00
Russ Cox
08c54565dc [dev.boringcrypto.go1.8] crypto/internal/boring: disable for android & non-cgo builds
Change-Id: Ia4458090118c4391a73cf1ae65bc8d187f03eca0
Reviewed-on: https://go-review.googlesource.com/58250
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-08-26 00:52:35 +00:00
Russ Cox
1da9aa90bc [dev.boringcrypto.go1.8] crypto/rsa: use BoringCrypto
Change-Id: Ibb92f0f8cb487f4d179b069e588e1cb266599384
Reviewed-on: https://go-review.googlesource.com/55479
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/57942
2017-08-26 00:52:33 +00:00
Russ Cox
775b2384e7 [dev.boringcrypto.go1.8] crypto/ecdsa: use unsafe.Pointer instead of atomic.Value
Using atomic.Value causes vet errors in code copying
PublicKey or PrivateKey structures. I don't think the errors
are accurate, but it's easier to work around them than
to change vet or change atomic.Value.

See #21504.

Change-Id: I3a3435c1fc664cc5166c81674f6f7c58dab35f21
Reviewed-on: https://go-review.googlesource.com/56671
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/57941
2017-08-26 00:52:31 +00:00
Russ Cox
fb11572dfd [dev.boringcrypto.go1.8] crypto/ecdsa: use BoringCrypto
Change-Id: I108e0a527bddd673b16582d206e0697341d0a0ea
Reviewed-on: https://go-review.googlesource.com/55478
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/57940
2017-08-26 00:52:29 +00:00
Russ Cox
ddd775ff44 [dev.boringcrypto.go1.8] crypto/tls: use TLS-specific AES-GCM mode if available
Change-Id: Ide00c40c0ca8d486f3bd8968e1d301c8b0ed6d05
Reviewed-on: https://go-review.googlesource.com/56011
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/57939
2017-08-26 00:52:26 +00:00
Russ Cox
cb5b47443f [dev.boringcrypto.go1.8] crypto/aes: implement TLS-specific AES-GCM mode from BoringCrypto
Change-Id: I8407310e7d00eafe9208879228dbf4ac3d26a907
Reviewed-on: https://go-review.googlesource.com/55477
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/57938
2017-08-26 00:52:24 +00:00
Russ Cox
33ebf73c45 [dev.boringcrypto.go1.8] crypto/aes: use BoringCrypto
Change-Id: If83fdeac31f65aba818bbc7edd2f215b16814021
Reviewed-on: https://go-review.googlesource.com/55476
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/57937
2017-08-26 00:52:20 +00:00
Russ Cox
065bb6eb30 [dev.boringcrypto.go1.8] crypto/hmac: use BoringCrypto
Change-Id: Id4019d601c615b4835b0337d82be3d508292810e
Reviewed-on: https://go-review.googlesource.com/55475
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/57936
2017-08-26 00:52:18 +00:00
Russ Cox
367461427e [dev.boringcrypto.go1.8] crypto/sha1,sha256,sha512: use BoringCrypto
Change-Id: I80a764971b41f75c3b699797bfed71f509e3407d
Reviewed-on: https://go-review.googlesource.com/55474
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/57935
2017-08-26 00:52:16 +00:00
Russ Cox
497ad3015b [dev.boringcrypto.go1.8] runtime/race: move TestRaceIssue5567 from sha1 to crc32
If we substitute a SHA1 implementation where the entirety of the
reading of the buffer is done in assembly (or C called from cgo),
then the race detector cannot observe the race.

Change to crc32 with a fake polynomial, in the hope that it will
always be handled by Go code, not optimized assembly or cgo calls.

Change-Id: I34e90b14ede6bc220ef686f6aef16b8e464b5cde
Reviewed-on: https://go-review.googlesource.com/56510
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/57934
Reviewed-by: Adam Langley <agl@golang.org>
2017-08-26 00:52:14 +00:00
Russ Cox
73f9e27276 [dev.boringcrypto.go1.8] crypto/rand: use BoringCrypto
Change-Id: Ie630eff90f7fee9b359683930aec2daf96c1bdfe
Reviewed-on: https://go-review.googlesource.com/55473
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/57933
2017-08-26 00:52:12 +00:00
Russ Cox
4ab59be66e [dev.boringcrypto.go1.8] crypto/internal/boring: add initial BoringCrypto access
Right now the package doesn't do anything useful, but it will.
This CL is about the machinery for building goboringcrypto_linux_amd64.syso
and then running the self-test and checking FIPS_mode from Go init.

Change-Id: I4ec0f5efaa88ccfb506b9818d24a7f1cbcc5a7d6
Reviewed-on: https://go-review.googlesource.com/55472
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/57932
2017-08-26 00:52:09 +00:00
Russ Cox
4f6c6be21e [dev.boringcrypto.go1.8] add README.boringcrypto.md, update VERSION
Change-Id: I415fcc23b62666d78aed3ddc7d2731127c810be3
Reviewed-on: https://go-review.googlesource.com/55471
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-on: https://go-review.googlesource.com/57931
2017-08-26 00:52:07 +00:00
Russ Cox
e6ba6f7890 [dev.boringcrypto.go1.8] cmd/link: implement R_X86_64_PC64 relocations
Change-Id: I1d7bd5cff7350a4e0f78b8efc8406e79c74732d1
Reviewed-on: https://go-review.googlesource.com/55370
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/55470
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-on: https://go-review.googlesource.com/57930
Reviewed-by: Adam Langley <agl@golang.org>
2017-08-26 00:52:04 +00:00
Chris Broadfoot
f3e6216450 [release-branch.go1.8] doc: update bootstrap archive URL
This includes the patch for systems that build PIE executables by
defaul

Updates #20276.

Change-Id: Iecf8dfcf11bc18d397b8075559c37e3610f825cb
Reviewed-on: https://go-review.googlesource.com/44470
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/44491
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-05-31 21:06:00 +00:00
78 changed files with 4448 additions and 47 deletions

18
README.boringcrypto.md Normal file
View File

@@ -0,0 +1,18 @@
# dev.boringcrypto branch
We have been working inside Google on a fork of Go that uses
BoringCrypto (the core of [BoringSSL](https://boringssl.googlesource.com/boringssl/)) for various crypto primitives, in
furtherance of some [work related to FIPS 140-2](http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140sp/140sp2964.pdf). We have heard that
some external users of Go would be interested in this code as well, so
I intend to create a new branch dev.boringcrypto that will hold
patches to make Go use BoringCrypto.
Unlike typical dev branches, we do not intend any eventual merge of
this code into the master branch. Instead we intend to maintain in
that branch the latest release plus BoringCrypto patches. In this
sense it is a bit like dev.typealias holding go1.8+type alias 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.

View File

@@ -1 +0,0 @@
go1.8.3

View File

@@ -57,6 +57,7 @@ pkg crypto/x509, const SHA384WithRSAPSS SignatureAlgorithm
pkg crypto/x509, const SHA512WithRSAPSS = 15
pkg crypto/x509, const SHA512WithRSAPSS SignatureAlgorithm
pkg crypto/x509, type UnknownAuthorityError struct, Cert *Certificate
pkg crypto/x509, type VerifyOptions struct, IsBoring func(*Certificate) bool
pkg database/sql, const LevelDefault = 0
pkg database/sql, const LevelDefault IsolationLevel
pkg database/sql, const LevelLinearizable = 7

View File

@@ -143,7 +143,7 @@ packaged Go distribution.
<p>
To build a bootstrap tool chain from source, use
either the git branch <code>release-branch.go1.4</code> or
<a href="https://storage.googleapis.com/golang/go1.4-bootstrap-20161024.tar.gz">go1.4-bootstrap-20161024.tar.gz</a>,
<a href="https://storage.googleapis.com/golang/go1.4-bootstrap-20170531.tar.gz">go1.4-bootstrap-20170531.tar.gz</a>,
which contains the Go 1.4 source code plus accumulated fixes
to keep the tools running on newer operating systems.
(Go 1.4 was the last distribution in which the tool chain was written in C.)

1
misc/boring/VERSION Normal file
View File

@@ -0,0 +1 @@
4

View File

@@ -1312,9 +1312,32 @@ ok:
// ../../../../runtime/type.go:/structType
// for security, only the exported fields.
case TSTRUCT:
// 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 *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 == localpkg {
path = myimportpath
}
return strings.HasPrefix(path, "crypto/")
}
n := 0
for _, t1 := range t.Fields().Slice() {
if omitFieldForAwfulBoringCryptoKludge(t1) {
continue
}
dtypesym(t1.Type)
n++
}
@@ -1342,6 +1365,9 @@ ok:
ot = dextratype(s, ot, t, dataAdd)
for _, f := range t.Fields().Slice() {
if omitFieldForAwfulBoringCryptoKludge(f) {
continue
}
// ../../../../runtime/type.go:/structField
ot = dnameField(s, ot, pkg, f)
ot = dsymptr(s, ot, dtypesym(f.Type), 0)

View File

@@ -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"))
}

View File

@@ -3497,8 +3497,8 @@ func TestBinaryOnlyPackages(t *testing.T) {
tg.grepStdout("false", "did not see BinaryOnly=false for p4")
}
// Issue 16050.
func TestAlwaysLinkSysoFiles(t *testing.T) {
// Issue 16050 and 21884.
func TestLinkSysoFiles(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
@@ -3517,6 +3517,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.

View File

@@ -173,6 +173,12 @@ func (p *Package) copyBuild(pp *build.Package) {
p.SwigFiles = pp.SwigFiles
p.SwigCXXFiles = pp.SwigCXXFiles
p.SysoFiles = pp.SysoFiles
if 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

View File

@@ -118,6 +118,17 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
r.Add += 4
return true
case 256 + ld.R_X86_64_PC64:
if targ.Type == obj.SDYNIMPORT {
ld.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", targ.Name)
}
if targ.Type == 0 || targ.Type == obj.SXREF {
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
}
r.Type = obj.R_PCREL
r.Add += 8
return true
case 256 + ld.R_X86_64_PLT32:
r.Type = obj.R_PCREL
r.Add += 4

View File

@@ -1836,6 +1836,11 @@ func (ctxt *Link) dodata() {
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
for _, s := range dwarfp[i:] {
// Syms can (incorrectly) appear twice on the list. Ignore repeats.
// See golang.org/issue/21566.
if s.Type == obj.SRODATA {
continue
}
if s.Type != obj.SDWARFINFO {
break
}

View File

@@ -1201,6 +1201,7 @@ func relSize(ctxt *Link, pn string, elftype uint32) uint8 {
return 4
case AMD64 | R_X86_64_64<<24,
AMD64 | R_X86_64_PC64<<24,
PPC64 | R_PPC64_ADDR64<<24,
S390X | R_390_GLOB_DAT<<24,
S390X | R_390_RELATIVE<<24,

View File

@@ -808,6 +808,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",

View File

@@ -6,6 +6,7 @@ package aes
import (
"crypto/cipher"
"crypto/internal/boring"
"strconv"
)
@@ -36,6 +37,9 @@ func NewCipher(key []byte) (cipher.Block, error) {
case 16, 24, 32:
break
}
if boring.Enabled {
return boring.NewAESCipher(key)
}
return newCipher(key)
}

View File

@@ -6,6 +6,7 @@ package aes
import (
"crypto/cipher"
"crypto/internal/boring"
"crypto/internal/cipherhw"
)
@@ -46,6 +47,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")
}
@@ -56,6 +58,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")
}

100
src/crypto/ecdsa/boring.go Normal file
View File

@@ -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),
}
}

View File

@@ -21,11 +21,13 @@ import (
"crypto/aes"
"crypto/cipher"
"crypto/elliptic"
"crypto/internal/boring"
"crypto/sha512"
"encoding/asn1"
"errors"
"io"
"math/big"
"unsafe"
)
// A invertible implements fast inverse mod Curve.Params().N
@@ -47,12 +49,16 @@ const (
type PublicKey struct {
elliptic.Curve
X, Y *big.Int
boring unsafe.Pointer
}
// PrivateKey represents a ECDSA private key.
type PrivateKey struct {
PublicKey
D *big.Int
boring unsafe.Pointer
}
type ecdsaSignature struct {
@@ -69,6 +75,15 @@ func (priv *PrivateKey) Public() crypto.PublicKey {
// hardware module. Common uses should use the Sign function in this package
// directly.
func (priv *PrivateKey) Sign(rand io.Reader, msg []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, msg)
}
boring.UnreachableExceptTests()
r, s, err := Sign(rand, priv, msg)
if err != nil {
return nil, err
@@ -98,6 +113,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
@@ -149,6 +173,15 @@ var errZeroParam = errors.New("zero parameter")
// returns the signature as a pair of integers. The security of the private key
// depends on the entropy of rand.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
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 {
@@ -225,6 +258,15 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
// 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

View File

@@ -22,6 +22,7 @@ timing side-channels:
package hmac
import (
"crypto/internal/boring"
"crypto/subtle"
"hash"
)
@@ -65,6 +66,13 @@ func (h *hmac) Reset() {
// New returns a new HMAC hash using the given hash.Hash type and key.
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()

View File

@@ -5,6 +5,7 @@
package hmac
import (
"bytes"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
@@ -518,6 +519,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) {
@@ -569,6 +595,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)

View File

@@ -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-20170615/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.

View File

@@ -0,0 +1,357 @@
// 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/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 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 int) (cipher.AEAD, error) {
return c.newGCM(nonceSize, false)
}
func (c *aesCipher) NewGCMTLS() (cipher.AEAD, error) {
return c.newGCM(gcmStandardNonceSize, true)
}
func (c *aesCipher) newGCM(nonceSize int, tls bool) (cipher.AEAD, error) {
if nonceSize != gcmStandardNonceSize {
// Fall back to standard library for GCM with non-standard nonce size.
return cipher.NewGCMWithNonceSize(&noGCM{c}, nonceSize)
}
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}, nonceSize)
}
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() != nonceSize {
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")
}
var outLen C.size_t
ok := C._goboringcrypto_EVP_AEAD_CTX_seal(
&g.ctx,
(*C.uint8_t)(unsafe.Pointer(&dst[n])), &outLen, C.size_t(len(plaintext)+gcmTagSize),
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"))
}
if outLen != C.size_t(len(plaintext)+gcmTagSize) {
panic("boringcrypto: internal confusion about GCM tag size")
}
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")
}
var outLen C.size_t
ok := C._goboringcrypto_EVP_AEAD_CTX_open(
&g.ctx,
base(dst[n:]), &outLen, C.size_t(len(ciphertext)-gcmTagSize),
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
}
if outLen != C.size_t(len(ciphertext)-gcmTagSize) {
panic("boringcrypto: internal confusion about GCM tag size")
}
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)
}

View File

@@ -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
}

View File

@@ -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()
}

View File

@@ -0,0 +1 @@
boringssl-24e5886c0edfc409c8083d10f9f1120111efd6f5.tar.xz

View File

@@ -0,0 +1,6 @@
This is not a Go package. The directory must not contain Go sources,
to prevent it from being considered a Go package.
This directory holds the script for building ../goboringcrypto_*.syso.
Run build.sh on an Ubuntu system.
See the comment at the top of build.sh for details.

View File

@@ -0,0 +1,63 @@
#!/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.
# Run on Ubuntu system set up with:
# sudo apt-get install debootstrap
# sudo apt-get install squid-deb-proxy
#
# The script sets up an Ubuntu chroot and then runs the build
# in that chroot, to make sure we know exactly what software
# is being used for the build. To repeat the script reusing the
# chroot installation, run build.sh -quick. This mode is useful
# if all you've modified is goboringcrypto.c and ../goboringcrypto.h
# (or some of the setup scripts in this directory).
# Comment this setting out if not using squid-deb-proxy,
# but it will be much slower to repeat the script.
http_proxy=http://127.0.0.1:8000
chroot=/var/tmp/boringssl
sudo umount -f $chroot/proc
sudo umount -f $chroot/sys
sudo umount -f $chroot/dev/pts
sudo umount -f $chroot/dev
set -e
if [ "$1" != "-quick" ]; then
sudo rm -rf $chroot
sudo http_proxy=$http_proxy debootstrap --variant=minbase zesty $chroot
fi
sudo chown $USER $chroot
sudo chmod u+w $chroot
sudo mount -t proc proc $chroot/proc
sudo mount -t sysfs sys $chroot/sys
sudo mount -o bind /dev $chroot/dev
sudo mount -t devpts devpts $chroot/dev/pts
sudo cp sources.list $chroot/etc/apt/sources.list
cp *chroot.sh $chroot
# Following http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140sp/140sp2964.pdf page 18.
if [ ! -e $chroot/boringssl-24e5886c0edfc409c8083d10f9f1120111efd6f5.tar.xz ]; then
wget -O $chroot/boringssl-24e5886c0edfc409c8083d10f9f1120111efd6f5.tar.xz https://commondatastorage.googleapis.com/chromium-boringssl-docs/fips/boringssl-24e5886c0edfc409c8083d10f9f1120111efd6f5.tar.xz
fi
if [ "$(sha256sum $chroot/boringssl-24e5886c0edfc409c8083d10f9f1120111efd6f5.tar.xz | awk '{print $1}')" != 15a65d676eeae27618e231183a1ce9804fc9c91bcc3abf5f6ca35216c02bf4da ]; then
echo WRONG SHA256SUM
exit 2
fi
rm -rf $chroot/godriver
mkdir $chroot/godriver
cp ../goboringcrypto.h $chroot/godriver
sudo http_proxy=$http_proxy chroot $chroot /root_setup_in_chroot.sh
sudo chroot --userspec=$(id -u):$(id -g) $chroot /build_in_chroot.sh
cp $chroot/godriver/goboringcrypto_linux_amd64.syso ..
sha256sum ../goboringcrypto_linux_amd64.syso
echo DONE

View File

@@ -0,0 +1,198 @@
#!/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.
set -e
echo running build_in_chroot.sh
id
date
export LANG=C
unset LANGUAGE
# Build BoringCrypto libcrypto.a.
# Following http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140sp/140sp2964.pdf page 18.
if ! [ -e ./boringssl/build/tool/bssl ]; then
export PATH=$PATH:/usr/lib/go-1.8/bin:/clangbin
# 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.
mkdir /clangbin
echo '#!/bin/bash
exec clang-4.0 -fPIC "$@"
' >/clangbin/clang
echo '#!/bin/bash
exec clang++-4.0 -fPIC "$@"
' >/clangbin/clang++
chmod +x /clangbin/clang /clangbin/clang++
rm -rf boringssl
tar xJf ../boringssl-*z
cd boringssl
# Verbatim instructions from BoringCrypto build docs.
printf "set(CMAKE_C_COMPILER \"clang\")\nset(CMAKE_CXX_COMPILER \"clang++\")\n" >/toolchain
mkdir build && cd build && cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=/toolchain -DFIPS=1 -DCMAKE_BUILD_TYPE=Release ..
ninja -v
ninja run_tests
cd ../..
fi
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++-4.0 -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-4.0 -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 --redefine-syms=renames.txt goboringcrypto.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

View File

@@ -0,0 +1,13 @@
#!/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.
set -e
id
date
echo http_proxy=$http_proxy
export LANG=C
unset LANGUAGE
apt-get update
apt-get install --no-install-recommends -y cmake clang-4.0 golang-1.8-go ninja-build xz-utils

View File

@@ -0,0 +1,10 @@
deb http://archive.ubuntu.com/ubuntu/ zesty main restricted
deb http://archive.ubuntu.com/ubuntu/ zesty-updates main restricted
deb http://archive.ubuntu.com/ubuntu/ zesty universe
deb http://archive.ubuntu.com/ubuntu/ zesty-updates universe
deb http://archive.ubuntu.com/ubuntu/ zesty multiverse
deb http://archive.ubuntu.com/ubuntu/ zesty-updates multiverse
deb http://archive.ubuntu.com/ubuntu/ zesty-backports main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu zesty-security main restricted
deb http://security.ubuntu.com/ubuntu zesty-security universe
deb http://security.ubuntu.com/ubuntu zesty-security multiverse

View File

@@ -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

View File

@@ -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
}

View File

@@ -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).

View File

@@ -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
}

View File

@@ -0,0 +1,236 @@
// 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);
// #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[24]; } 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[120]; } 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, 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);

View File

@@ -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...)
}

View File

@@ -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")
}

View File

@@ -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)

View File

@@ -0,0 +1,329 @@
// 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 *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}
// 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, (*PublicKeyRSA).finalize)
return k, nil
}
func (k *PublicKeyRSA) finalize() {
C._goboringcrypto_RSA_free(k.key)
}
type PrivateKeyRSA struct {
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}
// 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, (*PrivateKeyRSA).finalize)
return k, nil
}
func (k *PrivateKeyRSA) finalize() {
C._goboringcrypto_RSA_free(k.key)
}
func setupRSA(key *C.GO_RSA,
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 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.malloc(C.size_t(len(label))))
if clabel == nil {
return nil, nil, fail("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(gokey interface{}, key *C.GO_RSA,
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(key, 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")
}
runtime.KeepAlive(gokey) // keep key from being freed before now
return out[:outLen], nil
}
func DecryptRSAOAEP(h hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) {
return cryptRSA(priv, priv.key, 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, pub.key, C.GO_RSA_PKCS1_OAEP_PADDING, h, label, 0, 0, encryptInit, encrypt, msg)
}
func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) {
return cryptRSA(priv, priv.key, C.GO_RSA_PKCS1_PADDING, nil, nil, 0, 0, decryptInit, decrypt, ciphertext)
}
func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) ([]byte, error) {
return cryptRSA(pub, pub.key, C.GO_RSA_PKCS1_PADDING, nil, nil, 0, 0, encryptInit, encrypt, msg)
}
func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) {
return cryptRSA(priv, priv.key, C.GO_RSA_NO_PADDING, nil, nil, 0, 0, decryptInit, decrypt, ciphertext)
}
func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) ([]byte, error) {
return cryptRSA(pub, pub.key, 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
}
out := make([]byte, C._goboringcrypto_RSA_size(priv.key))
var outLen C.size_t
if C._goboringcrypto_RSA_sign_pss_mgf1(priv.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")
}
runtime.KeepAlive(priv)
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 C._goboringcrypto_RSA_verify_pss_mgf1(pub.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")
}
runtime.KeepAlive(pub)
return nil
}
func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) {
out := make([]byte, C._goboringcrypto_RSA_size(priv.key))
if h == 0 {
// No hashing.
var outLen C.size_t
if C._goboringcrypto_RSA_sign_raw(priv.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")
}
runtime.KeepAlive(priv)
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 outLen C.uint
if C._goboringcrypto_RSA_sign(nid, base(hashed), C.uint(len(hashed)), base(out), &outLen, priv.key) == 0 {
return nil, fail("RSA_sign")
}
runtime.KeepAlive(priv)
return out[:outLen], nil
}
func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error {
size := int(C._goboringcrypto_RSA_size(pub.key))
if len(sig) < size {
// BoringCrypto requires sig to be same size as RSA key, so pad with leading zeros.
zsig := make([]byte, size)
copy(zsig[len(zsig)-len(sig):], sig)
sig = zsig
}
if h == 0 {
var outLen C.size_t
out := make([]byte, size)
if C._goboringcrypto_RSA_verify_raw(pub.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")
}
runtime.KeepAlive(pub)
return nil
}
md := cryptoHashToMD(h)
if md == nil {
return errors.New("crypto/rsa: unsupported hash function")
}
nid := C._goboringcrypto_EVP_MD_type(md)
if C._goboringcrypto_RSA_verify(nid, base(hashed), C.size_t(len(hashed)), base(sig), C.size_t(len(sig)), pub.key) == 0 {
return fail("RSA_verify")
}
runtime.KeepAlive(pub)
return nil
}

View File

@@ -0,0 +1,177 @@
// 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 (
"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
}
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[:]
}
// 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[:]
}
// 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[:]
}

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -6,11 +6,19 @@
package cipherhw
import "crypto/internal/boring"
// defined in asm_amd64.s
func hasAESNI() bool
// AESGCMSupport returns true if the Go standard library supports AES-GCM in
// hardware.
func AESGCMSupport() bool {
// If BoringCrypto is enabled, we report having
// AES-GCM support, so that crypto/tls will
// prioritize AES-GCM usage.
if boring.Enabled {
return true
}
return hasAESNI()
}

View File

@@ -13,6 +13,7 @@ import (
"bufio"
"crypto/aes"
"crypto/cipher"
"crypto/internal/boring"
"io"
"os"
"runtime"
@@ -26,6 +27,10 @@ const urandomDevice = "/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 {
@@ -45,6 +50,7 @@ type devReader struct {
var altGetRandom func([]byte) (ok bool)
func (r *devReader) Read(b []byte) (n int, err error) {
boring.Unreachable()
if altGetRandom != nil && r.name == urandomDevice && altGetRandom(b) {
return len(b), nil
}
@@ -108,6 +114,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)

163
src/crypto/rsa/boring.go Normal file
View File

@@ -0,0 +1,163 @@
// 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"
"crypto/rand"
"io"
"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
}
// boringFakeRandomBlind consumes from random to mimic the
// blinding operation done in the standard Go func decrypt.
// When we are using BoringCrypto, we always let it handle decrypt
// regardless of random source, because the blind doesn't affect
// the visible output of decryption, but if the random source is not
// true randomness then the caller might still observe the side effect
// of consuming from the source. We consume from the source
// to give the same side effect. This should only happen during tests
// (verified by the UnreachableExceptTests call below).
//
// We go to the trouble of doing this so that we can verify that
// func decrypt (standard RSA decryption) is dropped from
// BoringCrypto-linked binaries entirely; otherwise we'd have to
// keep it in the binary just in case a call happened with a
// non-standard randomness source.
func boringFakeRandomBlind(random io.Reader, priv *PrivateKey) {
if random == nil || random == boring.RandReader {
return
}
boring.UnreachableExceptTests()
// Copied from func decrypt.
for {
r, err := rand.Int(random, priv.N)
if err != nil {
return
}
if r.Cmp(bigZero) == 0 {
r = bigOne
}
_, ok := modInverse(r, priv.N)
if ok {
break
}
}
}

View File

@@ -0,0 +1,332 @@
// 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 (
"bytes"
"crypto"
"crypto/rand"
"crypto/sha1"
"crypto/sha256"
"encoding/asn1"
"encoding/hex"
"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) {
// This changed behavior and broke golang.org/x/crypto/openpgp.
// Go accepts signatures without leading 0 padding, while BoringCrypto does not.
// So the Go wrappers must adapt.
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: %v", err)
}
err = VerifyPKCS1v15(key, crypto.SHA1, hash, sig)
if err != nil {
t.Errorf("sha1: %v", err)
}
}
// The goal for BoringCrypto is to be indistinguishable from standard Go crypto.
// Test that when routines are passed a not-actually-random reader, they
// consume and potentially expose the expected bits from that reader.
// This is awful but it makes sure that golden tests based on deterministic
// "randomness" sources are unchanged by BoringCrypto.
//
// For decryption and signing, r is only used for blinding,
// so we can and do still use BoringCrypto with its own true
// randomness source, but we must be careful to consume
// from r as if we'd used it for blinding.
type testRandReader struct {
t *testing.T
offset int64
seq [8]byte
data []byte
buf [32]byte
}
func (r *testRandReader) Read(b []byte) (int, error) {
if len(r.data) == 0 && len(b) > 0 {
for i := range r.seq {
r.seq[i]++
if r.seq[i] != 0 {
break
}
}
r.buf = sha256.Sum256(r.seq[:])
r.data = r.buf[:]
}
n := copy(b, r.data)
r.data = r.data[n:]
r.offset += int64(n)
return n, nil
}
func (r *testRandReader) checkOffset(offset int64) {
if r.offset != offset {
r.t.Fatalf("r.offset = %d, expected %d", r.offset, offset)
}
}
func testRand(t *testing.T) *testRandReader {
return &testRandReader{t: t}
}
var testKeyCache struct {
once sync.Once
k *PrivateKey
}
func testKey(t *testing.T) *PrivateKey {
testKeyCache.once.Do(func() {
// Note: Key must be 2048 bits in order to trigger
// BoringCrypto code paths.
k, err := GenerateKey(testRand(t), 2048)
if err != nil {
t.Fatal(err)
}
testKeyCache.k = k
})
return testKeyCache.k
}
func bytesFromHex(t *testing.T, x string) []byte {
b, err := hex.DecodeString(x)
if err != nil {
t.Fatal(err)
}
return b
}
func TestBoringRandGenerateKey(t *testing.T) {
r := testRand(t)
k, err := GenerateKey(r, 2048) // 2048 is smallest size BoringCrypto might kick in for
if err != nil {
t.Fatal(err)
}
n := bigFromHex("b2e9c4c8b1c0f03ba6994fe1e715a3e598f0571f4676da420615b7b997d431ea7535ceb98e6b52172fe0d2fccfc5f696d1b34144f7d19d85633fcbf56daff805a66457b360b1b0f40ec18fb83f4c9b86f1b5fe26b209cdfff26911a95047df797210969693226423915c9be53ff1c06f86fe2d228273ef25970b90a3c70979f9d68458d5dd38f6700436f7cd5939c04be3e1f2ff52272513171540a685c9e8c8e20694e529cc3e0cc13d2fb91ac499d44b920a03e42be89a15e7ca73c29f2e2a1a8a7d9be57516ccb95e878db6ce6096e386a793cccc19eba15a37cc0f1234b7a25ee7c87569bc74c7ef3d6ad8d84a5ddb1e8901ae593f945523fe5e0ed451a5")
if k.N.Cmp(n) != 0 {
t.Fatalf("GenerateKey: wrong N\nhave %x\nwant %x", k.N, n)
}
r.checkOffset(35200)
// 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 TestBoringRandGenerateMultiPrimeKey(t *testing.T) {
r := testRand(t)
k, err := GenerateMultiPrimeKey(r, 2, 2048)
if err != nil {
t.Fatal(err)
}
n := bigFromHex("b2e9c4c8b1c0f03ba6994fe1e715a3e598f0571f4676da420615b7b997d431ea7535ceb98e6b52172fe0d2fccfc5f696d1b34144f7d19d85633fcbf56daff805a66457b360b1b0f40ec18fb83f4c9b86f1b5fe26b209cdfff26911a95047df797210969693226423915c9be53ff1c06f86fe2d228273ef25970b90a3c70979f9d68458d5dd38f6700436f7cd5939c04be3e1f2ff52272513171540a685c9e8c8e20694e529cc3e0cc13d2fb91ac499d44b920a03e42be89a15e7ca73c29f2e2a1a8a7d9be57516ccb95e878db6ce6096e386a793cccc19eba15a37cc0f1234b7a25ee7c87569bc74c7ef3d6ad8d84a5ddb1e8901ae593f945523fe5e0ed451a5")
if k.N.Cmp(n) != 0 {
t.Fatalf("GenerateKey: wrong N\nhave %x\nwant %x", k.N, n)
}
r.checkOffset(35200)
}
func TestBoringRandEncryptPKCS1v15(t *testing.T) {
r := testRand(t)
k := testKey(t)
enc, err := EncryptPKCS1v15(r, &k.PublicKey, []byte("hello world"))
if err != nil {
t.Fatal(err)
}
want := bytesFromHex(t, "a8c8c0d248e669942a140c1184e1112afbf794b7427d9ac966bd2dbb4c05a2fee76f311f7feec743b8a8715e34bf741b0d0c4226559daf4de258ff712178e3f25fecb7d3eee90251e8ae4b4b7b907cd2763948cc9da34ce83c69934b523830545a536c1ba4d3740f4687e877acee9c768bcd8e88d472ba5d905493121f4830d95dcea36ef0f1223ffb0a9008eddfc53aca36877328924a2c631dce4b67e745564301fe51ab2c768b39e525bda1e1a08e029b58c53a0b92285f734592d2deebda957bcfd29c697aee263fce5c5023c7d3495b6a9114a8ac691aa661721cf45973b68678bb1e15d6605b9040951163d5b6df0d7f0b20dcefa251a7a8947a090f4b")
if !bytes.Equal(enc, want) {
t.Fatalf("EncryptPKCS1v15: wrong enc\nhave %x\nwant %x", enc, want)
}
r.checkOffset(242)
}
func TestBoringRandDecryptPKCS1v15(t *testing.T) {
r := testRand(t)
k := testKey(t)
enc := bytesFromHex(t, "a8c8c0d248e669942a140c1184e1112afbf794b7427d9ac966bd2dbb4c05a2fee76f311f7feec743b8a8715e34bf741b0d0c4226559daf4de258ff712178e3f25fecb7d3eee90251e8ae4b4b7b907cd2763948cc9da34ce83c69934b523830545a536c1ba4d3740f4687e877acee9c768bcd8e88d472ba5d905493121f4830d95dcea36ef0f1223ffb0a9008eddfc53aca36877328924a2c631dce4b67e745564301fe51ab2c768b39e525bda1e1a08e029b58c53a0b92285f734592d2deebda957bcfd29c697aee263fce5c5023c7d3495b6a9114a8ac691aa661721cf45973b68678bb1e15d6605b9040951163d5b6df0d7f0b20dcefa251a7a8947a090f4b")
dec, err := DecryptPKCS1v15(r, k, enc)
if err != nil {
t.Fatal(err)
}
want := []byte("hello world")
if !bytes.Equal(dec, want) {
t.Fatalf("DecryptPKCS1v15: wrong dec\nhave %x\nwant %x", dec, want)
}
r.checkOffset(256)
}
func TestBoringRandDecryptPKCS1v15SessionKey(t *testing.T) {
r := testRand(t)
k := testKey(t)
enc := bytesFromHex(t, "a8c8c0d248e669942a140c1184e1112afbf794b7427d9ac966bd2dbb4c05a2fee76f311f7feec743b8a8715e34bf741b0d0c4226559daf4de258ff712178e3f25fecb7d3eee90251e8ae4b4b7b907cd2763948cc9da34ce83c69934b523830545a536c1ba4d3740f4687e877acee9c768bcd8e88d472ba5d905493121f4830d95dcea36ef0f1223ffb0a9008eddfc53aca36877328924a2c631dce4b67e745564301fe51ab2c768b39e525bda1e1a08e029b58c53a0b92285f734592d2deebda957bcfd29c697aee263fce5c5023c7d3495b6a9114a8ac691aa661721cf45973b68678bb1e15d6605b9040951163d5b6df0d7f0b20dcefa251a7a8947a090f4b")
dec := make([]byte, 11)
err := DecryptPKCS1v15SessionKey(r, k, enc, dec)
if err != nil {
t.Fatal(err)
}
want := []byte("hello world")
if !bytes.Equal(dec, want) {
t.Fatalf("DecryptPKCS1v15SessionKey: wrong dec\nhave %x\nwant %x", dec, want)
}
r.checkOffset(256)
}
func TestBoringRandSignPKCS1v15(t *testing.T) {
r := testRand(t)
k := testKey(t)
sum := sha1.Sum([]byte("hello"))
sig, err := SignPKCS1v15(r, k, crypto.SHA1, sum[:])
if err != nil {
t.Fatal(err)
}
want := bytesFromHex(t, "4a8da3c0c41af2b8a93d011d4e11f4da9b2d52641c6c3d78d863987e857295adcedfae0e0d3ec00352bd134dc3fbb93b23a1fbe3718775762d78165bbbd37c6ef8e07bfa44e16ed2f1b05ebc04ba7bd60162d8689edb8709349e06bc281d34c2a3ee75d3454bfd95053cbb27c10515fb9132290a6ecc858e0c003201a9e100aac7f66af967364a1176e4ed9ef672d41481c59580f98bb82f205f712153fd5e3035a811da9d6e56e50609d1d604857f6d8e958bb84f354cfa28e0b8bcbb1261f929382d431454f07cbf60c18ff1243b11c6b552f3a0aa7e936f45cded40688ee53b1b630f944139f4f51baae49cd039b57b2b82f58f5589335137f4b09bd315f5")
if !bytes.Equal(sig, want) {
t.Fatalf("SignPKCS1v15(hash=SHA1): wrong sig\nhave %x\nwant %x", sig, want)
}
sig, err = SignPKCS1v15(r, k, 0, sum[:])
if err != nil {
t.Fatal(err)
}
want = bytesFromHex(t, "5d3d34495ffade926adab2de0545aaf1f22a03def949b69e1c91d34a2f0c7f2d682af46034151a1b67aa22cb9c1a8cc24c1358fce9ac6a2141879bbe107371b14faa97b12494260d9602ed1355f22ab3495b0bb7c137bc6801c1113fc2bdc00d4c250bbd8fa17e4ff86f71544b30a78e9d62c0b949afd1159760282c2700ec8be24cd884efd585ec55b45506d90e66cc3c5911baaea961e6c4e8018c4b4feb04afdd71880e3d8eff120288e53289a1bfb9fe7a3b9aca1d4549f133063647bfd4c6f4c0f4038f1bbcb4d112aa601f1b15402595076adfdbefb1bb64d3193bafb0305145bb536cd949a03ebe0470c6a155369f784afab2e25e9d5c03d8e13dcf1a")
if !bytes.Equal(sig, want) {
t.Fatalf("SignPKCS1v15(hash=0): wrong sig\nhave %x\nwant %x", sig, want)
}
r.checkOffset(768)
}
func TestBoringRandSignPSS(t *testing.T) {
r := testRand(t)
k := testKey(t)
sum := sha1.Sum([]byte("hello"))
sig, err := SignPSS(r, k, crypto.SHA1, sum[:], nil)
if err != nil {
t.Fatal(err)
}
want := bytesFromHex(t, "a0de84c9654c2e78e33c899090f8dc0590046fda4ee29d133340800596401ae0df61bf8aa5689df3f873ad13cf55df5209c3a8c6450918b74c2017f87c2d588809740622c7752e3153a26d04bd3e9d9f6daa676e8e5e65a8a11d4fbd271d4693ab6a303652328dc1c923b484fa179fd6d9e8b523da74f3a307531c0dd75f243a041f7df22414dfdb83b3a241fe73e7af0f95cb6b60831bdd46dc05618e5cb3653476eb7d5405fa5ca98dad8f787ca86179055f305daa87eb424671878a93965e47d3002e2774be311d696b42e5691eddb2f788cd35246b408eb5d045c891ba1d57ce4c6fc935ceec90f7999406252f6266957cce4e7f12cf0ec94af358aeefa7")
if !bytes.Equal(sig, want) {
t.Fatalf("SignPSS: wrong sig\nhave %x\nwant %x", sig, want)
}
r.checkOffset(490)
}
func TestBoringRandEncryptOAEP(t *testing.T) {
r := testRand(t)
k := testKey(t)
enc, err := EncryptOAEP(sha256.New(), r, &k.PublicKey, []byte("hello"), []byte("label"))
if err != nil {
t.Fatal(err)
}
want := bytesFromHex(t, "55dc7b590a511c2d249232ecbb70040e8e0ec03206caae5ec0a401a0ad8013209ef546870f93d0946b9845ace092d456d092403f76f12ee65c2b8759731a25589d8a7e857407d09cfbe36ae36fc4daeb514ac597b1de2f7dc8450ab78a9e420c9b5dbbae3e402c8f378bd35505a47d556b705ab8985707a22e3583c172ef5730f05fd0845880d67c1ddd3c1525aa4c2c4e162bd6435a485609f6bd76c8ff73a7b5d043e4724458594703245fabdb479ef2786c757b35932a645399f2703647785b59b971970e6bccef3e6cd6fae39f9f135203eb104f0db20cf48e461cb7d824889c0d5d6a47cd0bf213c2f7acb3ddbd3effefebb4f60458ffc8b6ff1e4cc447")
if !bytes.Equal(enc, want) {
t.Fatalf("EncryptOAEP: wrong enc\nhave %x\nwant %x", enc, want)
}
r.checkOffset(32)
}
func TestBoringRandDecryptOAEP(t *testing.T) {
r := testRand(t)
k := testKey(t)
enc := bytesFromHex(t, "55dc7b590a511c2d249232ecbb70040e8e0ec03206caae5ec0a401a0ad8013209ef546870f93d0946b9845ace092d456d092403f76f12ee65c2b8759731a25589d8a7e857407d09cfbe36ae36fc4daeb514ac597b1de2f7dc8450ab78a9e420c9b5dbbae3e402c8f378bd35505a47d556b705ab8985707a22e3583c172ef5730f05fd0845880d67c1ddd3c1525aa4c2c4e162bd6435a485609f6bd76c8ff73a7b5d043e4724458594703245fabdb479ef2786c757b35932a645399f2703647785b59b971970e6bccef3e6cd6fae39f9f135203eb104f0db20cf48e461cb7d824889c0d5d6a47cd0bf213c2f7acb3ddbd3effefebb4f60458ffc8b6ff1e4cc447")
dec, err := DecryptOAEP(sha256.New(), r, k, enc, []byte("label"))
if err != nil {
t.Fatal(err)
}
want := []byte("hello")
if !bytes.Equal(dec, want) {
t.Fatalf("DecryptOAEP: wrong dec\nhave %x\nwant %x", dec, want)
}
r.checkOffset(256)
}
func TestBoringFinalizers(t *testing.T) {
if runtime.GOOS == "nacl" {
// Times out on nacl (without BoringCrypto)
// but not clear why - probably consuming rand.Reader too quickly
// and being throttled. Also doesn't really matter.
t.Skip("skipping on nacl")
}
k := testKey(t)
// 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()
}
}

View File

@@ -6,6 +6,7 @@ package rsa
import (
"crypto"
"crypto/internal/boring"
"crypto/subtle"
"errors"
"io"
@@ -34,7 +35,7 @@ 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) {
func EncryptPKCS1v15(random io.Reader, pub *PublicKey, msg []byte) ([]byte, error) {
if err := checkPub(pub); err != nil {
return nil, err
}
@@ -43,20 +44,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)
copyWithLeftPad(em, c.Bytes())
return em, nil
}
@@ -73,6 +91,20 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byt
if err := checkPub(&priv.PublicKey); err != nil {
return nil, err
}
if boring.Enabled {
boringFakeRandomBlind(rand, priv)
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
@@ -140,13 +172,27 @@ 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 {
boringFakeRandomBlind(rand, priv)
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 = leftPad(m.Bytes(), k)
}
em = leftPad(m.Bytes(), k)
firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0)
secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2)
@@ -225,7 +271,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
@@ -237,6 +283,15 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
return nil, ErrMessageTooLong
}
if boring.Enabled {
boringFakeRandomBlind(random, priv)
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
@@ -247,7 +302,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
}
@@ -262,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

View File

@@ -64,7 +64,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) {

View File

@@ -11,6 +11,7 @@ package rsa
import (
"bytes"
"crypto"
"crypto/internal/boring"
"errors"
"hash"
"io"
@@ -197,6 +198,22 @@ func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed,
if err != nil {
return
}
if boring.Enabled {
boringFakeRandomBlind(rand, priv)
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 {
@@ -259,6 +276,14 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte,
hash = opts.Hash
}
if boring.Enabled && rand == boring.RandReader {
bkey, err := boringPrivateKey(priv)
if err != nil {
return nil, err
}
return boring.SignRSAPSS(bkey, hash, hashed, saltLength)
}
salt := make([]byte, saltLength)
if _, err := io.ReadFull(rand, salt); err != nil {
return nil, err
@@ -277,6 +302,16 @@ func VerifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, opts
// verifyPSS verifies a PSS signature with the given salt length.
func verifyPSS(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte, saltLen int) error {
if boring.Enabled {
bkey, err := boringPublicKey(pub)
if err != nil {
return err
}
if err := boring.VerifyRSAPSS(bkey, hash, hashed, sig, saltLen); err != nil {
return ErrVerification
}
return nil
}
nBits := pub.N.BitLen()
if len(sig) != (nBits+7)/8 {
return ErrVerification

View 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)

View File

@@ -24,6 +24,7 @@ package rsa
import (
"crypto"
"crypto/internal/boring"
"crypto/rand"
"crypto/subtle"
"errors"
@@ -31,6 +32,7 @@ import (
"io"
"math"
"math/big"
"unsafe"
)
var bigZero = big.NewInt(0)
@@ -40,6 +42,8 @@ var bigOne = big.NewInt(1)
type PublicKey struct {
N *big.Int // modulus
E int // public exponent
boring unsafe.Pointer
}
// OAEPOptions is an interface for passing options to OAEP decryption using the
@@ -85,6 +89,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.
@@ -210,6 +216,32 @@ func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) {
// [1] US patent 4405829 (1972, expired)
// [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf
func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey, error) {
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.Cmp(big.NewInt(e64)) != 0 || 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
@@ -344,6 +376,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
@@ -376,6 +409,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()
@@ -396,10 +438,24 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l
mgf1XOR(db, hash, seed)
mgf1XOR(seed, hash, db)
m := new(big.Int)
m.SetBytes(em)
c := encrypt(new(big.Int), pub, m)
out := c.Bytes()
var out []byte
if boring.Enabled {
var bkey *boring.PublicKeyRSA
bkey, err = boringPublicKey(pub)
if err != nil {
return nil, err
}
c, err := boring.EncryptRSANoPadding(bkey, em)
if err != nil {
return nil, err
}
out = c
} else {
m := new(big.Int)
m.SetBytes(em)
c := encrypt(new(big.Int), pub, m)
out = c.Bytes()
}
if len(out) < k {
// If the output is too small, we need to left-pad with zeros.
@@ -477,6 +533,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
@@ -592,6 +651,18 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext
return nil, ErrDecryption
}
if boring.Enabled {
boringFakeRandomBlind(random, priv)
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)

View File

@@ -7,26 +7,29 @@ package rsa
import (
"bytes"
"crypto"
"crypto/internal/boring"
"crypto/rand"
"crypto/sha1"
"crypto/sha256"
"fmt"
"math/big"
"testing"
)
func TestKeyGeneration(t *testing.T) {
size := 1024
if testing.Short() {
size = 128
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
}
}
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)
}
testKeyBasics(t, priv)
}
func Test3PrimeKeyGeneration(t *testing.T) {
@@ -110,6 +113,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 +180,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 +206,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 +252,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 +277,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 +302,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

22
src/crypto/sha1/boring.go Normal file
View File

@@ -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() }

View File

@@ -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() {}

View File

@@ -49,6 +49,9 @@ func (d *digest) Reset() {
// New returns a new hash.Hash computing the SHA1 checksum.
func New() hash.Hash {
if boringEnabled {
return boringNewSHA1()
}
d := new(digest)
d.Reset()
return d
@@ -59,6 +62,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 {
@@ -82,6 +86,7 @@ func (d *digest) Write(p []byte) (nn int, err error) {
}
func (d0 *digest) Sum(in []byte) []byte {
boringUnreachable()
// Make a copy of d0 so that caller can keep writing and summing.
d := *d0
hash := d.checkSum()
@@ -191,6 +196,13 @@ func (d *digest) constSum() [Size]byte {
// Sum returns the SHA1 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)

View File

@@ -7,6 +7,7 @@
package sha1
import (
"crypto/internal/boring"
"crypto/rand"
"fmt"
"io"
@@ -73,6 +74,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:])
@@ -103,6 +107,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)

View File

@@ -8,6 +8,7 @@ package sha256
import (
"crypto"
"crypto/internal/boring"
"hash"
)
@@ -80,6 +81,9 @@ func (d *digest) Reset() {
// New returns a new hash.Hash computing the SHA256 checksum.
func New() hash.Hash {
if boring.Enabled {
return boring.NewSHA256()
}
d := new(digest)
d.Reset()
return d
@@ -87,6 +91,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()
@@ -103,6 +110,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 {
@@ -126,6 +134,7 @@ func (d *digest) Write(p []byte) (nn int, err error) {
}
func (d0 *digest) Sum(in []byte) []byte {
boring.Unreachable()
// Make a copy of d0 so that caller can keep writing and summing.
d := *d0
hash := d.checkSum()
@@ -175,6 +184,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)
@@ -183,6 +199,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()

View File

@@ -7,6 +7,7 @@
package sha256
import (
"crypto/internal/boring"
"crypto/rand"
"fmt"
"io"
@@ -153,6 +154,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)

View File

@@ -8,6 +8,7 @@ package sha512
import (
"crypto"
"crypto/internal/boring"
"hash"
)
@@ -126,6 +127,9 @@ func (d *digest) Reset() {
// 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
@@ -147,6 +151,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
@@ -168,6 +175,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 {
@@ -191,6 +201,9 @@ func (d *digest) Write(p []byte) (nn int, err error) {
}
func (d0 *digest) Sum(in []byte) []byte {
if d0.function != crypto.SHA512_224 && d0.function != crypto.SHA512_256 {
boring.Unreachable()
}
// Make a copy of d0 so that caller can keep writing and summing.
d := new(digest)
*d = *d0
@@ -251,6 +264,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)
@@ -259,6 +279,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)

View File

@@ -7,6 +7,7 @@
package sha512
import (
"crypto/internal/boring"
"crypto/rand"
"encoding/hex"
"hash"
@@ -307,6 +308,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)

121
src/crypto/tls/boring.go Normal file
View File

@@ -0,0 +1,121 @@
// 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
}
// default FIPSCipherSuites is the FIPS-allowed cipher suites,
// in preference order (most preferable first).
var defaultFIPSCipherSuites = []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 defaultFIPSCipherSuites
}
var list []uint16
for _, id := range c.CipherSuites {
for _, allowed := range defaultFIPSCipherSuites {
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
}
// supportedSignatureAlgorithms returns the supported signature algorithms.
// It knows that the FIPS-allowed ones are all at the beginning of
// defaultSupportedSignatureAlgorithms.
func supportedSignatureAlgorithms() []signatureAndHash {
all := defaultSupportedSignatureAlgorithms
if !needFIPS() {
return all
}
i := 0
for i < len(all) && all[i].hash != hashSHA1 {
i++
}
return all[:i]
}
var testingOnlyForceClientHelloSignatureAndHashes []signatureAndHash

View File

@@ -0,0 +1,579 @@
// 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"
"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,
cipherSuites: allCipherSuites(),
compressionMethods: []uint8{compressionNone},
}
testClientHelloFailure(t, serverConfig, clientHello, msg)
})
}
test("VersionSSL30", VersionSSL30, "")
test("VersionTLS10", VersionTLS10, "")
test("VersionTLS11", VersionTLS11, "")
test("VersionTLS12", VersionTLS12, "")
fipstls.Force()
defer fipstls.Abandon()
test("VersionSSL30", VersionSSL30, "unsupported, maximum protocol version")
test("VersionTLS10", VersionTLS10, "unsupported, maximum protocol version")
test("VersionTLS11", VersionTLS11, "unsupported, maximum protocol version")
test("VersionTLS12", 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&suiteECDSA == suiteECDSA
}
}
panic(fmt.Sprintf("unknown cipher suite %#x", id))
}
func isBoringSignatureAndHash(sigHash signatureAndHash) bool {
switch sigHash.signature {
default:
return false
case signatureRSA,
signatureECDSA:
// ok
}
switch sigHash.hash {
default:
return false
case hashSHA256,
hashSHA384:
// 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,
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,
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 := realNetPipe(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) {
serverConfig := testConfig.Clone()
serverConfig.Certificates = make([]Certificate, 1)
defer func() {
testingOnlyForceClientHelloSignatureAndHashes = nil
}()
for _, sigHash := range defaultSupportedSignatureAlgorithms {
testingOnlyForceClientHelloSignatureAndHashes = []signatureAndHash{sigHash}
t.Run(fmt.Sprintf("%v", sigHash), func(t *testing.T) {
if sigHash.signature == signatureRSA {
serverConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
serverConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey
} else {
serverConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
serverConfig.Certificates = make([]Certificate, 1)
serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
}
serverConfig.BuildNameToCertificate()
clientErr, _ := boringHandshake(t, testConfig, serverConfig)
if clientErr != nil {
t.Fatalf("expected handshake with %v to succeed; err=%v", sigHash, clientErr)
}
// 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 isBoringSignatureAndHash(sigHash) {
if clientErr != nil {
t.Fatalf("expected handshake with %v to succeed; err=%v", sigHash, clientErr)
}
} else {
if clientErr == nil {
t.Fatalf("expected handshake with %v 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.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 hello.vers != VersionTLS12 {
t.Errorf("client vers=%#x, want %#x (TLS 1.2)", hello.vers, VersionTLS12)
}
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.signatureAndHashes {
if !isBoringSignatureAndHash(sigHash) {
t.Errorf("client offered disallowed signature-and-hash %v", sigHash)
}
}
}
func TestBoringCertAlgs(t *testing.T) {
// NaCl and arm 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" {
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}
}
func boringPool(t *testing.T, list ...*boringCertificate) *x509.CertPool {
pool := x509.NewCertPool()
for _, c := range list {
cert, err := x509.ParseCertificate(c.der)
if err != nil {
t.Fatal(err)
}
pool.AddCert(cert)
}
return pool
}
func boringList(t *testing.T, list ...*boringCertificate) [][]byte {
var all [][]byte
for _, c := range list {
all = append(all, c.der)
}
return all
}
// realNetPipe is like net.Pipe but returns an actual network socket pair,
// which has buffering that avoids various deadlocks if both sides
// try to speak at the same time.
func realNetPipe(t *testing.T) (net.Conn, net.Conn) {
l := newLocalListener(t)
defer l.Close()
c, err := net.Dial("tcp", l.Addr().String())
if err != nil {
t.Fatal(err)
}
s, err := l.Accept()
if err != nil {
c.Close()
t.Fatal(err)
}
return c, s
}

View File

@@ -9,6 +9,7 @@ import (
"crypto/cipher"
"crypto/des"
"crypto/hmac"
"crypto/internal/boring"
"crypto/rc4"
"crypto/sha1"
"crypto/sha256"
@@ -135,7 +136,11 @@ func macSHA1(version uint16, key []byte) macFunction {
copy(mac.key, key)
return mac
}
return tls10MAC{hmac.New(newConstantTimeHash(sha1.New), key)}
h := sha1.New
if !boring.Enabled {
h = newConstantTimeHash(h)
}
return tls10MAC{hmac.New(h, key)}
}
// macSHA256 returns a SHA-256 based MAC. These are only supported in TLS 1.2
@@ -215,12 +220,22 @@ func (f *xorNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byt
return result, err
}
type gcmtls interface {
NewGCMTLS() (cipher.AEAD, error)
}
func aeadAESGCM(key, fixedNonce []byte) cipher.AEAD {
aes, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
aead, err := cipher.NewGCM(aes)
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)
}
@@ -298,6 +313,11 @@ 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 {
if boring.Enabled {
// The BoringCrypto SHA1 does not have a constant-time
// checksum function, so don't try to use it.
return h
}
return func() hash.Hash {
return &cthWrapper{h().(constantTimeHash)}
}

View File

@@ -145,10 +145,10 @@ type signatureAndHash struct {
hash, signature uint8
}
// 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.
var supportedSignatureAlgorithms = []signatureAndHash{
var defaultSupportedSignatureAlgorithms = []signatureAndHash{
{hashSHA256, signatureRSA},
{hashSHA256, signatureECDSA},
{hashSHA384, signatureRSA},
@@ -670,6 +670,9 @@ func (c *Config) time() time.Time {
}
func (c *Config) cipherSuites() []uint16 {
if needFIPS() {
return fipsCipherSuites(c)
}
s := c.CipherSuites
if s == nil {
s = defaultCipherSuites()
@@ -678,6 +681,9 @@ func (c *Config) cipherSuites() []uint16 {
}
func (c *Config) minVersion() uint16 {
if needFIPS() {
return fipsMinVersion(c)
}
if c == nil || c.MinVersion == 0 {
return minVersion
}
@@ -685,6 +691,9 @@ func (c *Config) minVersion() uint16 {
}
func (c *Config) maxVersion() uint16 {
if needFIPS() {
return fipsMaxVersion(c)
}
if c == nil || c.MaxVersion == 0 {
return maxVersion
}
@@ -694,6 +703,9 @@ func (c *Config) maxVersion() 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
}

View File

@@ -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()
}

View File

@@ -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")
}
}

View File

@@ -99,7 +99,11 @@ NextCipherSuite:
}
if hello.vers >= VersionTLS12 {
hello.signatureAndHashes = supportedSignatureAlgorithms
hello.signatureAndHashes = supportedSignatureAlgorithms()
}
if testingOnlyForceClientHelloSignatureAndHashes != nil {
hello.signatureAndHashes = testingOnlyForceClientHelloSignatureAndHashes
}
var session *ClientSessionState
@@ -285,6 +289,8 @@ func (hs *clientHandshakeState) doFullHandshake() error {
if !c.config.InsecureSkipVerify {
opts := x509.VerifyOptions{
IsBoring: isBoringCertificate,
Roots: c.config.RootCAs,
CurrentTime: c.config.time(),
DNSName: c.config.ServerName,

View File

@@ -137,7 +137,7 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
}
}
if rand.Intn(10) > 5 {
m.signatureAndHashes = supportedSignatureAlgorithms
m.signatureAndHashes = supportedSignatureAlgorithms()
}
m.alpnProtocols = make([]string, rand.Intn(5))
for i := range m.alpnProtocols {

View File

@@ -422,7 +422,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
if c.vers >= VersionTLS12 {
certReq.hasSignatureAndHash = true
certReq.signatureAndHashes = supportedSignatureAlgorithms
certReq.signatureAndHashes = supportedSignatureAlgorithms()
}
// An empty list of certificateAuthorities signals to
@@ -526,7 +526,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
var signatureAndHash signatureAndHash
if certVerify.hasSignatureAndHash {
signatureAndHash = certVerify.signatureAndHash
if !isSupportedSignatureAndHash(signatureAndHash, supportedSignatureAlgorithms) {
if !isSupportedSignatureAndHash(signatureAndHash, supportedSignatureAlgorithms()) {
return errors.New("tls: unsupported hash function for client certificate")
}
} else {
@@ -722,6 +722,8 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
opts := x509.VerifyOptions{
IsBoring: isBoringCertificate,
Roots: c.config.ClientCAs,
CurrentTime: c.config.time(),
Intermediates: x509.NewCertPool(),

View File

@@ -114,7 +114,7 @@ func md5SHA1Hash(slices [][]byte) []byte {
// only used for >= TLS 1.2 and precisely identifies the hash function to use.
func hashForServerKeyExchange(sigAndHash signatureAndHash, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) {
if version >= VersionTLS12 {
if !isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) {
if !isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms()) {
return nil, crypto.Hash(0), errors.New("tls: unsupported hash function used by peer")
}
hashFunc, err := lookupTLSHash(sigAndHash.hash)
@@ -149,7 +149,7 @@ func pickTLS12HashForSignature(sigType uint8, clientList []signatureAndHash) (ui
if sigAndHash.signature != sigType {
continue
}
if isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) {
if isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms()) {
return sigAndHash.hash, nil
}
}

View File

@@ -319,7 +319,7 @@ func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []signatureA
}
for _, v := range serverList {
if v.signature == sigType && isSupportedSignatureAndHash(v, supportedSignatureAlgorithms) {
if v.signature == sigType && isSupportedSignatureAndHash(v, supportedSignatureAlgorithms()) {
return v, nil
}
}

View File

@@ -156,6 +156,11 @@ type VerifyOptions struct {
// constraint down the chain which mirrors Windows CryptoAPI behavior,
// but not the spec. To accept any key usage, include ExtKeyUsageAny.
KeyUsages []ExtKeyUsage
// 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
}
const (
@@ -248,6 +253,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
}

View File

@@ -110,10 +110,17 @@ var pkgDeps = map[string][]string{
"reflect": {"L2"},
"sort": {"reflect"},
"crypto/internal/boring": {"L2", "C", "crypto", "crypto/cipher", "crypto/internal/boring/sig", "crypto/subtle", "encoding/asn1", "hash", "math/big"},
"crypto/internal/boring/fipstls": {"sync/atomic"},
"crypto/internal/cipherhw": {"crypto/internal/boring"},
"crypto/tls/fipsonly": {"crypto/internal/boring/fipstls", "crypto/internal/boring/sig"},
"L3": {
"L2",
"crypto",
"crypto/cipher",
"crypto/internal/boring",
"crypto/internal/boring/fipstls",
"crypto/internal/cipherhw",
"crypto/subtle",
"encoding/base32",

View File

@@ -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

View File

@@ -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")
}
}

View File

@@ -6,9 +6,9 @@ package race_test
import (
"bytes"
"crypto/sha1"
"errors"
"fmt"
"hash/crc32"
"io"
"os"
"runtime"
@@ -1904,7 +1904,7 @@ func TestRaceIssue5567(t *testing.T) {
err = nil
}
}()
h := sha1.New()
h := crc32.New(crc32.MakeTable(0x12345678))
for b := range in {
h.Write(b)
}

View File

@@ -57,3 +57,15 @@ func syscall_Getpagesize() int { return int(physPageSize) }
//go:linkname os_runtime_args os.runtime_args
func os_runtime_args() []string { return append([]string{}, argslice...) }
//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() }