mirror of
https://github.com/golang/go.git
synced 2026-02-04 18:05:03 +03:00
Compare commits
36 Commits
dev.typeal
...
dev.boring
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42cb4dcdb5 | ||
|
|
93c869ec16 | ||
|
|
6201a632a2 | ||
|
|
af56294e54 | ||
|
|
6e3cb838fc | ||
|
|
39d24b6b6d | ||
|
|
52f2e65060 | ||
|
|
0c01487988 | ||
|
|
deabc8dc44 | ||
|
|
86b7b52729 | ||
|
|
0bc83d7aaa | ||
|
|
f2a2dbe422 | ||
|
|
eb32dbc4f6 | ||
|
|
11e083e44b | ||
|
|
043302c56d | ||
|
|
20cf471364 | ||
|
|
f2ab41b02d | ||
|
|
2f048bcaf9 | ||
|
|
a6fa239225 | ||
|
|
d5efcb1ead | ||
|
|
4aff713ddb | ||
|
|
08c54565dc | ||
|
|
1da9aa90bc | ||
|
|
775b2384e7 | ||
|
|
fb11572dfd | ||
|
|
ddd775ff44 | ||
|
|
cb5b47443f | ||
|
|
33ebf73c45 | ||
|
|
065bb6eb30 | ||
|
|
367461427e | ||
|
|
497ad3015b | ||
|
|
73f9e27276 | ||
|
|
4ab59be66e | ||
|
|
4f6c6be21e | ||
|
|
e6ba6f7890 | ||
|
|
f3e6216450 |
18
README.boringcrypto.md
Normal file
18
README.boringcrypto.md
Normal 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.
|
||||
@@ -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
|
||||
|
||||
@@ -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
1
misc/boring/VERSION
Normal file
@@ -0,0 +1 @@
|
||||
4
|
||||
@@ -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)
|
||||
|
||||
20
src/cmd/go/go_boring_test.go
Normal file
20
src/cmd/go/go_boring_test.go
Normal 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"))
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
100
src/crypto/ecdsa/boring.go
Normal 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),
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
200
src/crypto/internal/boring/LICENSE
Normal file
200
src/crypto/internal/boring/LICENSE
Normal 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.
|
||||
357
src/crypto/internal/boring/aes.go
Normal file
357
src/crypto/internal/boring/aes.go
Normal 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)
|
||||
}
|
||||
83
src/crypto/internal/boring/boring.go
Normal file
83
src/crypto/internal/boring/boring.go
Normal 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
|
||||
}
|
||||
34
src/crypto/internal/boring/boring_test.go
Normal file
34
src/crypto/internal/boring/boring_test.go
Normal 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()
|
||||
}
|
||||
1
src/crypto/internal/boring/build/.gitignore
vendored
Normal file
1
src/crypto/internal/boring/build/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
boringssl-24e5886c0edfc409c8083d10f9f1120111efd6f5.tar.xz
|
||||
6
src/crypto/internal/boring/build/README
Normal file
6
src/crypto/internal/boring/build/README
Normal 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.
|
||||
63
src/crypto/internal/boring/build/build.sh
Executable file
63
src/crypto/internal/boring/build/build.sh
Executable 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
|
||||
198
src/crypto/internal/boring/build/build_in_chroot.sh
Executable file
198
src/crypto/internal/boring/build/build_in_chroot.sh
Executable 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
|
||||
13
src/crypto/internal/boring/build/root_setup_in_chroot.sh
Executable file
13
src/crypto/internal/boring/build/root_setup_in_chroot.sh
Executable 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
|
||||
10
src/crypto/internal/boring/build/sources.list
Normal file
10
src/crypto/internal/boring/build/sources.list
Normal 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
|
||||
14
src/crypto/internal/boring/doc.go
Normal file
14
src/crypto/internal/boring/doc.go
Normal 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
|
||||
201
src/crypto/internal/boring/ecdsa.go
Normal file
201
src/crypto/internal/boring/ecdsa.go
Normal 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
|
||||
}
|
||||
10
src/crypto/internal/boring/fipstls/dummy.s
Normal file
10
src/crypto/internal/boring/fipstls/dummy.s
Normal 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).
|
||||
49
src/crypto/internal/boring/fipstls/tls.go
Normal file
49
src/crypto/internal/boring/fipstls/tls.go
Normal 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
|
||||
}
|
||||
236
src/crypto/internal/boring/goboringcrypto.h
Normal file
236
src/crypto/internal/boring/goboringcrypto.h
Normal 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);
|
||||
BIN
src/crypto/internal/boring/goboringcrypto_linux_amd64.syso
Normal file
BIN
src/crypto/internal/boring/goboringcrypto_linux_amd64.syso
Normal file
Binary file not shown.
156
src/crypto/internal/boring/hmac.go
Normal file
156
src/crypto/internal/boring/hmac.go
Normal 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...)
|
||||
}
|
||||
109
src/crypto/internal/boring/notboring.go
Normal file
109
src/crypto/internal/boring/notboring.go
Normal 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")
|
||||
}
|
||||
27
src/crypto/internal/boring/rand.go
Normal file
27
src/crypto/internal/boring/rand.go
Normal 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)
|
||||
329
src/crypto/internal/boring/rsa.go
Normal file
329
src/crypto/internal/boring/rsa.go
Normal 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
|
||||
}
|
||||
177
src/crypto/internal/boring/sha.go
Normal file
177
src/crypto/internal/boring/sha.go
Normal 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[:]
|
||||
}
|
||||
17
src/crypto/internal/boring/sig/sig.go
Normal file
17
src/crypto/internal/boring/sig/sig.go
Normal 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()
|
||||
54
src/crypto/internal/boring/sig/sig_amd64.s
Normal file
54
src/crypto/internal/boring/sig/sig_amd64.s
Normal 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
|
||||
19
src/crypto/internal/boring/sig/sig_other.s
Normal file
19
src/crypto/internal/boring/sig/sig_other.s
Normal 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
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
163
src/crypto/rsa/boring.go
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
332
src/crypto/rsa/boring_test.go
Normal file
332
src/crypto/rsa/boring_test.go
Normal 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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
22
src/crypto/sha1/boring.go
Normal 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() }
|
||||
17
src/crypto/sha1/notboring.go
Normal file
17
src/crypto/sha1/notboring.go
Normal 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() {}
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
121
src/crypto/tls/boring.go
Normal 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
|
||||
579
src/crypto/tls/boring_test.go
Normal file
579
src/crypto/tls/boring_test.go
Normal 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
|
||||
}
|
||||
@@ -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)}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
27
src/crypto/tls/fipsonly/fipsonly.go
Normal file
27
src/crypto/tls/fipsonly/fipsonly.go
Normal 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()
|
||||
}
|
||||
16
src/crypto/tls/fipsonly/fipsonly_test.go
Normal file
16
src/crypto/tls/fipsonly/fipsonly_test.go
Normal 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")
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
8
src/internal/boringtest/boring.go
Normal file
8
src/internal/boringtest/boring.go
Normal 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
|
||||
47
src/internal/boringtest/boring_test.go
Normal file
47
src/internal/boringtest/boring_test.go
Normal 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")
|
||||
}
|
||||
}
|
||||
4
src/runtime/race/testdata/mop_test.go
vendored
4
src/runtime/race/testdata/mop_test.go
vendored
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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() }
|
||||
|
||||
Reference in New Issue
Block a user