Commit 6736ef96 by Ian Lance Taylor

libgo: Merge to master revision 19184.

The next revision, 19185, renames several runtime files, and
will be handled in a separate change.

From-SVN: r211328
parent 38a13841
......@@ -34,17 +34,17 @@ func main() {
for i := 0; i < N; i++ {
go func() {
defer wg.Done()
v := new(int)
v := new(string)
f := func() {
if *v != 0 {
if *v != "" {
panic("oops")
}
}
if *v != 0 {
if *v != "" {
// let the compiler think f escapes
sink = f
}
runtime.SetFinalizer(v, func(p *int) {
runtime.SetFinalizer(v, func(p *string) {
atomic.AddInt32(&count, -1)
})
defer f()
......
......@@ -30,7 +30,7 @@ func G() {
func main() {
nf := testing.AllocsPerRun(100, F)
ng := testing.AllocsPerRun(100, G)
if int(nf) != 1 {
if int(nf) > 1 {
fmt.Printf("AllocsPerRun(100, F) = %v, want 1\n", nf)
os.Exit(1)
}
......
......@@ -26,11 +26,11 @@ func F() {
func main() {
nf := testing.AllocsPerRun(100, F)
ng := testing.AllocsPerRun(100, G)
if int(nf) != 1 {
if int(nf) > 1 {
fmt.Printf("AllocsPerRun(100, F) = %v, want 1\n", nf)
os.Exit(1)
}
if int(ng) != 1 {
if int(ng) > 1 {
fmt.Printf("AllocsPerRun(100, G) = %v, want 1\n", ng)
os.Exit(1)
}
......
00cce3a34d7e
50c8fc924389
The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources.
......@@ -199,7 +199,8 @@ toolexeclibgodebug_DATA = \
debug/goobj.gox \
debug/gosym.gox \
debug/macho.gox \
debug/pe.gox
debug/pe.gox \
debug/plan9obj.gox
toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
......@@ -500,7 +501,6 @@ runtime_files = \
runtime/mcache.c \
runtime/mcentral.c \
$(runtime_mem_file) \
runtime/mfinal.c \
runtime/mfixalloc.c \
runtime/mgc0.c \
runtime/mheap.c \
......@@ -1144,7 +1144,8 @@ go_crypto_hmac_files = \
go/crypto/hmac/hmac.go
go_crypto_md5_files = \
go/crypto/md5/md5.go \
go/crypto/md5/md5block.go
go/crypto/md5/md5block.go \
go/crypto/md5/md5block_generic.go
go_crypto_rand_files = \
go/crypto/rand/rand.go \
go/crypto/rand/rand_unix.go \
......@@ -1158,7 +1159,8 @@ go_crypto_rsa_files = \
go/crypto/rsa/rsa.go
go_crypto_sha1_files = \
go/crypto/sha1/sha1.go \
go/crypto/sha1/sha1block.go
go/crypto/sha1/sha1block.go \
go/crypto/sha1/sha1block_generic.go
go_crypto_sha256_files = \
go/crypto/sha256/sha256.go \
go/crypto/sha256/sha256block.go
......@@ -1208,6 +1210,7 @@ go_debug_dwarf_files = \
go/debug/dwarf/line.go \
go/debug/dwarf/open.go \
go/debug/dwarf/type.go \
go/debug/dwarf/typeunit.go \
go/debug/dwarf/unit.go
go_debug_elf_files = \
go/debug/elf/elf.go \
......@@ -1218,11 +1221,15 @@ go_debug_gosym_files = \
go/debug/gosym/pclntab.go \
go/debug/gosym/symtab.go
go_debug_macho_files = \
go/debug/macho/fat.go \
go/debug/macho/file.go \
go/debug/macho/macho.go
go_debug_pe_files = \
go/debug/pe/file.go \
go/debug/pe/pe.go
go_debug_plan9obj_files = \
go/debug/plan9obj/file.go \
go/debug/plan9obj/plan9obj.go
go_encoding_ascii85_files = \
go/encoding/ascii85/ascii85.go
......@@ -1452,6 +1459,7 @@ go_net_http_pprof_files = \
go_net_http_httputil_files = \
go/net/http/httputil/chunked.go \
go/net/http/httputil/dump.go \
go/net/http/httputil/httputil.go \
go/net/http/httputil/persist.go \
go/net/http/httputil/reverseproxy.go
......@@ -1876,6 +1884,7 @@ libgo_go_objs = \
debug/gosym.lo \
debug/macho.lo \
debug/pe.lo \
debug/plan9obj.lo \
encoding/ascii85.lo \
encoding/asn1.lo \
encoding/base32.lo \
......@@ -2636,6 +2645,15 @@ debug/pe/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: debug/pe/check
@go_include@ debug/plan9obj.lo.dep
debug/plan9obj.lo.dep: $(go_debug_plan9obj_files)
$(BUILDDEPS)
debug/plan9obj.lo: $(go_debug_plan9obj_files)
$(BUILDPACKAGE)
debug/plan9obj/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: debug/plan9obj/check
@go_include@ encoding/asn1.lo.dep
encoding/asn1.lo.dep: $(go_encoding_asn1_files)
$(BUILDDEPS)
......@@ -3435,6 +3453,8 @@ debug/macho.gox: debug/macho.lo
$(BUILDGOX)
debug/pe.gox: debug/pe.lo
$(BUILDGOX)
debug/plan9obj.gox: debug/plan9obj.lo
$(BUILDGOX)
encoding/ascii85.gox: encoding/ascii85.lo
$(BUILDGOX)
......@@ -3659,6 +3679,7 @@ TEST_PACKAGES = \
debug/elf/check \
debug/macho/check \
debug/pe/check \
debug/plan9obj/check \
encoding/ascii85/check \
encoding/asn1/check \
encoding/base32/check \
......
......@@ -148,21 +148,21 @@ am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \
crypto/sha512.lo crypto/subtle.lo crypto/tls.lo crypto/x509.lo \
crypto/x509/pkix.lo database/sql.lo database/sql/driver.lo \
debug/dwarf.lo debug/elf.lo debug/goobj.lo debug/gosym.lo \
debug/macho.lo debug/pe.lo encoding/ascii85.lo \
encoding/asn1.lo encoding/base32.lo encoding/base64.lo \
encoding/binary.lo encoding/csv.lo encoding/gob.lo \
encoding/hex.lo encoding/json.lo encoding/pem.lo \
encoding/xml.lo exp/proxy.lo exp/terminal.lo html/template.lo \
go/ast.lo go/build.lo go/doc.lo go/format.lo go/parser.lo \
go/printer.lo go/scanner.lo go/token.lo hash/adler32.lo \
hash/crc32.lo hash/crc64.lo hash/fnv.lo net/http/cgi.lo \
net/http/cookiejar.lo net/http/fcgi.lo net/http/httptest.lo \
net/http/httputil.lo net/http/pprof.lo image/color.lo \
image/color/palette.lo image/draw.lo image/gif.lo \
image/jpeg.lo image/png.lo index/suffixarray.lo io/ioutil.lo \
log/syslog.lo log/syslog/syslog_c.lo math/big.lo math/cmplx.lo \
math/rand.lo mime/multipart.lo net/http.lo net/mail.lo \
net/rpc.lo net/smtp.lo net/textproto.lo net/url.lo \
debug/macho.lo debug/pe.lo debug/plan9obj.lo \
encoding/ascii85.lo encoding/asn1.lo encoding/base32.lo \
encoding/base64.lo encoding/binary.lo encoding/csv.lo \
encoding/gob.lo encoding/hex.lo encoding/json.lo \
encoding/pem.lo encoding/xml.lo exp/proxy.lo exp/terminal.lo \
html/template.lo go/ast.lo go/build.lo go/doc.lo go/format.lo \
go/parser.lo go/printer.lo go/scanner.lo go/token.lo \
hash/adler32.lo hash/crc32.lo hash/crc64.lo hash/fnv.lo \
net/http/cgi.lo net/http/cookiejar.lo net/http/fcgi.lo \
net/http/httptest.lo net/http/httputil.lo net/http/pprof.lo \
image/color.lo image/color/palette.lo image/draw.lo \
image/gif.lo image/jpeg.lo image/png.lo index/suffixarray.lo \
io/ioutil.lo log/syslog.lo log/syslog/syslog_c.lo math/big.lo \
math/cmplx.lo math/rand.lo mime/multipart.lo net/http.lo \
net/mail.lo net/rpc.lo net/smtp.lo net/textproto.lo net/url.lo \
old/regexp.lo old/template.lo os/exec.lo $(am__DEPENDENCIES_1) \
os/signal.lo os/user.lo path/filepath.lo regexp/syntax.lo \
net/rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
......@@ -213,8 +213,8 @@ am__objects_6 = go-append.lo go-assert.lo go-assert-interface.lo \
go-unsafe-new.lo go-unsafe-newarray.lo go-unsafe-pointer.lo \
go-unwind.lo go-varargs.lo chan.lo cpuprof.lo env_posix.lo \
lfstack.lo $(am__objects_1) mcache.lo mcentral.lo \
$(am__objects_2) mfinal.lo mfixalloc.lo mgc0.lo mheap.lo \
msize.lo $(am__objects_3) panic.lo parfor.lo print.lo proc.lo \
$(am__objects_2) mfixalloc.lo mgc0.lo mheap.lo msize.lo \
$(am__objects_3) panic.lo parfor.lo print.lo proc.lo \
runtime.lo signal_unix.lo thread.lo yield.lo $(am__objects_4) \
iface.lo malloc.lo map.lo mprof.lo netpoll.lo reflect.lo \
runtime1.lo sema.lo sigqueue.lo string.lo time.lo \
......@@ -591,7 +591,8 @@ toolexeclibgodebug_DATA = \
debug/goobj.gox \
debug/gosym.gox \
debug/macho.gox \
debug/pe.gox
debug/pe.gox \
debug/plan9obj.gox
toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
toolexeclibgoencoding_DATA = \
......@@ -829,7 +830,6 @@ runtime_files = \
runtime/mcache.c \
runtime/mcentral.c \
$(runtime_mem_file) \
runtime/mfinal.c \
runtime/mfixalloc.c \
runtime/mgc0.c \
runtime/mheap.c \
......@@ -1302,7 +1302,8 @@ go_crypto_hmac_files = \
go_crypto_md5_files = \
go/crypto/md5/md5.go \
go/crypto/md5/md5block.go
go/crypto/md5/md5block.go \
go/crypto/md5/md5block_generic.go
go_crypto_rand_files = \
go/crypto/rand/rand.go \
......@@ -1320,7 +1321,8 @@ go_crypto_rsa_files = \
go_crypto_sha1_files = \
go/crypto/sha1/sha1.go \
go/crypto/sha1/sha1block.go
go/crypto/sha1/sha1block.go \
go/crypto/sha1/sha1block_generic.go
go_crypto_sha256_files = \
go/crypto/sha256/sha256.go \
......@@ -1375,6 +1377,7 @@ go_debug_dwarf_files = \
go/debug/dwarf/line.go \
go/debug/dwarf/open.go \
go/debug/dwarf/type.go \
go/debug/dwarf/typeunit.go \
go/debug/dwarf/unit.go
go_debug_elf_files = \
......@@ -1389,6 +1392,7 @@ go_debug_gosym_files = \
go/debug/gosym/symtab.go
go_debug_macho_files = \
go/debug/macho/fat.go \
go/debug/macho/file.go \
go/debug/macho/macho.go
......@@ -1396,6 +1400,10 @@ go_debug_pe_files = \
go/debug/pe/file.go \
go/debug/pe/pe.go
go_debug_plan9obj_files = \
go/debug/plan9obj/file.go \
go/debug/plan9obj/plan9obj.go
go_encoding_ascii85_files = \
go/encoding/ascii85/ascii85.go
......@@ -1656,6 +1664,7 @@ go_net_http_pprof_files = \
go_net_http_httputil_files = \
go/net/http/httputil/chunked.go \
go/net/http/httputil/dump.go \
go/net/http/httputil/httputil.go \
go/net/http/httputil/persist.go \
go/net/http/httputil/reverseproxy.go
......@@ -1947,6 +1956,7 @@ libgo_go_objs = \
debug/gosym.lo \
debug/macho.lo \
debug/pe.lo \
debug/plan9obj.lo \
encoding/ascii85.lo \
encoding/asn1.lo \
encoding/base32.lo \
......@@ -2187,6 +2197,7 @@ TEST_PACKAGES = \
debug/elf/check \
debug/macho/check \
debug/pe/check \
debug/plan9obj/check \
encoding/ascii85/check \
encoding/asn1/check \
encoding/base32/check \
......@@ -2472,7 +2483,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mcentral.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem_posix_memalign.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mfinal.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mfixalloc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mgc0.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mheap.Plo@am__quote@
......@@ -3081,13 +3091,6 @@ mem.lo: runtime/mem.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mem.lo `test -f 'runtime/mem.c' || echo '$(srcdir)/'`runtime/mem.c
mfinal.lo: runtime/mfinal.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mfinal.lo -MD -MP -MF $(DEPDIR)/mfinal.Tpo -c -o mfinal.lo `test -f 'runtime/mfinal.c' || echo '$(srcdir)/'`runtime/mfinal.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mfinal.Tpo $(DEPDIR)/mfinal.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/mfinal.c' object='mfinal.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mfinal.lo `test -f 'runtime/mfinal.c' || echo '$(srcdir)/'`runtime/mfinal.c
mfixalloc.lo: runtime/mfixalloc.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mfixalloc.lo -MD -MP -MF $(DEPDIR)/mfixalloc.Tpo -c -o mfixalloc.lo `test -f 'runtime/mfixalloc.c' || echo '$(srcdir)/'`runtime/mfixalloc.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mfixalloc.Tpo $(DEPDIR)/mfixalloc.Plo
......@@ -5014,6 +5017,15 @@ debug/pe/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: debug/pe/check
@go_include@ debug/plan9obj.lo.dep
debug/plan9obj.lo.dep: $(go_debug_plan9obj_files)
$(BUILDDEPS)
debug/plan9obj.lo: $(go_debug_plan9obj_files)
$(BUILDPACKAGE)
debug/plan9obj/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: debug/plan9obj/check
@go_include@ encoding/asn1.lo.dep
encoding/asn1.lo.dep: $(go_encoding_asn1_files)
$(BUILDDEPS)
......@@ -5805,6 +5817,8 @@ debug/macho.gox: debug/macho.lo
$(BUILDGOX)
debug/pe.gox: debug/pe.lo
$(BUILDGOX)
debug/plan9obj.gox: debug/plan9obj.lo
$(BUILDGOX)
encoding/ascii85.gox: encoding/ascii85.lo
$(BUILDGOX)
......
......@@ -57,6 +57,7 @@ type Header struct {
Devminor int64 // minor number of character or block device
AccessTime time.Time // access time
ChangeTime time.Time // status change time
Xattrs map[string]string
}
// File name constants from the tar spec.
......@@ -189,6 +190,7 @@ const (
paxSize = "size"
paxUid = "uid"
paxUname = "uname"
paxXattr = "SCHILY.xattr."
paxNone = ""
)
......
......@@ -139,8 +139,14 @@ func mergePAX(hdr *Header, headers map[string]string) error {
return err
}
hdr.Size = int64(size)
default:
if strings.HasPrefix(k, paxXattr) {
if hdr.Xattrs == nil {
hdr.Xattrs = make(map[string]string)
}
hdr.Xattrs[k[len(paxXattr):]] = v
}
}
}
return nil
}
......
......@@ -161,6 +161,46 @@ var untarTests = []*untarTest{
},
},
},
{
file: "testdata/xattrs.tar",
headers: []*Header{
{
Name: "small.txt",
Mode: 0644,
Uid: 1000,
Gid: 10,
Size: 5,
ModTime: time.Unix(1386065770, 448252320),
Typeflag: '0',
Uname: "alex",
Gname: "wheel",
AccessTime: time.Unix(1389782991, 419875220),
ChangeTime: time.Unix(1389782956, 794414986),
Xattrs: map[string]string{
"user.key": "value",
"user.key2": "value2",
// Interestingly, selinux encodes the terminating null inside the xattr
"security.selinux": "unconfined_u:object_r:default_t:s0\x00",
},
},
{
Name: "small2.txt",
Mode: 0644,
Uid: 1000,
Gid: 10,
Size: 11,
ModTime: time.Unix(1386065770, 449252304),
Typeflag: '0',
Uname: "alex",
Gname: "wheel",
AccessTime: time.Unix(1389782991, 419875220),
ChangeTime: time.Unix(1386065770, 449252304),
Xattrs: map[string]string{
"security.selinux": "unconfined_u:object_r:default_t:s0\x00",
},
},
},
},
}
func TestReader(t *testing.T) {
......@@ -180,7 +220,7 @@ testLoop:
f.Close()
continue testLoop
}
if *hdr != *header {
if !reflect.DeepEqual(*hdr, *header) {
t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
i, j, *hdr, *header)
}
......@@ -253,7 +293,7 @@ func TestIncrementalRead(t *testing.T) {
}
// check the header
if *hdr != *headers[nread] {
if !reflect.DeepEqual(*hdr, *headers[nread]) {
t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
*hdr, headers[nread])
}
......@@ -321,7 +361,7 @@ func TestParsePAXHeader(t *testing.T) {
{"mtime", "mtime=1350244992.023960108", "30 mtime=1350244992.023960108\n"}}
for _, test := range paxTests {
key, expected, raw := test[0], test[1], test[2]
reader := bytes.NewBuffer([]byte(raw))
reader := bytes.NewReader([]byte(raw))
headers, err := parsePAX(reader)
if err != nil {
t.Errorf("Couldn't parse correctly formatted headers: %v", err)
......@@ -337,7 +377,7 @@ func TestParsePAXHeader(t *testing.T) {
t.Error("Buffer wasn't consumed")
}
}
badHeader := bytes.NewBuffer([]byte("3 somelongkey="))
badHeader := bytes.NewReader([]byte("3 somelongkey="))
if _, err := parsePAX(badHeader); err != ErrHeader {
t.Fatal("Unexpected success when parsing bad header")
}
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux openbsd
// +build linux dragonfly openbsd solaris
package tar
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux darwin freebsd openbsd netbsd
// +build linux darwin dragonfly freebsd openbsd netbsd solaris
package tar
......
......@@ -236,6 +236,12 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
return tw.err
}
if allowPax {
for k, v := range hdr.Xattrs {
paxHeaders[paxXattr+k] = v
}
}
if len(paxHeaders) > 0 {
if !allowPax {
return errInvalidHeader
......
......@@ -10,6 +10,7 @@ import (
"io"
"io/ioutil"
"os"
"reflect"
"strings"
"testing"
"testing/iotest"
......@@ -338,6 +339,45 @@ func TestPaxNonAscii(t *testing.T) {
}
}
func TestPaxXattrs(t *testing.T) {
xattrs := map[string]string{
"user.key": "value",
}
// Create an archive with an xattr
fileinfo, err := os.Stat("testdata/small.txt")
if err != nil {
t.Fatal(err)
}
hdr, err := FileInfoHeader(fileinfo, "")
if err != nil {
t.Fatalf("os.Stat: %v", err)
}
contents := "Kilts"
hdr.Xattrs = xattrs
var buf bytes.Buffer
writer := NewWriter(&buf)
if err := writer.WriteHeader(hdr); err != nil {
t.Fatal(err)
}
if _, err = writer.Write([]byte(contents)); err != nil {
t.Fatal(err)
}
if err := writer.Close(); err != nil {
t.Fatal(err)
}
// Test that we can get the xattrs back out of the archive.
reader := NewReader(&buf)
hdr, err = reader.Next()
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(hdr.Xattrs, xattrs) {
t.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
hdr.Xattrs, xattrs)
}
}
func TestPAXHeader(t *testing.T) {
medName := strings.Repeat("CD", 50)
longName := strings.Repeat("AB", 100)
......
......@@ -235,6 +235,18 @@ var tests = []ZipTest{
},
},
},
// Another zip64 file with different Extras fields. (golang.org/issue/7069)
{
Name: "zip64-2.zip",
File: []ZipTestFile{
{
Name: "README",
Content: []byte("This small file is in ZIP64 format.\n"),
Mtime: "08-10-12 14:33:32",
Mode: 0644,
},
},
},
}
var crossPlatform = []ZipTestFile{
......@@ -343,19 +355,13 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
testFileMode(t, zt.Name, f, ft.Mode)
size0 := f.UncompressedSize
var b bytes.Buffer
r, err := f.Open()
if err != nil {
t.Error(err)
t.Errorf("%s: %v", zt.Name, err)
return
}
if size1 := f.UncompressedSize; size0 != size1 {
t.Errorf("file %q changed f.UncompressedSize from %d to %d", f.Name, size0, size1)
}
_, err = io.Copy(&b, r)
if err != ft.ContentErr {
t.Errorf("%s: copying contents: %v (want %v)", zt.Name, err, ft.ContentErr)
......@@ -365,6 +371,14 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
}
r.Close()
size := uint64(f.UncompressedSize)
if size == uint32max {
size = f.UncompressedSize64
}
if g := uint64(b.Len()); g != size {
t.Errorf("%v: read %v bytes but f.UncompressedSize == %v", f.Name, g, size)
}
var c []byte
if ft.Content != nil {
c = ft.Content
......
......@@ -6,6 +6,7 @@ package zip
import (
"compress/flate"
"errors"
"io"
"io/ioutil"
"sync"
......@@ -21,12 +22,50 @@ type Compressor func(io.Writer) (io.WriteCloser, error)
// when they're finished reading.
type Decompressor func(io.Reader) io.ReadCloser
var flateWriterPool sync.Pool
func newFlateWriter(w io.Writer) io.WriteCloser {
fw, ok := flateWriterPool.Get().(*flate.Writer)
if ok {
fw.Reset(w)
} else {
fw, _ = flate.NewWriter(w, 5)
}
return &pooledFlateWriter{fw: fw}
}
type pooledFlateWriter struct {
mu sync.Mutex // guards Close and Write
fw *flate.Writer
}
func (w *pooledFlateWriter) Write(p []byte) (n int, err error) {
w.mu.Lock()
defer w.mu.Unlock()
if w.fw == nil {
return 0, errors.New("Write after Close")
}
return w.fw.Write(p)
}
func (w *pooledFlateWriter) Close() error {
w.mu.Lock()
defer w.mu.Unlock()
var err error
if w.fw != nil {
err = w.fw.Close()
flateWriterPool.Put(w.fw)
w.fw = nil
}
return err
}
var (
mu sync.RWMutex // guards compressor and decompressor maps
compressors = map[uint16]Compressor{
Store: func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil },
Deflate: func(w io.Writer) (io.WriteCloser, error) { return flate.NewWriter(w, 5) },
Deflate: func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil },
}
decompressors = map[uint16]Decompressor{
......
......@@ -125,3 +125,21 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
t.Errorf("File contents %q, want %q", b, wt.Data)
}
}
func BenchmarkCompressedZipGarbage(b *testing.B) {
b.ReportAllocs()
var buf bytes.Buffer
bigBuf := bytes.Repeat([]byte("a"), 1<<20)
for i := 0; i < b.N; i++ {
buf.Reset()
zw := NewWriter(&buf)
for j := 0; j < 3; j++ {
w, _ := zw.CreateHeader(&FileHeader{
Name: "foo",
Method: Deflate,
})
w.Write(bigBuf)
}
zw.Close()
}
}
......@@ -65,12 +65,12 @@ func readBytes(buf *Reader) string {
func TestReaderSimple(t *testing.T) {
data := "hello world"
b := NewReader(bytes.NewBufferString(data))
b := NewReader(strings.NewReader(data))
if s := readBytes(b); s != "hello world" {
t.Errorf("simple hello world test failed: got %q", s)
}
b = NewReader(newRot13Reader(bytes.NewBufferString(data)))
b = NewReader(newRot13Reader(strings.NewReader(data)))
if s := readBytes(b); s != "uryyb jbeyq" {
t.Errorf("rot13 hello world test failed: got %q", s)
}
......@@ -161,7 +161,7 @@ func TestReader(t *testing.T) {
readmaker := readMakers[i]
bufreader := bufreaders[j]
bufsize := bufsizes[k]
read := readmaker.fn(bytes.NewBufferString(text))
read := readmaker.fn(strings.NewReader(text))
buf := NewReaderSize(read, bufsize)
s := bufreader.fn(buf)
if s != text {
......@@ -479,7 +479,7 @@ func TestWriteErrors(t *testing.T) {
func TestNewReaderSizeIdempotent(t *testing.T) {
const BufSize = 1000
b := NewReaderSize(bytes.NewBufferString("hello world"), BufSize)
b := NewReaderSize(strings.NewReader("hello world"), BufSize)
// Does it recognize itself?
b1 := NewReaderSize(b, BufSize)
if b1 != b {
......@@ -677,7 +677,7 @@ func TestLineTooLong(t *testing.T) {
for i := 0; i < minReadBufferSize*5/2; i++ {
data = append(data, '0'+byte(i%10))
}
buf := bytes.NewBuffer(data)
buf := bytes.NewReader(data)
l := NewReaderSize(buf, minReadBufferSize)
line, isPrefix, err := l.ReadLine()
if !isPrefix || !bytes.Equal(line, data[:minReadBufferSize]) || err != nil {
......@@ -702,7 +702,7 @@ func TestLineTooLong(t *testing.T) {
func TestReadAfterLines(t *testing.T) {
line1 := "this is line1"
restData := "this is line2\nthis is line 3\n"
inbuf := bytes.NewBuffer([]byte(line1 + "\n" + restData))
inbuf := bytes.NewReader([]byte(line1 + "\n" + restData))
outbuf := new(bytes.Buffer)
maxLineLength := len(line1) + len(restData)/2
l := NewReaderSize(inbuf, maxLineLength)
......@@ -728,7 +728,7 @@ func TestReadEmptyBuffer(t *testing.T) {
}
func TestLinesAfterRead(t *testing.T) {
l := NewReaderSize(bytes.NewBuffer([]byte("foo")), minReadBufferSize)
l := NewReaderSize(bytes.NewReader([]byte("foo")), minReadBufferSize)
_, err := ioutil.ReadAll(l)
if err != nil {
t.Error(err)
......@@ -818,7 +818,7 @@ func createTestInput(n int) []byte {
func TestReaderWriteTo(t *testing.T) {
input := createTestInput(8192)
r := NewReader(onlyReader{bytes.NewBuffer(input)})
r := NewReader(onlyReader{bytes.NewReader(input)})
w := new(bytes.Buffer)
if n, err := r.WriteTo(w); err != nil || n != int64(len(input)) {
t.Fatalf("r.WriteTo(w) = %d, %v, want %d, nil", n, err, len(input))
......@@ -877,7 +877,7 @@ func TestWriterReadFrom(t *testing.T) {
input := createTestInput(8192)
b := new(bytes.Buffer)
w := NewWriter(wfunc(b))
r := rfunc(bytes.NewBuffer(input))
r := rfunc(bytes.NewReader(input))
if n, err := w.ReadFrom(r); err != nil || n != int64(len(input)) {
t.Errorf("ws[%d],rs[%d]: w.ReadFrom(r) = %d, %v, want %d, nil", wi, ri, n, err, len(input))
continue
......@@ -1112,63 +1112,83 @@ func (w onlyWriter) Write(b []byte) (int, error) {
func BenchmarkReaderCopyOptimal(b *testing.B) {
// Optimal case is where the underlying reader implements io.WriterTo
srcBuf := bytes.NewBuffer(make([]byte, 8192))
src := NewReader(srcBuf)
dstBuf := new(bytes.Buffer)
dst := onlyWriter{dstBuf}
for i := 0; i < b.N; i++ {
b.StopTimer()
src := NewReader(bytes.NewBuffer(make([]byte, 8192)))
dst := onlyWriter{new(bytes.Buffer)}
b.StartTimer()
srcBuf.Reset()
src.Reset(srcBuf)
dstBuf.Reset()
io.Copy(dst, src)
}
}
func BenchmarkReaderCopyUnoptimal(b *testing.B) {
// Unoptimal case is where the underlying reader doesn't implement io.WriterTo
srcBuf := bytes.NewBuffer(make([]byte, 8192))
src := NewReader(onlyReader{srcBuf})
dstBuf := new(bytes.Buffer)
dst := onlyWriter{dstBuf}
for i := 0; i < b.N; i++ {
b.StopTimer()
src := NewReader(onlyReader{bytes.NewBuffer(make([]byte, 8192))})
dst := onlyWriter{new(bytes.Buffer)}
b.StartTimer()
srcBuf.Reset()
src.Reset(onlyReader{srcBuf})
dstBuf.Reset()
io.Copy(dst, src)
}
}
func BenchmarkReaderCopyNoWriteTo(b *testing.B) {
srcBuf := bytes.NewBuffer(make([]byte, 8192))
srcReader := NewReader(srcBuf)
src := onlyReader{srcReader}
dstBuf := new(bytes.Buffer)
dst := onlyWriter{dstBuf}
for i := 0; i < b.N; i++ {
b.StopTimer()
src := onlyReader{NewReader(bytes.NewBuffer(make([]byte, 8192)))}
dst := onlyWriter{new(bytes.Buffer)}
b.StartTimer()
srcBuf.Reset()
srcReader.Reset(srcBuf)
dstBuf.Reset()
io.Copy(dst, src)
}
}
func BenchmarkWriterCopyOptimal(b *testing.B) {
// Optimal case is where the underlying writer implements io.ReaderFrom
srcBuf := bytes.NewBuffer(make([]byte, 8192))
src := onlyReader{srcBuf}
dstBuf := new(bytes.Buffer)
dst := NewWriter(dstBuf)
for i := 0; i < b.N; i++ {
b.StopTimer()
src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
dst := NewWriter(new(bytes.Buffer))
b.StartTimer()
srcBuf.Reset()
dstBuf.Reset()
dst.Reset(dstBuf)
io.Copy(dst, src)
}
}
func BenchmarkWriterCopyUnoptimal(b *testing.B) {
srcBuf := bytes.NewBuffer(make([]byte, 8192))
src := onlyReader{srcBuf}
dstBuf := new(bytes.Buffer)
dst := NewWriter(onlyWriter{dstBuf})
for i := 0; i < b.N; i++ {
b.StopTimer()
src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
dst := NewWriter(onlyWriter{new(bytes.Buffer)})
b.StartTimer()
srcBuf.Reset()
dstBuf.Reset()
dst.Reset(onlyWriter{dstBuf})
io.Copy(dst, src)
}
}
func BenchmarkWriterCopyNoReadFrom(b *testing.B) {
srcBuf := bytes.NewBuffer(make([]byte, 8192))
src := onlyReader{srcBuf}
dstBuf := new(bytes.Buffer)
dstWriter := NewWriter(dstBuf)
dst := onlyWriter{dstWriter}
for i := 0; i < b.N; i++ {
b.StopTimer()
src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
dst := onlyWriter{NewWriter(new(bytes.Buffer))}
b.StartTimer()
srcBuf.Reset()
dstBuf.Reset()
dstWriter.Reset(dstBuf)
io.Copy(dst, src)
}
}
......
......@@ -306,7 +306,7 @@ func isSpace(r rune) bool {
return true
}
switch r {
case '\u1680', '\u180e', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
case '\u1680', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
return true
}
return false
......
......@@ -38,7 +38,7 @@ var scanTests = []string{
func TestScanByte(t *testing.T) {
for n, test := range scanTests {
buf := bytes.NewBufferString(test)
buf := strings.NewReader(test)
s := NewScanner(buf)
s.Split(ScanBytes)
var i int
......@@ -60,7 +60,7 @@ func TestScanByte(t *testing.T) {
// Test that the rune splitter returns same sequence of runes (not bytes) as for range string.
func TestScanRune(t *testing.T) {
for n, test := range scanTests {
buf := bytes.NewBufferString(test)
buf := strings.NewReader(test)
s := NewScanner(buf)
s.Split(ScanRunes)
var i, runeCount int
......@@ -104,7 +104,7 @@ var wordScanTests = []string{
// Test that the word splitter returns the same data as strings.Fields.
func TestScanWords(t *testing.T) {
for n, test := range wordScanTests {
buf := bytes.NewBufferString(test)
buf := strings.NewReader(test)
s := NewScanner(buf)
s.Split(ScanWords)
words := strings.Fields(test)
......@@ -135,7 +135,7 @@ func TestScanWords(t *testing.T) {
// reads in Scanner.Scan.
type slowReader struct {
max int
buf *bytes.Buffer
buf io.Reader
}
func (sr *slowReader) Read(p []byte) (n int, err error) {
......@@ -248,7 +248,7 @@ func TestScanLineTooLong(t *testing.T) {
// Test that the line splitter handles a final line without a newline.
func testNoNewline(text string, lines []string, t *testing.T) {
buf := bytes.NewBufferString(text)
buf := strings.NewReader(text)
s := NewScanner(&slowReader{7, buf})
s.Split(ScanLines)
for lineNum := 0; s.Scan(); lineNum++ {
......@@ -328,7 +328,7 @@ func TestSplitError(t *testing.T) {
}
// Read the data.
const text = "abcdefghijklmnopqrstuvwxyz"
buf := bytes.NewBufferString(text)
buf := strings.NewReader(text)
s := NewScanner(&slowReader{1, buf})
s.Split(errorSplit)
var i int
......
......@@ -14,7 +14,7 @@ import (
)
func TestBitReader(t *testing.T) {
buf := bytes.NewBuffer([]byte{0xaa})
buf := bytes.NewReader([]byte{0xaa})
br := newBitReader(buf)
if n := br.ReadBits(1); n != 1 {
t.Errorf("read 1 wrong")
......@@ -31,7 +31,7 @@ func TestBitReader(t *testing.T) {
}
func TestBitReaderLarge(t *testing.T) {
buf := bytes.NewBuffer([]byte{0x12, 0x34, 0x56, 0x78})
buf := bytes.NewReader([]byte{0x12, 0x34, 0x56, 0x78})
br := newBitReader(buf)
if n := br.ReadBits(32); n != 0x12345678 {
t.Errorf("got: %x want: %x", n, 0x12345678)
......@@ -43,7 +43,7 @@ func readerFromHex(s string) io.Reader {
if err != nil {
panic("readerFromHex: bad input")
}
return bytes.NewBuffer(data)
return bytes.NewReader(data)
}
func decompressHex(s string) (out []byte, err error) {
......@@ -191,7 +191,7 @@ func benchmarkDecode(b *testing.B, testfile int) {
}
b.SetBytes(int64(len(compressed)))
for i := 0; i < b.N; i++ {
r := bytes.NewBuffer(compressed)
r := bytes.NewReader(compressed)
io.Copy(ioutil.Discard, NewReader(r))
}
}
......@@ -201,7 +201,7 @@ func BenchmarkDecodeTwain(b *testing.B) { benchmarkDecode(b, twain) }
func TestBufferOverrun(t *testing.T) {
// Tests https://code.google.com/p/go/issues/detail?id=5747.
buffer := bytes.NewBuffer([]byte(bufferOverrunBase64))
buffer := bytes.NewReader([]byte(bufferOverrunBase64))
decoder := base64.NewDecoder(base64.StdEncoding, buffer)
decompressor := NewReader(decoder)
// This shouldn't panic.
......
......@@ -190,7 +190,37 @@ func buildHuffmanNode(t *huffmanTree, codes []huffmanCode, level uint32) (nodeIn
right := codes[firstRightIndex:]
if len(left) == 0 || len(right) == 0 {
return 0, StructuralError("superfluous level in Huffman tree")
// There is a superfluous level in the Huffman tree indicating
// a bug in the encoder. However, this bug has been observed in
// the wild so we handle it.
// If this function was called recursively then we know that
// len(codes) >= 2 because, otherwise, we would have hit the
// "leaf node" case, below, and not recursed.
//
// However, for the initial call it's possible that len(codes)
// is zero or one. Both cases are invalid because a zero length
// tree cannot encode anything and a length-1 tree can only
// encode EOF and so is superfluous. We reject both.
if len(codes) < 2 {
return 0, StructuralError("empty Huffman tree")
}
// In this case the recursion doesn't always reduce the length
// of codes so we need to ensure termination via another
// mechanism.
if level == 31 {
// Since len(codes) >= 2 the only way that the values
// can match at all 32 bits is if they are equal, which
// is invalid. This ensures that we never enter
// infinite recursion.
return 0, StructuralError("equal symbols in Huffman tree")
}
if len(left) == 0 {
return buildHuffmanNode(t, right, level+1)
}
return buildHuffmanNode(t, left, level+1)
}
nodeIndex = uint16(t.nextNode)
......
......@@ -14,7 +14,7 @@ import (
)
func TestUncompressedSource(t *testing.T) {
decoder := NewReader(bytes.NewBuffer([]byte{0x01, 0x01, 0x00, 0xfe, 0xff, 0x11}))
decoder := NewReader(bytes.NewReader([]byte{0x01, 0x01, 0x00, 0xfe, 0xff, 0x11}))
output := make([]byte, 1)
n, error := decoder.Read(output)
if n != 1 || error != nil {
......
......@@ -284,7 +284,7 @@ var gunzipTests = []gunzipTest{
func TestDecompressor(t *testing.T) {
b := new(bytes.Buffer)
for _, tt := range gunzipTests {
in := bytes.NewBuffer(tt.gzip)
in := bytes.NewReader(tt.gzip)
gzip, err := NewReader(in)
if err != nil {
t.Errorf("%s: NewReader: %s", tt.name, err)
......
......@@ -85,7 +85,7 @@ func TestRoundTrip(t *testing.T) {
func TestLatin1(t *testing.T) {
latin1 := []byte{0xc4, 'u', 0xdf, 'e', 'r', 'u', 'n', 'g', 0}
utf8 := "Äußerung"
z := Reader{r: bufio.NewReader(bytes.NewBuffer(latin1))}
z := Reader{r: bufio.NewReader(bytes.NewReader(latin1))}
s, err := z.readString()
if err != nil {
t.Fatalf("readString: %v", err)
......
......@@ -127,7 +127,7 @@ func benchmarkDecoder(b *testing.B, n int) {
if len(buf0) > n-i {
buf0 = buf0[:n-i]
}
io.Copy(w, bytes.NewBuffer(buf0))
w.Write(buf0)
}
w.Close()
buf1 := compressed.Bytes()
......@@ -135,7 +135,7 @@ func benchmarkDecoder(b *testing.B, n int) {
runtime.GC()
b.StartTimer()
for i := 0; i < b.N; i++ {
io.Copy(ioutil.Discard, NewReader(bytes.NewBuffer(buf1), LSB, 8))
io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1), LSB, 8))
}
}
......
......@@ -102,7 +102,7 @@ var zlibTests = []zlibTest{
func TestDecompressor(t *testing.T) {
b := new(bytes.Buffer)
for _, tt := range zlibTests {
in := bytes.NewBuffer(tt.compressed)
in := bytes.NewReader(tt.compressed)
zlib, err := NewReaderDict(in, tt.dict)
if err != nil {
if err != tt.err {
......
......@@ -22,7 +22,7 @@ import "sort"
// min-heap with the following invariants (established after
// Init has been called or if the data is empty or sorted):
//
// !h.Less(j, i) for 0 <= i < h.Len() and j = 2*i+1 or 2*i+2 and j < h.Len()
// !h.Less(j, i) for 0 <= i < h.Len() and 2*i+1 <= j <= 2*i+2 and j < h.Len()
//
// Note that Push and Pop in this interface are for package heap's
// implementation to call. To add and remove things from the heap,
......
......@@ -180,18 +180,18 @@ func (l *List) MoveToBack(e *Element) {
}
// MoveBefore moves element e to its new position before mark.
// If e is not an element of l, or e == mark, the list is not modified.
// If e or mark is not an element of l, or e == mark, the list is not modified.
func (l *List) MoveBefore(e, mark *Element) {
if e.list != l || e == mark {
if e.list != l || e == mark || mark.list != l {
return
}
l.insert(l.remove(e), mark.prev)
}
// MoveAfter moves element e to its new position after mark.
// If e is not an element of l, or e == mark, the list is not modified.
// If e or mark is not an element of l, or e == mark, the list is not modified.
func (l *List) MoveAfter(e, mark *Element) {
if e.list != l || e == mark {
if e.list != l || e == mark || mark.list != l {
return
}
l.insert(l.remove(e), mark)
......
......@@ -324,3 +324,20 @@ func TestInsertAfterUnknownMark(t *testing.T) {
l.InsertAfter(1, new(Element))
checkList(t, &l, []interface{}{1, 2, 3})
}
// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.
func TestMoveUnkownMark(t *testing.T) {
var l1 List
e1 := l1.PushBack(1)
var l2 List
e2 := l2.PushBack(2)
l1.MoveAfter(e1, e2)
checkList(t, &l1, []interface{}{1})
checkList(t, &l2, []interface{}{2})
l1.MoveBefore(e1, e2)
checkList(t, &l1, []interface{}{1})
checkList(t, &l2, []interface{}{2})
}
......@@ -48,13 +48,22 @@ func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
iv := x.iv
for len(src) > 0 {
xorBytes(x.iv, x.iv, src[:x.blockSize])
x.b.Encrypt(x.iv, x.iv)
copy(dst, x.iv)
// Write the xor to dst, then encrypt in place.
xorBytes(dst[:x.blockSize], src[:x.blockSize], iv)
x.b.Encrypt(dst[:x.blockSize], dst[:x.blockSize])
// Move to the next block with this block as the next iv.
iv = dst[:x.blockSize]
src = src[x.blockSize:]
dst = dst[x.blockSize:]
}
// Save the iv for the next CryptBlocks call.
copy(x.iv, iv)
}
func (x *cbcEncrypter) SetIV(iv []byte) {
......@@ -85,14 +94,35 @@ func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
for len(src) > 0 {
x.b.Decrypt(x.tmp, src[:x.blockSize])
xorBytes(x.tmp, x.tmp, x.iv)
copy(x.iv, src)
copy(dst, x.tmp)
src = src[x.blockSize:]
dst = dst[x.blockSize:]
if len(src) == 0 {
return
}
// For each block, we need to xor the decrypted data with the previous block's ciphertext (the iv).
// To avoid making a copy each time, we loop over the blocks BACKWARDS.
end := len(src)
start := end - x.blockSize
prev := start - x.blockSize
// Copy the last block of ciphertext in preparation as the new iv.
copy(x.tmp, src[start:end])
// Loop over all but the first block.
for start > 0 {
x.b.Decrypt(dst[start:end], src[start:end])
xorBytes(dst[start:end], dst[start:end], src[prev:start])
end = start
start = prev
prev -= x.blockSize
}
// The first block is special because it uses the saved iv.
x.b.Decrypt(dst[start:end], src[start:end])
xorBytes(dst[start:end], dst[start:end], x.iv)
// Set the new iv to the first block we copied earlier.
x.iv, x.tmp = x.tmp, x.iv
}
func (x *cbcDecrypter) SetIV(iv []byte) {
......
......@@ -63,28 +63,42 @@ var cbcAESTests = []struct {
},
}
func TestCBC_AES(t *testing.T) {
for _, tt := range cbcAESTests {
test := tt.name
c, err := aes.NewCipher(tt.key)
func TestCBCEncrypterAES(t *testing.T) {
for _, test := range cbcAESTests {
c, err := aes.NewCipher(test.key)
if err != nil {
t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
continue
}
encrypter := cipher.NewCBCEncrypter(c, tt.iv)
d := make([]byte, len(tt.in))
encrypter.CryptBlocks(d, tt.in)
if !bytes.Equal(tt.out, d) {
t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test, d, tt.out)
encrypter := cipher.NewCBCEncrypter(c, test.iv)
data := make([]byte, len(test.in))
copy(data, test.in)
encrypter.CryptBlocks(data, data)
if !bytes.Equal(test.out, data) {
t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test.name, data, test.out)
}
}
}
func TestCBCDecrypterAES(t *testing.T) {
for _, test := range cbcAESTests {
c, err := aes.NewCipher(test.key)
if err != nil {
t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
continue
}
decrypter := cipher.NewCBCDecrypter(c, test.iv)
data := make([]byte, len(test.out))
copy(data, test.out)
decrypter := cipher.NewCBCDecrypter(c, tt.iv)
p := make([]byte, len(d))
decrypter.CryptBlocks(p, d)
if !bytes.Equal(tt.in, p) {
t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test, d, tt.in)
decrypter.CryptBlocks(data, data)
if !bytes.Equal(test.in, data) {
t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test.name, data, test.in)
}
}
}
......@@ -167,8 +167,6 @@ var program = `// Copyright 2013 The Go Authors. All rights reserved.
// DO NOT EDIT.
// Generate with: go run gen.go{{if .Full}} -full{{end}} | gofmt >md5block.go
// +build !amd64,!386,!arm
package md5
import (
......@@ -204,7 +202,7 @@ func init() {
littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
}
func block(dig *digest, p []byte) {
func blockGeneric(dig *digest, p []byte) {
a := dig.s[0]
b := dig.s[1]
c := dig.s[2]
......
......@@ -5,6 +5,7 @@
package md5
import (
"crypto/rand"
"fmt"
"io"
"testing"
......@@ -105,6 +106,18 @@ func TestLarge(t *testing.T) {
}
}
// Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match.
func TestBlockGeneric(t *testing.T) {
gen, asm := New().(*digest), New().(*digest)
buf := make([]byte, BlockSize*20) // arbitrary factor
rand.Read(buf)
blockGeneric(gen, buf)
block(asm, buf)
if *gen != *asm {
t.Error("block and blockGeneric resulted in different states")
}
}
var bench = New()
var buf = make([]byte, 8192+1)
var sum = make([]byte, bench.Size())
......
......@@ -5,8 +5,6 @@
// DO NOT EDIT.
// Generate with: go run gen.go -full | gofmt >md5block.go
// +build !amd64,!386,!arm
package md5
import (
......@@ -24,7 +22,7 @@ func init() {
littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
}
func block(dig *digest, p []byte) {
func blockGeneric(dig *digest, p []byte) {
a := dig.s[0]
b := dig.s[1]
c := dig.s[2]
......
// Copyright 2014 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 !amd64,!386,!arm
package md5
var block = blockGeneric
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd plan9
// +build darwin dragonfly freebsd linux netbsd openbsd plan9 solaris
// Unix cryptographically secure pseudorandom number
// generator.
......
......@@ -6,6 +6,7 @@ package rand_test
import (
"crypto/rand"
"math/big"
"testing"
)
......@@ -24,3 +25,41 @@ func TestPrimeSmall(t *testing.T) {
}
}
}
// Test that passing bits < 2 causes Prime to return nil, error
func TestPrimeBitsLt2(t *testing.T) {
if p, err := rand.Prime(rand.Reader, 1); p != nil || err == nil {
t.Errorf("Prime should return nil, error when called with bits < 2")
}
}
func TestInt(t *testing.T) {
// start at 128 so the case of (max.BitLen() % 8) == 0 is covered
for n := 128; n < 140; n++ {
b := new(big.Int).SetInt64(int64(n))
if i, err := rand.Int(rand.Reader, b); err != nil {
t.Fatalf("Can't generate random value: %v, %v", i, err)
}
}
}
func testIntPanics(t *testing.T, b *big.Int) {
defer func() {
if err := recover(); err == nil {
t.Errorf("Int should panic when called with max <= 0: %v", b)
}
}()
rand.Int(rand.Reader, b)
}
// Test that passing a new big.Int as max causes Int to panic
func TestIntEmptyMaxPanics(t *testing.T) {
b := new(big.Int)
testIntPanics(t, b)
}
// Test that passing a negative value as max causes Int to panic
func TestIntNegativeMaxPanics(t *testing.T) {
b := new(big.Int).SetInt64(int64(-1))
testIntPanics(t, b)
}
......@@ -50,3 +50,20 @@ func (c *Cipher) Reset() {
}
c.i, c.j = 0, 0
}
// xorKeyStreamGeneric sets dst to the result of XORing src with the
// key stream. Dst and src may be the same slice but otherwise should
// not overlap.
//
// This is the pure Go version. rc4_{amd64,386,arm}* contain assembly
// implementations. This is here for tests and to prevent bitrot.
func (c *Cipher) xorKeyStreamGeneric(dst, src []byte) {
i, j := c.i, c.j
for k, v := range src {
i += 1
j += uint8(c.s[i])
c.s[i], c.s[j] = c.s[j], c.s[i]
dst[k] = v ^ uint8(c.s[uint8(c.s[i]+c.s[j])])
}
c.i, c.j = i, j
}
......@@ -9,12 +9,5 @@ package rc4
// XORKeyStream sets dst to the result of XORing src with the key stream.
// Dst and src may be the same slice but otherwise should not overlap.
func (c *Cipher) XORKeyStream(dst, src []byte) {
i, j := c.i, c.j
for k, v := range src {
i += 1
j += uint8(c.s[i])
c.s[i], c.s[j] = c.s[j], c.s[i]
dst[k] = v ^ uint8(c.s[uint8(c.s[i]+c.s[j])])
}
c.i, c.j = i, j
c.xorKeyStreamGeneric(dst, src)
}
......@@ -117,19 +117,30 @@ func TestGolden(t *testing.T) {
}
func TestBlock(t *testing.T) {
testBlock(t, (*Cipher).XORKeyStream)
}
// Test the pure Go version.
// Because we have assembly for amd64, 386, and arm, this prevents
// bitrot of the reference implementations.
func TestBlockGeneric(t *testing.T) {
testBlock(t, (*Cipher).xorKeyStreamGeneric)
}
func testBlock(t *testing.T, xor func(c *Cipher, dst, src []byte)) {
c1a, _ := NewCipher(golden[0].key)
c1b, _ := NewCipher(golden[1].key)
data1 := make([]byte, 1<<20)
for i := range data1 {
c1a.XORKeyStream(data1[i:i+1], data1[i:i+1])
c1b.XORKeyStream(data1[i:i+1], data1[i:i+1])
xor(c1a, data1[i:i+1], data1[i:i+1])
xor(c1b, data1[i:i+1], data1[i:i+1])
}
c2a, _ := NewCipher(golden[0].key)
c2b, _ := NewCipher(golden[1].key)
data2 := make([]byte, 1<<20)
c2a.XORKeyStream(data2, data2)
c2b.XORKeyStream(data2, data2)
xor(c2a, data2, data2)
xor(c2b, data2, data2)
if !bytes.Equal(data1, data2) {
t.Fatalf("bad block")
......
......@@ -120,16 +120,18 @@ func (priv *PrivateKey) Validate() error {
return nil
}
// GenerateKey generates an RSA keypair of the given bit size.
// GenerateKey generates an RSA keypair of the given bit size using the
// random source random (for example, crypto/rand.Reader).
func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error) {
return GenerateMultiPrimeKey(random, 2, bits)
}
// GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit
// size, as suggested in [1]. Although the public keys are compatible
// (actually, indistinguishable) from the 2-prime case, the private keys are
// not. Thus it may not be possible to export multi-prime private keys in
// certain formats or to subsequently import them into other code.
// size and the given random source, as suggested in [1]. Although the public
// keys are compatible (actually, indistinguishable) from the 2-prime case,
// the private keys are not. Thus it may not be possible to export multi-prime
// private keys in certain formats or to subsequently import them into other
// code.
//
// Table 1 in [2] suggests maximum numbers of primes for a given size.
//
......
......@@ -197,7 +197,7 @@ func TestEncryptOAEP(t *testing.T) {
public := PublicKey{n, test.e}
for j, message := range test.msgs {
randomSource := bytes.NewBuffer(message.seed)
randomSource := bytes.NewReader(message.seed)
out, err := EncryptOAEP(sha1, randomSource, &public, message.in, nil)
if err != nil {
t.Errorf("#%d,%d error: %s", i, j, err)
......
......@@ -7,6 +7,7 @@
package sha1
import (
"crypto/rand"
"fmt"
"io"
"testing"
......@@ -90,6 +91,18 @@ func TestBlockSize(t *testing.T) {
}
}
// Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match.
func TestBlockGeneric(t *testing.T) {
gen, asm := New().(*digest), New().(*digest)
buf := make([]byte, BlockSize*20) // arbitrary factor
rand.Read(buf)
blockGeneric(gen, buf)
block(asm, buf)
if *gen != *asm {
t.Error("block and blockGeneric resulted in different states")
}
}
var bench = New()
var buf = make([]byte, 8192)
......
......@@ -2,12 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64,!386
// SHA1 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
package sha1
const (
......@@ -17,7 +11,9 @@ const (
_K3 = 0xCA62C1D6
)
func block(dig *digest, p []byte) {
// blockGeneric is a portable, pure Go version of the SHA1 block step.
// It's used by sha1block_generic.go and tests.
func blockGeneric(dig *digest, p []byte) {
var w [16]uint32
h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4]
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64 386
// +build amd64 386 arm
package sha1
......
// Copyright 2014 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 !amd64,!386,!arm
package sha1
var block = blockGeneric
......@@ -10,6 +10,10 @@ package subtle
// and y, have equal contents. The time taken is a function of the length of
// the slices and is independent of the contents.
func ConstantTimeCompare(x, y []byte) int {
if len(x) != len(y) {
panic("subtle: slices have different lengths")
}
var v byte
for i := 0; i < len(x); i++ {
......
......@@ -5,9 +5,11 @@
package tls
import (
"container/list"
"crypto"
"crypto/rand"
"crypto/x509"
"fmt"
"io"
"math/big"
"strings"
......@@ -64,7 +66,7 @@ const (
)
// TLS extension numbers
var (
const (
extensionServerName uint16 = 0
extensionStatusRequest uint16 = 5
extensionSupportedCurves uint16 = 10
......@@ -72,11 +74,17 @@ var (
extensionSignatureAlgorithms uint16 = 13
extensionSessionTicket uint16 = 35
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
)
// TLS signaling cipher suite values
const (
scsvRenegotiation uint16 = 0x00ff
)
// TLS Elliptic Curves
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
var (
const (
curveP256 uint16 = 23
curveP384 uint16 = 24
curveP521 uint16 = 25
......@@ -84,7 +92,7 @@ var (
// TLS Elliptic Curve Point Formats
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
var (
const (
pointFormatUncompressed uint8 = 0
)
......@@ -167,6 +175,29 @@ const (
RequireAndVerifyClientCert
)
// ClientSessionState contains the state needed by clients to resume TLS
// sessions.
type ClientSessionState struct {
sessionTicket []uint8 // Encrypted ticket used for session resumption with server
vers uint16 // SSL/TLS version negotiated for the session
cipherSuite uint16 // Ciphersuite negotiated for the session
masterSecret []byte // MasterSecret generated by client on a full handshake
serverCertificates []*x509.Certificate // Certificate chain presented by the server
}
// ClientSessionCache is a cache of ClientSessionState objects that can be used
// by a client to resume a TLS session with a given server. ClientSessionCache
// implementations should expect to be called concurrently from different
// goroutines.
type ClientSessionCache interface {
// Get searches for a ClientSessionState associated with the given key.
// On return, ok is true if one was found.
Get(sessionKey string) (session *ClientSessionState, ok bool)
// Put adds the ClientSessionState to the cache with the given key.
Put(sessionKey string, cs *ClientSessionState)
}
// A Config structure is used to configure a TLS client or server. After one
// has been passed to a TLS function it must not be modified.
type Config struct {
......@@ -200,8 +231,9 @@ type Config struct {
// NextProtos is a list of supported, application level protocols.
NextProtos []string
// ServerName is included in the client's handshake to support virtual
// hosting.
// ServerName is used to verify the hostname on the returned
// certificates unless InsecureSkipVerify is given. It is also included
// in the client's handshake to support virtual hosting.
ServerName string
// ClientAuth determines the server's policy for
......@@ -245,6 +277,10 @@ type Config struct {
// connections using that key are compromised.
SessionTicketKey [32]byte
// SessionCache is a cache of ClientSessionState entries for TLS session
// resumption.
ClientSessionCache ClientSessionCache
// MinVersion contains the minimum SSL/TLS version that is acceptable.
// If zero, then SSLv3 is taken as the minimum.
MinVersion uint16
......@@ -406,6 +442,77 @@ type handshakeMessage interface {
unmarshal([]byte) bool
}
// lruSessionCache is a ClientSessionCache implementation that uses an LRU
// caching strategy.
type lruSessionCache struct {
sync.Mutex
m map[string]*list.Element
q *list.List
capacity int
}
type lruSessionCacheEntry struct {
sessionKey string
state *ClientSessionState
}
// NewLRUClientSessionCache returns a ClientSessionCache with the given
// capacity that uses an LRU strategy. If capacity is < 1, a default capacity
// is used instead.
func NewLRUClientSessionCache(capacity int) ClientSessionCache {
const defaultSessionCacheCapacity = 64
if capacity < 1 {
capacity = defaultSessionCacheCapacity
}
return &lruSessionCache{
m: make(map[string]*list.Element),
q: list.New(),
capacity: capacity,
}
}
// Put adds the provided (sessionKey, cs) pair to the cache.
func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) {
c.Lock()
defer c.Unlock()
if elem, ok := c.m[sessionKey]; ok {
entry := elem.Value.(*lruSessionCacheEntry)
entry.state = cs
c.q.MoveToFront(elem)
return
}
if c.q.Len() < c.capacity {
entry := &lruSessionCacheEntry{sessionKey, cs}
c.m[sessionKey] = c.q.PushFront(entry)
return
}
elem := c.q.Back()
entry := elem.Value.(*lruSessionCacheEntry)
delete(c.m, entry.sessionKey)
entry.sessionKey = sessionKey
entry.state = cs
c.q.MoveToFront(elem)
c.m[sessionKey] = elem
}
// Get returns the ClientSessionState value associated with a given key. It
// returns (nil, false) if no value is found.
func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) {
c.Lock()
defer c.Unlock()
if elem, ok := c.m[sessionKey]; ok {
c.q.MoveToFront(elem)
return elem.Value.(*lruSessionCacheEntry).state, true
}
return nil, false
}
// TODO(jsing): Make these available to both crypto/x509 and crypto/tls.
type dsaSignature struct {
R, S *big.Int
......@@ -435,3 +542,7 @@ func initDefaultCipherSuites() {
varDefaultCipherSuites[i] = suite.id
}
}
func unexpectedMessageError(wanted, got interface{}) error {
return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
}
......@@ -12,6 +12,7 @@ import (
"crypto/subtle"
"crypto/x509"
"errors"
"fmt"
"io"
"net"
"sync"
......@@ -518,14 +519,17 @@ func (c *Conn) readRecord(want recordType) error {
// else application data. (We don't support renegotiation.)
switch want {
default:
return c.sendAlert(alertInternalError)
c.sendAlert(alertInternalError)
return errors.New("tls: unknown record type requested")
case recordTypeHandshake, recordTypeChangeCipherSpec:
if c.handshakeComplete {
return c.sendAlert(alertInternalError)
c.sendAlert(alertInternalError)
return errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete")
}
case recordTypeApplicationData:
if !c.handshakeComplete {
return c.sendAlert(alertInternalError)
c.sendAlert(alertInternalError)
return errors.New("tls: application data record requested before handshake complete")
}
}
......@@ -562,10 +566,12 @@ Again:
vers := uint16(b.data[1])<<8 | uint16(b.data[2])
n := int(b.data[3])<<8 | int(b.data[4])
if c.haveVers && vers != c.vers {
return c.sendAlert(alertProtocolVersion)
c.sendAlert(alertProtocolVersion)
return fmt.Errorf("tls: received record with version %x when expecting version %x", vers, c.vers)
}
if n > maxCiphertext {
return c.sendAlert(alertRecordOverflow)
c.sendAlert(alertRecordOverflow)
return fmt.Errorf("tls: oversized record received with length %d", n)
}
if !c.haveVers {
// First message, be extra suspicious:
......@@ -577,7 +583,8 @@ Again:
// well under a kilobyte. If the length is >= 12 kB,
// it's probably not real.
if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 || n >= 0x3000 {
return c.sendAlert(alertUnexpectedMessage)
c.sendAlert(alertUnexpectedMessage)
return fmt.Errorf("tls: first record does not look like a TLS handshake")
}
}
if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
......@@ -799,6 +806,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
m = new(clientHelloMsg)
case typeServerHello:
m = new(serverHelloMsg)
case typeNewSessionTicket:
m = new(newSessionTicketMsg)
case typeCertificate:
m = new(certificateMsg)
case typeCertificateRequest:
......@@ -988,10 +997,10 @@ func (c *Conn) VerifyHostname(host string) error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
if !c.isClient {
return errors.New("VerifyHostname called on TLS server connection")
return errors.New("tls: VerifyHostname called on TLS server connection")
}
if !c.handshakeComplete {
return errors.New("TLS handshake has not yet been performed")
return errors.New("tls: handshake has not yet been performed")
}
return c.peerCertificates[0].VerifyHostname(host)
}
......@@ -353,3 +353,87 @@ func TestHandshakeClientCertECDSA(t *testing.T) {
runClientTestTLS10(t, test)
runClientTestTLS12(t, test)
}
func TestClientResumption(t *testing.T) {
serverConfig := &Config{
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
Certificates: testConfig.Certificates,
}
clientConfig := &Config{
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
InsecureSkipVerify: true,
ClientSessionCache: NewLRUClientSessionCache(32),
}
testResumeState := func(test string, didResume bool) {
hs, err := testHandshake(clientConfig, serverConfig)
if err != nil {
t.Fatalf("%s: handshake failed: %s", test, err)
}
if hs.DidResume != didResume {
t.Fatalf("%s resumed: %v, expected: %v", test, hs.DidResume, didResume)
}
}
testResumeState("Handshake", false)
testResumeState("Resume", true)
if _, err := io.ReadFull(serverConfig.rand(), serverConfig.SessionTicketKey[:]); err != nil {
t.Fatalf("Failed to invalidate SessionTicketKey")
}
testResumeState("InvalidSessionTicketKey", false)
testResumeState("ResumeAfterInvalidSessionTicketKey", true)
clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
testResumeState("DifferentCipherSuite", false)
testResumeState("DifferentCipherSuiteRecovers", true)
clientConfig.ClientSessionCache = nil
testResumeState("WithoutSessionCache", false)
}
func TestLRUClientSessionCache(t *testing.T) {
// Initialize cache of capacity 4.
cache := NewLRUClientSessionCache(4)
cs := make([]ClientSessionState, 6)
keys := []string{"0", "1", "2", "3", "4", "5", "6"}
// Add 4 entries to the cache and look them up.
for i := 0; i < 4; i++ {
cache.Put(keys[i], &cs[i])
}
for i := 0; i < 4; i++ {
if s, ok := cache.Get(keys[i]); !ok || s != &cs[i] {
t.Fatalf("session cache failed lookup for added key: %s", keys[i])
}
}
// Add 2 more entries to the cache. First 2 should be evicted.
for i := 4; i < 6; i++ {
cache.Put(keys[i], &cs[i])
}
for i := 0; i < 2; i++ {
if s, ok := cache.Get(keys[i]); ok || s != nil {
t.Fatalf("session cache should have evicted key: %s", keys[i])
}
}
// Touch entry 2. LRU should evict 3 next.
cache.Get(keys[2])
cache.Put(keys[0], &cs[0])
if s, ok := cache.Get(keys[3]); ok || s != nil {
t.Fatalf("session cache should have evicted key 3")
}
// Update entry 0 in place.
cache.Put(keys[0], &cs[3])
if s, ok := cache.Get(keys[0]); !ok || s != &cs[3] {
t.Fatalf("session cache failed update for key 0")
}
// Adding a nil entry is valid.
cache.Put(keys[0], nil)
if s, ok := cache.Get(keys[0]); !ok || s != nil {
t.Fatalf("failed to add nil entry to cache")
}
}
......@@ -21,6 +21,7 @@ type clientHelloMsg struct {
ticketSupported bool
sessionTicket []uint8
signatureAndHashes []signatureAndHash
secureRenegotiation bool
}
func (m *clientHelloMsg) equal(i interface{}) bool {
......@@ -42,7 +43,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
bytes.Equal(m.supportedPoints, m1.supportedPoints) &&
m.ticketSupported == m1.ticketSupported &&
bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes)
eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) &&
m.secureRenegotiation == m1.secureRenegotiation
}
func (m *clientHelloMsg) marshal() []byte {
......@@ -80,6 +82,10 @@ func (m *clientHelloMsg) marshal() []byte {
extensionsLength += 2 + 2*len(m.signatureAndHashes)
numExtensions++
}
if m.secureRenegotiation {
extensionsLength += 1
numExtensions++
}
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
......@@ -114,13 +120,13 @@ func (m *clientHelloMsg) marshal() []byte {
}
if m.nextProtoNeg {
z[0] = byte(extensionNextProtoNeg >> 8)
z[1] = byte(extensionNextProtoNeg)
z[1] = byte(extensionNextProtoNeg & 0xff)
// The length is always 0
z = z[4:]
}
if len(m.serverName) > 0 {
z[0] = byte(extensionServerName >> 8)
z[1] = byte(extensionServerName)
z[1] = byte(extensionServerName & 0xff)
l := len(m.serverName) + 5
z[2] = byte(l >> 8)
z[3] = byte(l)
......@@ -224,6 +230,13 @@ func (m *clientHelloMsg) marshal() []byte {
z = z[2:]
}
}
if m.secureRenegotiation {
z[0] = byte(extensionRenegotiationInfo >> 8)
z[1] = byte(extensionRenegotiationInfo & 0xff)
z[2] = 0
z[3] = 1
z = z[5:]
}
m.raw = x
......@@ -256,6 +269,9 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.cipherSuites = make([]uint16, numCipherSuites)
for i := 0; i < numCipherSuites; i++ {
m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
if m.cipherSuites[i] == scsvRenegotiation {
m.secureRenegotiation = true
}
}
data = data[2+cipherSuiteLen:]
if len(data) < 1 {
......@@ -379,6 +395,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.signatureAndHashes[i].signature = d[1]
d = d[2:]
}
case extensionRenegotiationInfo + 1:
if length != 1 || data[0] != 0 {
return false
}
m.secureRenegotiation = true
}
data = data[length:]
}
......@@ -397,6 +418,7 @@ type serverHelloMsg struct {
nextProtos []string
ocspStapling bool
ticketSupported bool
secureRenegotiation bool
}
func (m *serverHelloMsg) equal(i interface{}) bool {
......@@ -414,7 +436,8 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
m.nextProtoNeg == m1.nextProtoNeg &&
eqStrings(m.nextProtos, m1.nextProtos) &&
m.ocspStapling == m1.ocspStapling &&
m.ticketSupported == m1.ticketSupported
m.ticketSupported == m1.ticketSupported &&
m.secureRenegotiation == m1.secureRenegotiation
}
func (m *serverHelloMsg) marshal() []byte {
......@@ -441,6 +464,10 @@ func (m *serverHelloMsg) marshal() []byte {
if m.ticketSupported {
numExtensions++
}
if m.secureRenegotiation {
extensionsLength += 1
numExtensions++
}
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
......@@ -469,7 +496,7 @@ func (m *serverHelloMsg) marshal() []byte {
}
if m.nextProtoNeg {
z[0] = byte(extensionNextProtoNeg >> 8)
z[1] = byte(extensionNextProtoNeg)
z[1] = byte(extensionNextProtoNeg & 0xff)
z[2] = byte(nextProtoLen >> 8)
z[3] = byte(nextProtoLen)
z = z[4:]
......@@ -494,6 +521,13 @@ func (m *serverHelloMsg) marshal() []byte {
z[1] = byte(extensionSessionTicket)
z = z[4:]
}
if m.secureRenegotiation {
z[0] = byte(extensionRenegotiationInfo >> 8)
z[1] = byte(extensionRenegotiationInfo & 0xff)
z[2] = 0
z[3] = 1
z = z[5:]
}
m.raw = x
......@@ -573,6 +607,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
return false
}
m.ticketSupported = true
case extensionRenegotiationInfo:
if length != 1 || data[0] != 0 {
return false
}
m.secureRenegotiation = true
}
data = data[length:]
}
......
......@@ -12,6 +12,7 @@ import (
"crypto/x509"
"encoding/asn1"
"errors"
"fmt"
"io"
)
......@@ -100,11 +101,13 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
var ok bool
hs.clientHello, ok = msg.(*clientHelloMsg)
if !ok {
return false, c.sendAlert(alertUnexpectedMessage)
c.sendAlert(alertUnexpectedMessage)
return false, unexpectedMessageError(hs.clientHello, msg)
}
c.vers, ok = config.mutualVersion(hs.clientHello.vers)
if !ok {
return false, c.sendAlert(alertProtocolVersion)
c.sendAlert(alertProtocolVersion)
return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers)
}
c.haveVers = true
......@@ -142,20 +145,18 @@ Curves:
}
if !foundCompression {
return false, c.sendAlert(alertHandshakeFailure)
c.sendAlert(alertHandshakeFailure)
return false, errors.New("tls: client does not support uncompressed connections")
}
hs.hello.vers = c.vers
t := uint32(config.time().Unix())
hs.hello.random = make([]byte, 32)
hs.hello.random[0] = byte(t >> 24)
hs.hello.random[1] = byte(t >> 16)
hs.hello.random[2] = byte(t >> 8)
hs.hello.random[3] = byte(t)
_, err = io.ReadFull(config.rand(), hs.hello.random[4:])
_, err = io.ReadFull(config.rand(), hs.hello.random)
if err != nil {
return false, c.sendAlert(alertInternalError)
c.sendAlert(alertInternalError)
return false, err
}
hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
hs.hello.compressionMethod = compressionNone
if len(hs.clientHello.serverName) > 0 {
c.serverName = hs.clientHello.serverName
......@@ -170,7 +171,8 @@ Curves:
}
if len(config.Certificates) == 0 {
return false, c.sendAlert(alertInternalError)
c.sendAlert(alertInternalError)
return false, errors.New("tls: no certificates configured")
}
hs.cert = &config.Certificates[0]
if len(hs.clientHello.serverName) > 0 {
......@@ -199,7 +201,8 @@ Curves:
}
if hs.suite == nil {
return false, c.sendAlert(alertHandshakeFailure)
c.sendAlert(alertHandshakeFailure)
return false, errors.New("tls: no cipher suite supported by both client and server")
}
return false, nil
......@@ -349,7 +352,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
// certificate message, even if it's empty.
if config.ClientAuth >= RequestClientCert {
if certMsg, ok = msg.(*certificateMsg); !ok {
return c.sendAlert(alertHandshakeFailure)
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(certMsg, msg)
}
hs.finishedHash.Write(certMsg.marshal())
......@@ -376,7 +380,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
// Get client key exchange
ckx, ok := msg.(*clientKeyExchangeMsg)
if !ok {
return c.sendAlert(alertUnexpectedMessage)
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(ckx, msg)
}
hs.finishedHash.Write(ckx.marshal())
......@@ -393,7 +398,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
certVerify, ok := msg.(*certificateVerifyMsg)
if !ok {
return c.sendAlert(alertUnexpectedMessage)
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(certVerify, msg)
}
switch key := pub.(type) {
......@@ -473,7 +479,8 @@ func (hs *serverHandshakeState) readFinished() error {
}
nextProto, ok := msg.(*nextProtoMsg)
if !ok {
return c.sendAlert(alertUnexpectedMessage)
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(nextProto, msg)
}
hs.finishedHash.Write(nextProto.marshal())
c.clientProtocol = nextProto.proto
......@@ -485,13 +492,15 @@ func (hs *serverHandshakeState) readFinished() error {
}
clientFinished, ok := msg.(*finishedMsg)
if !ok {
return c.sendAlert(alertUnexpectedMessage)
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(clientFinished, msg)
}
verify := hs.finishedHash.clientSum(hs.masterSecret)
if len(verify) != len(clientFinished.verifyData) ||
subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
return c.sendAlert(alertHandshakeFailure)
c.sendAlert(alertHandshakeFailure)
return errors.New("tls: client's Finished message is incorrect")
}
hs.finishedHash.Write(clientFinished.marshal())
......@@ -594,7 +603,8 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
case *ecdsa.PublicKey, *rsa.PublicKey:
pub = key
default:
return nil, c.sendAlert(alertUnsupportedCertificate)
c.sendAlert(alertUnsupportedCertificate)
return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
}
c.peerCertificates = certs
return pub, nil
......
......@@ -20,6 +20,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
)
......@@ -53,7 +54,7 @@ func init() {
testConfig.BuildNameToCertificate()
}
func testClientHelloFailure(t *testing.T, m handshakeMessage, expected error) {
func testClientHelloFailure(t *testing.T, m handshakeMessage, expectedSubStr string) {
// Create in-memory network connection,
// send message to server. Should return
// expected error.
......@@ -68,20 +69,20 @@ func testClientHelloFailure(t *testing.T, m handshakeMessage, expected error) {
}()
err := Server(s, testConfig).Handshake()
s.Close()
if e, ok := err.(*net.OpError); !ok || e.Err != expected {
t.Errorf("Got error: %s; expected: %s", err, expected)
if err == nil || !strings.Contains(err.Error(), expectedSubStr) {
t.Errorf("Got error: %s; expected to match substring '%s'", err, expectedSubStr)
}
}
func TestSimpleError(t *testing.T) {
testClientHelloFailure(t, &serverHelloDoneMsg{}, alertUnexpectedMessage)
testClientHelloFailure(t, &serverHelloDoneMsg{}, "unexpected handshake message")
}
var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205}
func TestRejectBadProtocolVersion(t *testing.T) {
for _, v := range badProtocolVersions {
testClientHelloFailure(t, &clientHelloMsg{vers: v}, alertProtocolVersion)
testClientHelloFailure(t, &clientHelloMsg{vers: v}, "unsupported, maximum protocol version")
}
}
......@@ -91,7 +92,7 @@ func TestNoSuiteOverlap(t *testing.T) {
cipherSuites: []uint16{0xff00},
compressionMethods: []uint8{0},
}
testClientHelloFailure(t, clientHello, alertHandshakeFailure)
testClientHelloFailure(t, clientHello, "no cipher suite supported by both client and server")
}
func TestNoCompressionOverlap(t *testing.T) {
......@@ -100,7 +101,7 @@ func TestNoCompressionOverlap(t *testing.T) {
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
compressionMethods: []uint8{0xff},
}
testClientHelloFailure(t, clientHello, alertHandshakeFailure)
testClientHelloFailure(t, clientHello, "client does not support uncompressed connections")
}
func TestTLS12OnlyCipherSuites(t *testing.T) {
......@@ -177,10 +178,12 @@ func TestClose(t *testing.T) {
func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, err error) {
c, s := net.Pipe()
done := make(chan bool)
go func() {
cli := Client(c, clientConfig)
cli.Handshake()
c.Close()
done <- true
}()
server := Server(s, serverConfig)
err = server.Handshake()
......@@ -188,6 +191,7 @@ func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, e
state = server.ConnectionState()
}
s.Close()
<-done
return
}
......@@ -490,9 +494,9 @@ func TestHandshakeServerSNI(t *testing.T) {
// TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
// an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate.
func TestCipherSuiteCertPreferance(t *testing.T) {
func TestCipherSuiteCertPreferenceECDSA(t *testing.T) {
config := *testConfig
config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}
config.PreferServerCipherSuites = true
test := &serverTest{
......
......@@ -19,6 +19,9 @@ import (
"math/big"
)
var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
// rsaKeyAgreement implements the standard TLS key agreement where the client
// encrypts the pre-master secret to the server's public key.
type rsaKeyAgreement struct{}
......@@ -35,14 +38,14 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
}
if len(ckx.ciphertext) < 2 {
return nil, errors.New("bad ClientKeyExchange")
return nil, errClientKeyExchange
}
ciphertext := ckx.ciphertext
if version != VersionSSL30 {
ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
if ciphertextLen != len(ckx.ciphertext)-2 {
return nil, errors.New("bad ClientKeyExchange")
return nil, errClientKeyExchange
}
ciphertext = ckx.ciphertext[2:]
}
......@@ -61,7 +64,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
}
func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
return errors.New("unexpected ServerKeyExchange")
return errors.New("tls: unexpected ServerKeyExchange")
}
func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
......@@ -271,11 +274,11 @@ Curve:
func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
return nil, errors.New("bad ClientKeyExchange")
return nil, errClientKeyExchange
}
x, y := elliptic.Unmarshal(ka.curve, ckx.ciphertext[1:])
if x == nil {
return nil, errors.New("bad ClientKeyExchange")
return nil, errClientKeyExchange
}
x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
......@@ -285,8 +288,6 @@ func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Cert
return preMasterSecret, nil
}
var errServerKeyExchange = errors.New("invalid ServerKeyExchange")
func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
if len(skx.key) < 4 {
return errServerKeyExchange
......
>>> Flow 1 (client to server)
00000000 16 03 01 01 39 01 00 01 35 03 03 52 ac 77 f8 cf |....9...5..R.w..|
00000010 8e 29 75 5c 1e a8 0c ef df a1 2b c5 c0 ca fe bc |.)u\......+.....|
00000020 63 b1 df 9a 17 e3 5f a4 e1 1c c4 00 00 a0 c0 30 |c....._........0|
00000000 16 03 01 00 ca 01 00 00 c6 03 03 52 cc 5e 7f 49 |...........R.^.I|
00000010 8a 7a 88 c0 85 24 6b 3d 95 ff 0f 9e 91 32 c2 a4 |.z...$k=.....2..|
00000020 6b 4c 53 e4 b4 4c 40 72 e4 54 27 00 00 32 c0 30 |kLS..L@r.T'..2.0|
00000030 c0 2c c0 28 c0 24 c0 14 c0 0a c0 22 c0 21 00 a3 |.,.(.$.....".!..|
00000040 00 9f 00 6b 00 6a 00 39 00 38 00 88 00 87 c0 32 |...k.j.9.8.....2|
00000050 c0 2e c0 2a c0 26 c0 0f c0 05 00 9d 00 3d 00 35 |...*.&.......=.5|
00000060 00 84 c0 12 c0 08 c0 1c c0 1b 00 16 00 13 c0 0d |................|
00000070 c0 03 00 0a c0 2f c0 2b c0 27 c0 23 c0 13 c0 09 |...../.+.'.#....|
00000080 c0 1f c0 1e 00 a2 00 9e 00 67 00 40 00 33 00 32 |.........g.@.3.2|
00000090 00 9a 00 99 00 45 00 44 c0 31 c0 2d c0 29 c0 25 |.....E.D.1.-.).%|
000000a0 c0 0e c0 04 00 9c 00 3c 00 2f 00 96 00 41 00 07 |.......<./...A..|
000000b0 c0 11 c0 07 c0 0c c0 02 00 05 00 04 00 15 00 12 |................|
000000c0 00 09 00 14 00 11 00 08 00 06 00 03 00 ff 02 01 |................|
000000d0 00 00 6b 00 0b 00 04 03 00 01 02 00 0a 00 34 00 |..k...........4.|
000000e0 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 00 09 00 |2...............|
000000f0 0a 00 16 00 17 00 08 00 06 00 07 00 14 00 15 00 |................|
00000100 04 00 05 00 12 00 13 00 01 00 02 00 03 00 0f 00 |................|
00000110 10 00 11 00 0d 00 22 00 20 06 01 06 02 06 03 05 |......". .......|
00000120 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 |................|
00000130 03 02 01 02 02 02 03 01 01 00 0f 00 01 01 |..............|
00000060 01 00 00 6b 00 0b 00 04 03 00 01 02 00 0a 00 34 |...k...........4|
00000070 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 00 09 |.2..............|
00000080 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 00 15 |................|
00000090 00 04 00 05 00 12 00 13 00 01 00 02 00 03 00 0f |................|
000000a0 00 10 00 11 00 0d 00 22 00 20 06 01 06 02 06 03 |.......". ......|
000000b0 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 |................|
000000c0 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 01 |...............|
>>> Flow 2 (server to client)
00000000 16 03 03 00 2a 02 00 00 26 03 03 00 00 00 00 00 |....*...&.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
......@@ -72,35 +65,35 @@
00000310 48 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 |H...jB..~~1...f.|
00000320 42 00 ad 7d 06 35 ab ec 8d ac d4 ba 1b 49 5e 05 |B..}.5.......I^.|
00000330 5f f0 97 93 82 b8 2b 8d 91 98 63 8e b4 14 62 db |_.....+...c...b.|
00000340 1e c9 2b b9 8d 7b bf 37 1c f3 94 74 60 d6 7d a5 |..+..{.7...t`.}.|
00000350 28 0a 74 d1 59 87 c3 42 31 9a 0e f7 85 ce ec eb |(.t.Y..B1.......|
00000360 fa 4a 14 16 03 03 00 04 0e 00 00 00 |.J..........|
00000340 1e c9 2b ca fe c9 88 b7 3d 46 d2 5b 55 de bc 9a |..+.....=F.[U...|
00000350 66 c9 cf b7 3d e8 c8 62 24 93 d8 db 12 77 2a 6c |f...=..b$....w*l|
00000360 08 66 48 16 03 03 00 04 0e 00 00 00 |.fH.........|
>>> Flow 3 (client to server)
00000000 16 03 03 00 8a 10 00 00 86 85 04 01 31 b5 19 44 |............1..D|
00000010 f5 d4 29 20 77 2e cc a9 bb ab 5d 3b f6 0e 5c dd |..) w.....];..\.|
00000020 c2 cd 42 a4 b1 ce 1f 69 0f 09 c7 ef 5a 99 96 03 |..B....i....Z...|
00000030 5b 57 86 02 c0 d0 9a a6 5f 59 b0 5b 45 c2 ae ec |[W......_Y.[E...|
00000040 cf 3d 3d 60 b5 5f 7d c9 82 5a 54 0b 74 00 c2 8b |.==`._}..ZT.t...|
00000050 67 2f f9 dd c9 bd 2c 63 12 5b 55 61 09 8b fe 75 |g/....,c.[Ua...u|
00000060 23 2c a2 c1 bd 6e 71 23 07 e3 c2 64 5e 13 f1 d1 |#,...nq#...d^...|
00000070 cc db 17 dc 8b e6 4f d4 72 46 0a 1e 26 63 cb e0 |......O.rF..&c..|
00000080 da f3 f7 f6 d3 64 f5 44 ce 01 7b 21 4e cb 23 14 |.....d.D..{!N.#.|
00000090 03 03 00 01 01 16 03 03 00 40 5d 5b 3c 90 6b e1 |.........@][<.k.|
000000a0 33 90 6a a3 6a 9e f8 a6 9b 2d ca 8b ea 26 10 92 |3.j.j....-...&..|
000000b0 ca 60 7b 4b fb 8a df 5d 1d 4b 23 41 7e 4f f7 c2 |.`{K...].K#A~O..|
000000c0 98 64 11 84 56 bc 9c ba 11 1c 19 7f a9 04 43 d3 |.d..V.........C.|
000000d0 a0 80 47 11 09 a5 dc 08 fc a0 |..G.......|
00000000 16 03 03 00 8a 10 00 00 86 85 04 01 fd 02 a1 b1 |................|
00000010 56 3c 37 37 da 78 37 d9 07 ee 09 35 4f ff 3e db |V<77.x7....5O.>.|
00000020 da da 23 12 2c 40 12 dd 73 e7 2c c5 2e fb 37 24 |..#.,@..s.,...7$|
00000030 2f 97 95 b4 6c 1e 56 6c 4e 49 d5 89 21 8b ca 74 |/...l.VlNI..!..t|
00000040 85 1b 24 96 fb 28 cc 64 70 59 fc be 18 00 00 98 |..$..(.dpY......|
00000050 9a f6 c9 26 26 6d ce 48 7b 3b 62 ea dd da 73 8b |...&&m.H{;b...s.|
00000060 71 48 18 71 52 2d 22 1d 7c 67 55 1b 6b fa 44 40 |qH.qR-".|gU.k.D@|
00000070 be 87 0f 52 21 4b 86 b4 f0 6d 1b dd e7 0f f8 ef |...R!K...m......|
00000080 1a 09 8b 66 b9 60 38 da 6f 9d 9d 74 58 d9 35 14 |...f.`8.o..tX.5.|
00000090 03 03 00 01 01 16 03 03 00 40 5b 98 11 9d d4 83 |.........@[.....|
000000a0 13 b6 28 4b 85 61 0b e1 bf 36 3f 43 c0 95 3d 7e |..(K.a...6?C..=~|
000000b0 95 ea 84 14 e6 6d 1a e0 20 50 b4 02 d0 b2 e9 5f |.....m.. P....._|
000000c0 07 82 a8 6a 1e 7c 1e f7 6c b5 be 1b 20 2e 98 4e |...j.|..l... ..N|
000000d0 ab 8d 1e f2 56 88 ed ef aa 39 |....V....9|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
00000010 00 00 00 00 00 00 00 00 00 00 00 2e 6a 39 7e ab |............j9~.|
00000020 da af a7 27 4f 60 4e e4 d6 6e 75 3a 03 20 af 45 |...'O`N..nu:. .E|
00000030 a2 ad 58 2e 8b 4b e6 5f 22 41 87 79 21 eb 5c 71 |..X..K._"A.y!.\q|
00000040 d8 63 ba 42 8b 32 8a 61 e2 6f 43 17 03 03 00 40 |.c.B.2.a.oC....@|
00000010 00 00 00 00 00 00 00 00 00 00 00 7e f1 fc 1d 0c |...........~....|
00000020 f5 a2 c6 35 de 78 97 62 72 3f 05 6c a3 a8 0e cb |...5.x.br?.l....|
00000030 10 7e c0 3d 28 c7 d9 4e 71 f4 18 d7 14 42 09 5c |.~.=(..Nq....B.\|
00000040 22 26 04 1f 04 12 9f 88 3d 4a 4a 17 03 03 00 40 |"&......=JJ....@|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060 2e e2 39 2b 6c 28 9e 3a 59 f6 31 04 8b 95 be bd |..9+l(.:Y.1.....|
00000070 73 e6 12 77 ab 3a 30 30 1b f2 5f 7e 42 f9 53 1c |s..w.:00.._~B.S.|
00000080 bf 3c 58 8f e0 b6 c7 f2 c5 5d 0f d0 37 3f 37 96 |.<X......]..7?7.|
00000060 0f 35 50 38 be 3a c7 4e c4 de 36 63 85 c1 7a 78 |.5P8.:.N..6c..zx|
00000070 c6 7f 65 8c d1 44 c5 7e 45 32 60 88 93 bf 10 82 |..e..D.~E2`.....|
00000080 4b 1a 46 9a 60 54 c5 ee 2a c1 86 02 a7 b6 d5 ea |K.F.`T..*.......|
00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
000000a0 00 00 00 00 00 a5 fa 6a 4d 33 1a 0d 83 5e 26 39 |.......jM3...^&9|
000000b0 a1 07 3c 00 02 7e 2b 1b c0 95 4a 16 85 83 c4 af |..<..~+...J.....|
000000c0 79 0e 43 c6 c8 |y.C..|
000000a0 00 00 00 00 00 78 6c 41 05 2f 6f c2 d7 70 54 24 |.....xlA./o..pT$|
000000b0 66 01 2c 1e 71 43 05 3a 1b 9e 86 ff b4 c5 65 b2 |f.,.qC.:......e.|
000000c0 f0 f8 ef 6b 25 |...k%|
>>> Flow 1 (client to server)
00000000 16 03 01 01 39 01 00 01 35 03 03 52 ac 77 f8 37 |....9...5..R.w.7|
00000010 29 0d 02 21 92 09 b5 f1 91 cd bc a7 7d 84 2b 9b |)..!........}.+.|
00000020 f5 4f bf b6 c6 f3 a0 60 62 df cf 00 00 a0 c0 30 |.O.....`b......0|
00000000 16 03 01 00 ca 01 00 00 c6 03 03 52 cc 5e 7f ec |...........R.^..|
00000010 d7 b4 0c ac 92 e8 d1 6e df c1 e6 ee f5 84 5e 1a |.......n......^.|
00000020 1d 05 bf 2d 3f 71 91 d1 cc b7 f8 00 00 32 c0 30 |...-?q.......2.0|
00000030 c0 2c c0 28 c0 24 c0 14 c0 0a c0 22 c0 21 00 a3 |.,.(.$.....".!..|
00000040 00 9f 00 6b 00 6a 00 39 00 38 00 88 00 87 c0 32 |...k.j.9.8.....2|
00000050 c0 2e c0 2a c0 26 c0 0f c0 05 00 9d 00 3d 00 35 |...*.&.......=.5|
00000060 00 84 c0 12 c0 08 c0 1c c0 1b 00 16 00 13 c0 0d |................|
00000070 c0 03 00 0a c0 2f c0 2b c0 27 c0 23 c0 13 c0 09 |...../.+.'.#....|
00000080 c0 1f c0 1e 00 a2 00 9e 00 67 00 40 00 33 00 32 |.........g.@.3.2|
00000090 00 9a 00 99 00 45 00 44 c0 31 c0 2d c0 29 c0 25 |.....E.D.1.-.).%|
000000a0 c0 0e c0 04 00 9c 00 3c 00 2f 00 96 00 41 00 07 |.......<./...A..|
000000b0 c0 11 c0 07 c0 0c c0 02 00 05 00 04 00 15 00 12 |................|
000000c0 00 09 00 14 00 11 00 08 00 06 00 03 00 ff 02 01 |................|
000000d0 00 00 6b 00 0b 00 04 03 00 01 02 00 0a 00 34 00 |..k...........4.|
000000e0 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 00 09 00 |2...............|
000000f0 0a 00 16 00 17 00 08 00 06 00 07 00 14 00 15 00 |................|
00000100 04 00 05 00 12 00 13 00 01 00 02 00 03 00 0f 00 |................|
00000110 10 00 11 00 0d 00 22 00 20 06 01 06 02 06 03 05 |......". .......|
00000120 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 |................|
00000130 03 02 01 02 02 02 03 01 01 00 0f 00 01 01 |..............|
00000060 01 00 00 6b 00 0b 00 04 03 00 01 02 00 0a 00 34 |...k...........4|
00000070 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 00 09 |.2..............|
00000080 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 00 15 |................|
00000090 00 04 00 05 00 12 00 13 00 01 00 02 00 03 00 0f |................|
000000a0 00 10 00 11 00 0d 00 22 00 20 06 01 06 02 06 03 |.......". ......|
000000b0 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 |................|
000000c0 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 01 |...............|
>>> Flow 2 (server to client)
00000000 16 03 03 00 2a 02 00 00 26 03 03 00 00 00 00 00 |....*...&.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 13 00 16 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 14 00 16 |................|
00000030 03 03 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 |..............0.|
00000040 02 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 |..0.............|
00000050 bb a4 8a 7f b8 ca 30 0d 06 09 2a 86 48 86 f7 0d |......0...*.H...|
......@@ -76,42 +69,42 @@
00000350 61 28 63 33 78 f6 31 39 fd 8a f4 15 18 11 fe db |a(c3x.19........|
00000360 d5 07 da 2c ed 49 a0 23 bf d0 3a 38 1d 54 ae 1c |...,.I.#..:8.T..|
00000370 7b ea 29 ee d0 38 c1 76 a7 7f 2a f4 ce 1e ac cc |{.)..8.v..*.....|
00000380 94 79 90 33 04 01 00 80 8f 6a 76 5c 33 9a 1e 46 |.y.3.....jv\3..F|
00000390 e6 c4 91 f6 69 23 05 38 bf c0 fd 9e dc 32 49 a6 |....i#.8.....2I.|
000003a0 9a 80 43 a0 47 d4 37 f5 98 06 2f 77 cb 30 8a 95 |..C.G.7.../w.0..|
000003b0 04 02 76 f1 2a ee 7c a6 79 df 7f 63 1e 1a 64 75 |..v.*.|.y..c..du|
000003c0 f5 a9 1e a9 32 49 65 8b 5b 1b 02 68 7b 6c 39 e8 |....2Ie.[..h{l9.|
000003d0 06 99 10 08 77 f7 a2 b3 22 14 14 d6 83 b8 a2 3e |....w..."......>|
000003e0 e3 a6 4d dd da 99 c4 d7 5c 4c d1 2f 0e 0e 21 2e |..M.....\L./..!.|
000003f0 e0 9d dc bf 51 f3 da 1d 7a df 8e dc 41 77 b3 18 |....Q...z...Aw..|
00000400 38 75 ba b6 a3 75 0f fd 16 03 03 00 04 0e 00 00 |8u...u..........|
00000380 94 79 90 33 04 01 00 80 ad 89 a5 bf 16 74 a1 14 |.y.3.........t..|
00000390 c4 a1 09 31 95 69 e4 b4 e3 8d df 99 73 cd e6 94 |...1.i......s...|
000003a0 eb ca 07 7f f4 36 ca 31 1c 29 f0 f0 d8 40 6b 19 |.....6.1.)...@k.|
000003b0 f2 15 be f1 76 22 b3 82 f7 bf 2b 09 0f cd 31 c8 |....v"....+...1.|
000003c0 69 7b 7b 1a ed a1 f7 85 6e 04 5c fa a5 20 c0 ef |i{{.....n.\.. ..|
000003d0 c6 45 6d 05 25 37 ec f6 94 91 32 f3 c8 d1 f0 13 |.Em.%7....2.....|
000003e0 81 1e 26 bb 4c 47 91 79 ad cf 7e 61 85 54 eb 13 |..&.LG.y..~a.T..|
000003f0 6b b1 15 36 72 bf d1 ad 07 3e 6d bd 44 1a 30 ac |k..6r....>m.D.0.|
00000400 41 39 ad 75 14 bb 11 dc 16 03 03 00 04 0e 00 00 |A9.u............|
00000410 00 |.|
>>> Flow 3 (client to server)
00000000 16 03 03 00 8a 10 00 00 86 85 04 01 e0 a2 f2 1d |................|
00000010 d1 f5 e7 49 09 07 df 43 5f 45 f7 fc 42 9a 81 7d |...I...C_E..B..}|
00000020 39 fa bf 1c 74 df 68 de 93 49 62 3e 72 e7 78 47 |9...t.h..Ib>r.xG|
00000030 71 71 fd d0 3d 89 d3 38 aa f0 54 4a ad 1e 87 e9 |qq..=..8..TJ....|
00000040 f7 89 90 b0 25 5b a0 81 a0 20 1a 99 5e 01 7f 05 |....%[... ..^...|
00000050 95 78 f7 f4 4a ec 85 a9 aa cc 56 bc f7 15 37 ab |.x..J.....V...7.|
00000060 31 41 62 d3 ea 46 ce 94 bf 6c 00 83 a6 f0 ee dc |1Ab..F...l......|
00000070 0b 2a e0 5a fb f0 db 70 cd 9f 48 92 49 c9 9d 20 |.*.Z...p..H.I.. |
00000080 7b 8c de af 9d cd 5e 20 94 4e 95 c7 32 50 94 14 |{.....^ .N..2P..|
00000090 03 03 00 01 01 16 03 03 00 40 6a 6c 92 ef b5 d0 |.........@jl....|
000000a0 8f 4d c7 23 5b 31 65 71 24 50 be 5a e7 95 fc 14 |.M.#[1eq$P.Z....|
000000b0 e7 4f 33 c8 ae e0 e7 5f 63 76 3a 7b 51 cd 18 7a |.O3...._cv:{Q..z|
000000c0 15 15 0c aa cc 76 be fc 1e 55 a1 3a df 05 4c 84 |.....v...U.:..L.|
000000d0 75 6e c2 2b 3d 93 76 53 41 13 |un.+=.vSA.|
00000000 16 03 03 00 8a 10 00 00 86 85 04 01 fb 77 96 9a |.............w..|
00000010 82 26 4f 44 b5 2f 32 28 0a dd 51 f5 a4 84 46 a1 |.&OD./2(..Q...F.|
00000020 ba 58 e6 9a 96 1b 85 9f ae 3a 8b db a8 93 81 00 |.X.......:......|
00000030 17 be 24 26 17 fd b8 7c fe 93 7f af 5f 4d c6 47 |..$&...|...._M.G|
00000040 8b 72 5b 23 89 03 d5 a6 fb 6f de 59 15 00 bb 36 |.r[#.....o.Y...6|
00000050 6d 72 03 47 61 b7 7e d4 46 43 b3 e9 9d 2f 61 6a |mr.Ga.~.FC.../aj|
00000060 08 1b 04 70 ac 95 ad bf 18 e5 09 b6 b3 0d 6a bb |...p..........j.|
00000070 e8 77 09 fa 81 2e 8a e1 61 7e 9f 38 d0 67 f5 11 |.w......a~.8.g..|
00000080 f1 62 7f a4 69 4a 42 7a f8 9e 05 26 66 34 6e 14 |.b..iJBz...&f4n.|
00000090 03 03 00 01 01 16 03 03 00 40 2c a1 a8 3a 34 18 |.........@,..:4.|
000000a0 ea a1 d4 28 0b 1a ac ab 51 b1 c5 48 f2 56 8d c7 |...(....Q..H.V..|
000000b0 83 7b 70 44 40 7d 15 1c 00 19 ed 53 21 fe 9d c1 |.{pD@}.....S!...|
000000c0 a2 13 8f a0 0c 51 f5 13 67 1f bf 07 da bc 2d ca |.....Q..g.....-.|
000000d0 7c 0f 53 4b 4a 02 bb 0f 72 c6 ||.SKJ...r.|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
00000010 00 00 00 00 00 00 00 00 00 00 00 e8 4b a0 ea c7 |............K...|
00000020 e8 9e 4a c7 c5 65 84 eb 3f 4e a5 bd 97 11 b4 0b |..J..e..?N......|
00000030 26 b8 6d 28 16 38 c4 92 d9 45 48 7f 7f e0 74 dd |&.m(.8...EH...t.|
00000040 85 b7 13 5b f8 4e 5b 3f 00 95 0a 17 03 03 00 40 |...[.N[?.......@|
00000010 00 00 00 00 00 00 00 00 00 00 00 82 f6 03 51 7f |..............Q.|
00000020 37 19 ec 26 20 db e2 5b 8e 5e 22 29 1a 88 ca f1 |7..& ..[.^")....|
00000030 ad 55 1c 3c 07 1d 05 b6 c4 88 58 84 a0 5d 33 41 |.U.<......X..]3A|
00000040 7a 65 bc ba a1 71 a4 71 df 6c 9d 17 03 03 00 40 |ze...q.q.l.....@|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060 c6 52 ac 75 32 b3 86 f4 cb cf 18 66 02 40 a3 b1 |.R.u2......f.@..|
00000070 cb 1b 25 2e ac 91 a7 91 2b 73 37 72 c1 1f 2c 2f |..%.....+s7r..,/|
00000080 55 59 12 bd f0 df b4 07 fa b1 13 cc 58 f3 66 54 |UY..........X.fT|
00000060 8d ca 51 a1 4a b1 23 dc e3 ef 63 5f b0 e8 7a c6 |..Q.J.#...c_..z.|
00000070 97 d7 18 6a 4b 80 3e 5c 7b 79 86 93 60 2c 8b f1 |...jK.>\{y..`,..|
00000080 4e 46 c5 5e 64 0c 98 81 10 6d c5 08 22 f1 02 1d |NF.^d....m.."...|
00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
000000a0 00 00 00 00 00 14 49 94 f4 07 cb 98 d2 6f a5 b3 |......I......o..|
000000b0 37 bb 55 71 04 43 f9 3c 53 1c 00 31 c9 3b 8a 5c |7.Uq.C.<S..1.;.\|
000000c0 53 75 90 5d 59 |Su.]Y|
000000a0 00 00 00 00 00 51 19 c4 67 b7 14 6b 5c 49 ac 1d |.....Q..g..k\I..|
000000b0 b3 97 88 42 29 cb f5 06 54 f4 c6 38 9a 47 41 78 |...B)...T..8.GAx|
000000c0 0f 33 21 ac c5 |.3!..|
>>> Flow 1 (client to server)
00000000 16 03 01 00 e9 01 00 00 e5 03 03 52 ac 77 f8 65 |...........R.w.e|
00000010 60 65 1c ac 85 b1 4c d1 e0 5f 02 b0 22 80 c9 98 |`e....L.._.."...|
00000020 af d9 43 87 0a e8 26 a3 d9 59 cc 20 76 ef 21 5d |..C...&..Y. v.!]|
00000030 53 6c 8b 2e 11 a0 43 a8 af 74 8a 58 40 a5 95 ee |Sl....C..t.X@...|
00000040 6d a9 ff e8 e4 d8 ba d2 88 ca 7f 0a 00 04 00 05 |m...............|
00000050 00 ff 02 01 00 00 97 00 23 00 68 00 00 00 00 00 |........#.h.....|
00000060 00 00 00 00 00 00 00 00 00 00 00 65 ea 4b d1 ef |...........e.K..|
00000070 ba 11 a0 88 48 34 0d 3b 22 38 1e 62 c5 0a 33 b3 |....H4.;"8.b..3.|
00000080 f0 65 ff fa c4 f3 a8 2d 24 75 55 e4 47 cc d2 6b |.e.....-$uU.G..k|
00000090 8d 26 c6 d1 10 cc a2 48 29 c0 a1 a5 52 66 dc ec |.&.....H)...Rf..|
000000a0 0b 59 23 02 5b 66 c3 af 88 27 f0 65 c0 72 de 1a |.Y#.[f...'.e.r..|
000000b0 db cf 9b 5f e7 fe e8 2d 27 6f 67 fb 91 a1 46 70 |..._...-'og...Fp|
000000c0 b1 ce 29 00 0d 00 22 00 20 06 01 06 02 06 03 05 |..)...". .......|
000000d0 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 |................|
000000e0 03 02 01 02 02 02 03 01 01 00 0f 00 01 01 |..............|
00000000 16 03 01 00 e8 01 00 00 e4 03 03 52 cc 57 59 c3 |...........R.WY.|
00000010 8b df 97 05 d8 5f 16 22 b4 b1 e7 cb 7d 2f 9b 58 |....._."....}/.X|
00000020 a3 f4 d7 2c a4 c1 9d 49 ed 4b ba 20 90 da 90 3e |...,...I.K. ...>|
00000030 36 19 7a db 56 43 26 f7 dc 42 57 33 22 ed 9d a4 |6.z.VC&..BW3"...|
00000040 9d 53 da f8 9d 4e 60 66 71 a0 2e 2e 00 04 00 05 |.S...N`fq.......|
00000050 00 ff 01 00 00 97 00 23 00 68 00 00 00 00 00 00 |.......#.h......|
00000060 00 00 00 00 00 00 00 00 00 00 65 ea 4b d1 ef ba |..........e.K...|
00000070 06 38 1e e1 88 82 3a cd 03 ac 3b 39 0a e0 19 fd |.8....:...;9....|
00000080 af 6c 57 30 df 31 6e f7 92 38 4b 5d 77 90 39 ff |.lW0.1n..8K]w.9.|
00000090 32 51 f5 ed 12 d7 b0 7c 4d 6c c5 76 e4 72 48 3e |2Q.....|Ml.v.rH>|
000000a0 59 23 fe 0d 15 df f4 ba ea b9 67 16 23 8f 7d 15 |Y#........g.#.}.|
000000b0 b6 11 f1 ab d7 d4 cd a3 21 82 92 2a 12 cf 95 f3 |........!..*....|
000000c0 60 b2 00 0d 00 22 00 20 06 01 06 02 06 03 05 01 |`....". ........|
000000d0 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................|
000000e0 02 01 02 02 02 03 01 01 00 0f 00 01 01 |.............|
>>> Flow 2 (server to client)
00000000 16 03 03 00 4a 02 00 00 46 03 03 00 00 00 00 00 |....J...F.......|
00000000 16 03 03 00 51 02 00 00 4d 03 03 00 00 00 00 00 |....Q...M.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 20 76 ef 21 5d |........... v.!]|
00000030 53 6c 8b 2e 11 a0 43 a8 af 74 8a 58 40 a5 95 ee |Sl....C..t.X@...|
00000040 6d a9 ff e8 e4 d8 ba d2 88 ca 7f 0a 00 05 00 14 |m...............|
00000050 03 03 00 01 01 16 03 03 00 24 37 d8 ed 9b cc 6d |.........$7....m|
00000060 5f ce c0 40 68 4b 1f 45 ff 94 3a 98 ec c7 69 1c |_..@hK.E..:...i.|
00000070 26 50 9e 3c 54 e6 da b6 5c 2e 48 66 1d 65 |&P.<T...\.Hf.e|
00000020 00 00 00 00 00 00 00 00 00 00 00 20 90 da 90 3e |........... ...>|
00000030 36 19 7a db 56 43 26 f7 dc 42 57 33 22 ed 9d a4 |6.z.VC&..BW3"...|
00000040 9d 53 da f8 9d 4e 60 66 71 a0 2e 2e 00 05 00 00 |.S...N`fq.......|
00000050 05 ff 01 00 01 00 14 03 03 00 01 01 16 03 03 00 |................|
00000060 24 11 12 ff 28 10 14 4c e5 0e ad a7 fa f3 92 fb |$...(..L........|
00000070 13 7d ae f2 b2 4a 6b a1 9e 67 cf a8 f7 8c 6f a0 |.}...Jk..g....o.|
00000080 6c 30 0e 18 55 |l0..U|
>>> Flow 3 (client to server)
00000000 14 03 03 00 01 01 16 03 03 00 24 de 72 a3 15 54 |..........$.r..T|
00000010 7e 6d a0 ce 5c 38 5c f3 6f 49 00 ba fb c0 c2 cc |~m..\8\.oI......|
00000020 6f 29 00 39 f9 bf 77 07 57 f1 e4 cf 6e 0c a3 |o).9..w.W...n..|
00000000 14 03 03 00 01 01 16 03 03 00 24 0d 46 41 8b 24 |..........$.FA.$|
00000010 36 01 a9 fd 8b ec fc e6 b1 83 96 df 0d 3e 53 54 |6............>ST|
00000020 58 b8 43 f2 a6 25 5e 1a ae 19 9e d2 28 44 92 |X.C..%^.....(D.|
>>> Flow 4 (server to client)
00000000 17 03 03 00 21 b0 e7 1c af 33 cd 5e ad 24 cf a4 |....!....3.^.$..|
00000010 51 99 1a f6 65 1e f3 28 ec 83 93 25 3d 8f f9 57 |Q...e..(...%=..W|
00000020 cb ec 1f 4a 47 77 15 03 03 00 16 2b 87 cb 08 f7 |...JGw.....+....|
00000030 51 08 3b c9 73 f4 1f 22 ac 8c 7c 1a 2e 43 84 d7 |Q.;.s.."..|..C..|
00000040 ef |.|
00000000 17 03 03 00 21 c4 fb f6 53 bb 3e 04 cc 0b a0 03 |....!...S.>.....|
00000010 fa 49 96 da b5 8d b2 f2 e5 d8 f3 5c 27 57 4f 9c |.I.........\'WO.|
00000020 30 00 34 fc 52 92 15 03 03 00 16 a3 02 7a 50 d2 |0.4.R........zP.|
00000030 c6 b3 fc 69 8f e4 94 ae ab 22 ad 05 1d 15 69 b9 |...i....."....i.|
00000040 a5 |.|
......@@ -27,9 +27,8 @@ func Server(conn net.Conn, config *Config) *Conn {
// Client returns a new TLS client side connection
// using conn as the underlying transport.
// Client interprets a nil configuration as equivalent to
// the zero configuration; see the documentation of Config
// for the defaults.
// The config cannot be nil: users must set either ServerHostname or
// InsecureSkipVerify in the config.
func Client(conn net.Conn, config *Config) *Conn {
return &Conn{conn: conn, config: config, isClient: true}
}
......
......@@ -30,6 +30,13 @@ type AttributeTypeAndValue struct {
Value interface{}
}
// AttributeTypeAndValueSET represents a set of ASN.1 sequences of
// AttributeTypeAndValue sequences from RFC 2986 (PKCS #10).
type AttributeTypeAndValueSET struct {
Type asn1.ObjectIdentifier
Value [][]AttributeTypeAndValue `asn1:"set"`
}
// Extension represents the ASN.1 structure of the same name. See RFC
// 5280, section 4.2.
type Extension struct {
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build dragonfly freebsd linux openbsd netbsd
// +build dragonfly freebsd linux openbsd netbsd solaris
package x509
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment