Update go dependencies

This commit is contained in:
Manuel de Brito Fontes 2018-05-26 11:27:53 -04:00 committed by Manuel Alejandro de Brito Fontes
parent 15ffb51394
commit bb4d483837
No known key found for this signature in database
GPG key ID: 786136016A8BA02A
1621 changed files with 86368 additions and 284392 deletions

View file

@ -1,42 +0,0 @@
// Copyright 2012 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 !plan9
package fsnotify_test
import (
"log"
"github.com/fsnotify/fsnotify"
)
func ExampleNewWatcher() {
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
done := make(chan bool)
go func() {
for {
select {
case event := <-watcher.Events:
log.Println("event:", event)
if event.Op&fsnotify.Write == fsnotify.Write {
log.Println("modified file:", event.Name)
}
case err := <-watcher.Errors:
log.Println("error:", err)
}
}
}()
err = watcher.Add("/tmp/foo")
if err != nil {
log.Fatal(err)
}
<-done
}

View file

@ -1,70 +0,0 @@
// Copyright 2016 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 !plan9
package fsnotify
import (
"os"
"testing"
"time"
)
func TestEventStringWithValue(t *testing.T) {
for opMask, expectedString := range map[Op]string{
Chmod | Create: `"/usr/someFile": CREATE|CHMOD`,
Rename: `"/usr/someFile": RENAME`,
Remove: `"/usr/someFile": REMOVE`,
Write | Chmod: `"/usr/someFile": WRITE|CHMOD`,
} {
event := Event{Name: "/usr/someFile", Op: opMask}
if event.String() != expectedString {
t.Fatalf("Expected %s, got: %v", expectedString, event.String())
}
}
}
func TestEventOpStringWithValue(t *testing.T) {
expectedOpString := "WRITE|CHMOD"
event := Event{Name: "someFile", Op: Write | Chmod}
if event.Op.String() != expectedOpString {
t.Fatalf("Expected %s, got: %v", expectedOpString, event.Op.String())
}
}
func TestEventOpStringWithNoValue(t *testing.T) {
expectedOpString := ""
event := Event{Name: "testFile", Op: 0}
if event.Op.String() != expectedOpString {
t.Fatalf("Expected %s, got: %v", expectedOpString, event.Op.String())
}
}
// TestWatcherClose tests that the goroutine started by creating the watcher can be
// signalled to return at any time, even if there is no goroutine listening on the events
// or errors channels.
func TestWatcherClose(t *testing.T) {
t.Parallel()
name := tempMkFile(t, "")
w := newWatcher(t)
err := w.Add(name)
if err != nil {
t.Fatal(err)
}
err = os.Remove(name)
if err != nil {
t.Fatal(err)
}
// Allow the watcher to receive the event.
time.Sleep(time.Millisecond * 100)
err = w.Close()
if err != nil {
t.Fatal(err)
}
}

View file

@ -1,229 +0,0 @@
// 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.
// +build linux
package fsnotify
import (
"testing"
"time"
"golang.org/x/sys/unix"
)
type testFd [2]int
func makeTestFd(t *testing.T) testFd {
var tfd testFd
errno := unix.Pipe(tfd[:])
if errno != nil {
t.Fatalf("Failed to create pipe: %v", errno)
}
return tfd
}
func (tfd testFd) fd() int {
return tfd[0]
}
func (tfd testFd) closeWrite(t *testing.T) {
errno := unix.Close(tfd[1])
if errno != nil {
t.Fatalf("Failed to close write end of pipe: %v", errno)
}
}
func (tfd testFd) put(t *testing.T) {
buf := make([]byte, 10)
_, errno := unix.Write(tfd[1], buf)
if errno != nil {
t.Fatalf("Failed to write to pipe: %v", errno)
}
}
func (tfd testFd) get(t *testing.T) {
buf := make([]byte, 10)
_, errno := unix.Read(tfd[0], buf)
if errno != nil {
t.Fatalf("Failed to read from pipe: %v", errno)
}
}
func (tfd testFd) close() {
unix.Close(tfd[1])
unix.Close(tfd[0])
}
func makePoller(t *testing.T) (testFd, *fdPoller) {
tfd := makeTestFd(t)
poller, err := newFdPoller(tfd.fd())
if err != nil {
t.Fatalf("Failed to create poller: %v", err)
}
return tfd, poller
}
func TestPollerWithBadFd(t *testing.T) {
_, err := newFdPoller(-1)
if err != unix.EBADF {
t.Fatalf("Expected EBADF, got: %v", err)
}
}
func TestPollerWithData(t *testing.T) {
tfd, poller := makePoller(t)
defer tfd.close()
defer poller.close()
tfd.put(t)
ok, err := poller.wait()
if err != nil {
t.Fatalf("poller failed: %v", err)
}
if !ok {
t.Fatalf("expected poller to return true")
}
tfd.get(t)
}
func TestPollerWithWakeup(t *testing.T) {
tfd, poller := makePoller(t)
defer tfd.close()
defer poller.close()
err := poller.wake()
if err != nil {
t.Fatalf("wake failed: %v", err)
}
ok, err := poller.wait()
if err != nil {
t.Fatalf("poller failed: %v", err)
}
if ok {
t.Fatalf("expected poller to return false")
}
}
func TestPollerWithClose(t *testing.T) {
tfd, poller := makePoller(t)
defer tfd.close()
defer poller.close()
tfd.closeWrite(t)
ok, err := poller.wait()
if err != nil {
t.Fatalf("poller failed: %v", err)
}
if !ok {
t.Fatalf("expected poller to return true")
}
}
func TestPollerWithWakeupAndData(t *testing.T) {
tfd, poller := makePoller(t)
defer tfd.close()
defer poller.close()
tfd.put(t)
err := poller.wake()
if err != nil {
t.Fatalf("wake failed: %v", err)
}
// both data and wakeup
ok, err := poller.wait()
if err != nil {
t.Fatalf("poller failed: %v", err)
}
if !ok {
t.Fatalf("expected poller to return true")
}
// data is still in the buffer, wakeup is cleared
ok, err = poller.wait()
if err != nil {
t.Fatalf("poller failed: %v", err)
}
if !ok {
t.Fatalf("expected poller to return true")
}
tfd.get(t)
// data is gone, only wakeup now
err = poller.wake()
if err != nil {
t.Fatalf("wake failed: %v", err)
}
ok, err = poller.wait()
if err != nil {
t.Fatalf("poller failed: %v", err)
}
if ok {
t.Fatalf("expected poller to return false")
}
}
func TestPollerConcurrent(t *testing.T) {
tfd, poller := makePoller(t)
defer tfd.close()
defer poller.close()
oks := make(chan bool)
live := make(chan bool)
defer close(live)
go func() {
defer close(oks)
for {
ok, err := poller.wait()
if err != nil {
t.Fatalf("poller failed: %v", err)
}
oks <- ok
if !<-live {
return
}
}
}()
// Try a write
select {
case <-time.After(50 * time.Millisecond):
case <-oks:
t.Fatalf("poller did not wait")
}
tfd.put(t)
if !<-oks {
t.Fatalf("expected true")
}
tfd.get(t)
live <- true
// Try a wakeup
select {
case <-time.After(50 * time.Millisecond):
case <-oks:
t.Fatalf("poller did not wait")
}
err := poller.wake()
if err != nil {
t.Fatalf("wake failed: %v", err)
}
if <-oks {
t.Fatalf("expected false")
}
live <- true
// Try a close
select {
case <-time.After(50 * time.Millisecond):
case <-oks:
t.Fatalf("poller did not wait")
}
tfd.closeWrite(t)
if !<-oks {
t.Fatalf("expected true")
}
tfd.get(t)
}

View file

@ -1,449 +0,0 @@
// 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.
// +build linux
package fsnotify
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
func TestInotifyCloseRightAway(t *testing.T) {
w, err := NewWatcher()
if err != nil {
t.Fatalf("Failed to create watcher")
}
// Close immediately; it won't even reach the first unix.Read.
w.Close()
// Wait for the close to complete.
<-time.After(50 * time.Millisecond)
isWatcherReallyClosed(t, w)
}
func TestInotifyCloseSlightlyLater(t *testing.T) {
w, err := NewWatcher()
if err != nil {
t.Fatalf("Failed to create watcher")
}
// Wait until readEvents has reached unix.Read, and Close.
<-time.After(50 * time.Millisecond)
w.Close()
// Wait for the close to complete.
<-time.After(50 * time.Millisecond)
isWatcherReallyClosed(t, w)
}
func TestInotifyCloseSlightlyLaterWithWatch(t *testing.T) {
testDir := tempMkdir(t)
defer os.RemoveAll(testDir)
w, err := NewWatcher()
if err != nil {
t.Fatalf("Failed to create watcher")
}
w.Add(testDir)
// Wait until readEvents has reached unix.Read, and Close.
<-time.After(50 * time.Millisecond)
w.Close()
// Wait for the close to complete.
<-time.After(50 * time.Millisecond)
isWatcherReallyClosed(t, w)
}
func TestInotifyCloseAfterRead(t *testing.T) {
testDir := tempMkdir(t)
defer os.RemoveAll(testDir)
w, err := NewWatcher()
if err != nil {
t.Fatalf("Failed to create watcher")
}
err = w.Add(testDir)
if err != nil {
t.Fatalf("Failed to add .")
}
// Generate an event.
os.Create(filepath.Join(testDir, "somethingSOMETHINGsomethingSOMETHING"))
// Wait for readEvents to read the event, then close the watcher.
<-time.After(50 * time.Millisecond)
w.Close()
// Wait for the close to complete.
<-time.After(50 * time.Millisecond)
isWatcherReallyClosed(t, w)
}
func isWatcherReallyClosed(t *testing.T, w *Watcher) {
select {
case err, ok := <-w.Errors:
if ok {
t.Fatalf("w.Errors is not closed; readEvents is still alive after closing (error: %v)", err)
}
default:
t.Fatalf("w.Errors would have blocked; readEvents is still alive!")
}
select {
case _, ok := <-w.Events:
if ok {
t.Fatalf("w.Events is not closed; readEvents is still alive after closing")
}
default:
t.Fatalf("w.Events would have blocked; readEvents is still alive!")
}
}
func TestInotifyCloseCreate(t *testing.T) {
testDir := tempMkdir(t)
defer os.RemoveAll(testDir)
w, err := NewWatcher()
if err != nil {
t.Fatalf("Failed to create watcher: %v", err)
}
defer w.Close()
err = w.Add(testDir)
if err != nil {
t.Fatalf("Failed to add testDir: %v", err)
}
h, err := os.Create(filepath.Join(testDir, "testfile"))
if err != nil {
t.Fatalf("Failed to create file in testdir: %v", err)
}
h.Close()
select {
case _ = <-w.Events:
case err := <-w.Errors:
t.Fatalf("Error from watcher: %v", err)
case <-time.After(50 * time.Millisecond):
t.Fatalf("Took too long to wait for event")
}
// At this point, we've received one event, so the goroutine is ready.
// It's also blocking on unix.Read.
// Now we try to swap the file descriptor under its nose.
w.Close()
w, err = NewWatcher()
defer w.Close()
if err != nil {
t.Fatalf("Failed to create second watcher: %v", err)
}
<-time.After(50 * time.Millisecond)
err = w.Add(testDir)
if err != nil {
t.Fatalf("Error adding testDir again: %v", err)
}
}
// This test verifies the watcher can keep up with file creations/deletions
// when under load.
func TestInotifyStress(t *testing.T) {
maxNumToCreate := 1000
testDir := tempMkdir(t)
defer os.RemoveAll(testDir)
testFilePrefix := filepath.Join(testDir, "testfile")
w, err := NewWatcher()
if err != nil {
t.Fatalf("Failed to create watcher: %v", err)
}
defer w.Close()
err = w.Add(testDir)
if err != nil {
t.Fatalf("Failed to add testDir: %v", err)
}
doneChan := make(chan struct{})
// The buffer ensures that the file generation goroutine is never blocked.
errChan := make(chan error, 2*maxNumToCreate)
go func() {
for i := 0; i < maxNumToCreate; i++ {
testFile := fmt.Sprintf("%s%d", testFilePrefix, i)
handle, err := os.Create(testFile)
if err != nil {
errChan <- fmt.Errorf("Create failed: %v", err)
continue
}
err = handle.Close()
if err != nil {
errChan <- fmt.Errorf("Close failed: %v", err)
continue
}
}
// If we delete a newly created file too quickly, inotify will skip the
// create event and only send the delete event.
time.Sleep(100 * time.Millisecond)
for i := 0; i < maxNumToCreate; i++ {
testFile := fmt.Sprintf("%s%d", testFilePrefix, i)
err = os.Remove(testFile)
if err != nil {
errChan <- fmt.Errorf("Remove failed: %v", err)
}
}
close(doneChan)
}()
creates := 0
removes := 0
finished := false
after := time.After(10 * time.Second)
for !finished {
select {
case <-after:
t.Fatalf("Not done")
case <-doneChan:
finished = true
case err := <-errChan:
t.Fatalf("Got an error from file creator goroutine: %v", err)
case err := <-w.Errors:
t.Fatalf("Got an error from watcher: %v", err)
case evt := <-w.Events:
if !strings.HasPrefix(evt.Name, testFilePrefix) {
t.Fatalf("Got an event for an unknown file: %s", evt.Name)
}
if evt.Op == Create {
creates++
}
if evt.Op == Remove {
removes++
}
}
}
// Drain remaining events from channels
count := 0
for count < 10 {
select {
case err := <-errChan:
t.Fatalf("Got an error from file creator goroutine: %v", err)
case err := <-w.Errors:
t.Fatalf("Got an error from watcher: %v", err)
case evt := <-w.Events:
if !strings.HasPrefix(evt.Name, testFilePrefix) {
t.Fatalf("Got an event for an unknown file: %s", evt.Name)
}
if evt.Op == Create {
creates++
}
if evt.Op == Remove {
removes++
}
count = 0
default:
count++
// Give the watcher chances to fill the channels.
time.Sleep(time.Millisecond)
}
}
if creates-removes > 1 || creates-removes < -1 {
t.Fatalf("Creates and removes should not be off by more than one: %d creates, %d removes", creates, removes)
}
if creates < 50 {
t.Fatalf("Expected at least 50 creates, got %d", creates)
}
}
func TestInotifyRemoveTwice(t *testing.T) {
testDir := tempMkdir(t)
defer os.RemoveAll(testDir)
testFile := filepath.Join(testDir, "testfile")
handle, err := os.Create(testFile)
if err != nil {
t.Fatalf("Create failed: %v", err)
}
handle.Close()
w, err := NewWatcher()
if err != nil {
t.Fatalf("Failed to create watcher: %v", err)
}
defer w.Close()
err = w.Add(testFile)
if err != nil {
t.Fatalf("Failed to add testFile: %v", err)
}
err = w.Remove(testFile)
if err != nil {
t.Fatalf("wanted successful remove but got: %v", err)
}
err = w.Remove(testFile)
if err == nil {
t.Fatalf("no error on removing invalid file")
}
w.mu.Lock()
defer w.mu.Unlock()
if len(w.watches) != 0 {
t.Fatalf("Expected watches len is 0, but got: %d, %v", len(w.watches), w.watches)
}
if len(w.paths) != 0 {
t.Fatalf("Expected paths len is 0, but got: %d, %v", len(w.paths), w.paths)
}
}
func TestInotifyInnerMapLength(t *testing.T) {
testDir := tempMkdir(t)
defer os.RemoveAll(testDir)
testFile := filepath.Join(testDir, "testfile")
handle, err := os.Create(testFile)
if err != nil {
t.Fatalf("Create failed: %v", err)
}
handle.Close()
w, err := NewWatcher()
if err != nil {
t.Fatalf("Failed to create watcher: %v", err)
}
defer w.Close()
err = w.Add(testFile)
if err != nil {
t.Fatalf("Failed to add testFile: %v", err)
}
go func() {
for err := range w.Errors {
t.Fatalf("error received: %s", err)
}
}()
err = os.Remove(testFile)
if err != nil {
t.Fatalf("Failed to remove testFile: %v", err)
}
_ = <-w.Events // consume Remove event
<-time.After(50 * time.Millisecond) // wait IN_IGNORE propagated
w.mu.Lock()
defer w.mu.Unlock()
if len(w.watches) != 0 {
t.Fatalf("Expected watches len is 0, but got: %d, %v", len(w.watches), w.watches)
}
if len(w.paths) != 0 {
t.Fatalf("Expected paths len is 0, but got: %d, %v", len(w.paths), w.paths)
}
}
func TestInotifyOverflow(t *testing.T) {
// We need to generate many more events than the
// fs.inotify.max_queued_events sysctl setting.
// We use multiple goroutines (one per directory)
// to speed up file creation.
numDirs := 128
numFiles := 1024
testDir := tempMkdir(t)
defer os.RemoveAll(testDir)
w, err := NewWatcher()
if err != nil {
t.Fatalf("Failed to create watcher: %v", err)
}
defer w.Close()
for dn := 0; dn < numDirs; dn++ {
testSubdir := fmt.Sprintf("%s/%d", testDir, dn)
err := os.Mkdir(testSubdir, 0777)
if err != nil {
t.Fatalf("Cannot create subdir: %v", err)
}
err = w.Add(testSubdir)
if err != nil {
t.Fatalf("Failed to add subdir: %v", err)
}
}
errChan := make(chan error, numDirs*numFiles)
for dn := 0; dn < numDirs; dn++ {
testSubdir := fmt.Sprintf("%s/%d", testDir, dn)
go func() {
for fn := 0; fn < numFiles; fn++ {
testFile := fmt.Sprintf("%s/%d", testSubdir, fn)
handle, err := os.Create(testFile)
if err != nil {
errChan <- fmt.Errorf("Create failed: %v", err)
continue
}
err = handle.Close()
if err != nil {
errChan <- fmt.Errorf("Close failed: %v", err)
continue
}
}
}()
}
creates := 0
overflows := 0
after := time.After(10 * time.Second)
for overflows == 0 && creates < numDirs*numFiles {
select {
case <-after:
t.Fatalf("Not done")
case err := <-errChan:
t.Fatalf("Got an error from file creator goroutine: %v", err)
case err := <-w.Errors:
if err == ErrEventOverflow {
overflows++
} else {
t.Fatalf("Got an error from watcher: %v", err)
}
case evt := <-w.Events:
if !strings.HasPrefix(evt.Name, testDir) {
t.Fatalf("Got an event for an unknown file: %s", evt.Name)
}
if evt.Op == Create {
creates++
}
}
}
if creates == numDirs*numFiles {
t.Fatalf("Could not trigger overflow")
}
if overflows == 0 {
t.Fatalf("No overflow and not enough creates (expected %d, got %d)",
numDirs*numFiles, creates)
}
}

View file

@ -1,147 +0,0 @@
// Copyright 2016 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 fsnotify
import (
"os"
"path/filepath"
"testing"
"time"
"golang.org/x/sys/unix"
)
// testExchangedataForWatcher tests the watcher with the exchangedata operation on macOS.
//
// This is widely used for atomic saves on macOS, e.g. TextMate and in Apple's NSDocument.
//
// See https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/exchangedata.2.html
// Also see: https://github.com/textmate/textmate/blob/cd016be29489eba5f3c09b7b70b06da134dda550/Frameworks/io/src/swap_file_data.cc#L20
func testExchangedataForWatcher(t *testing.T, watchDir bool) {
// Create directory to watch
testDir1 := tempMkdir(t)
// For the intermediate file
testDir2 := tempMkdir(t)
defer os.RemoveAll(testDir1)
defer os.RemoveAll(testDir2)
resolvedFilename := "TestFsnotifyEvents.file"
// TextMate does:
//
// 1. exchangedata (intermediate, resolved)
// 2. unlink intermediate
//
// Let's try to simulate that:
resolved := filepath.Join(testDir1, resolvedFilename)
intermediate := filepath.Join(testDir2, resolvedFilename+"~")
// Make sure we create the file before we start watching
createAndSyncFile(t, resolved)
watcher := newWatcher(t)
// Test both variants in isolation
if watchDir {
addWatch(t, watcher, testDir1)
} else {
addWatch(t, watcher, resolved)
}
// Receive errors on the error channel on a separate goroutine
go func() {
for err := range watcher.Errors {
t.Fatalf("error received: %s", err)
}
}()
// Receive events on the event channel on a separate goroutine
eventstream := watcher.Events
var removeReceived counter
var createReceived counter
done := make(chan bool)
go func() {
for event := range eventstream {
// Only count relevant events
if event.Name == filepath.Clean(resolved) {
if event.Op&Remove == Remove {
removeReceived.increment()
}
if event.Op&Create == Create {
createReceived.increment()
}
}
t.Logf("event received: %s", event)
}
done <- true
}()
// Repeat to make sure the watched file/directory "survives" the REMOVE/CREATE loop.
for i := 1; i <= 3; i++ {
// The intermediate file is created in a folder outside the watcher
createAndSyncFile(t, intermediate)
// 1. Swap
if err := unix.Exchangedata(intermediate, resolved, 0); err != nil {
t.Fatalf("[%d] exchangedata failed: %s", i, err)
}
time.Sleep(50 * time.Millisecond)
// 2. Delete the intermediate file
err := os.Remove(intermediate)
if err != nil {
t.Fatalf("[%d] remove %s failed: %s", i, intermediate, err)
}
time.Sleep(50 * time.Millisecond)
}
// We expect this event to be received almost immediately, but let's wait 500 ms to be sure
time.Sleep(500 * time.Millisecond)
// The events will be (CHMOD + REMOVE + CREATE) X 2. Let's focus on the last two:
if removeReceived.value() < 3 {
t.Fatal("fsnotify remove events have not been received after 500 ms")
}
if createReceived.value() < 3 {
t.Fatal("fsnotify create events have not been received after 500 ms")
}
watcher.Close()
t.Log("waiting for the event channel to become closed...")
select {
case <-done:
t.Log("event channel closed")
case <-time.After(2 * time.Second):
t.Fatal("event stream was not closed after 2 seconds")
}
}
// TestExchangedataInWatchedDir test exchangedata operation on file in watched dir.
func TestExchangedataInWatchedDir(t *testing.T) {
testExchangedataForWatcher(t, true)
}
// TestExchangedataInWatchedDir test exchangedata operation on watched file.
func TestExchangedataInWatchedFile(t *testing.T) {
testExchangedataForWatcher(t, false)
}
func createAndSyncFile(t *testing.T, filepath string) {
f1, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
t.Fatalf("creating %s failed: %s", filepath, err)
}
f1.Sync()
f1.Close()
}

File diff suppressed because it is too large Load diff

View file

@ -1,172 +0,0 @@
package pool
import (
"sync"
"testing"
"time"
. "gopkg.in/go-playground/assert.v1"
)
// NOTES:
// - Run "go test" to run tests
// - Run "gocov test | gocov report" to report on test converage by file
// - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
//
// or
//
// -- may be a good idea to change to output path to somewherelike /tmp
// go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
//
func TestLimitedBatch(t *testing.T) {
newFunc := func(i int) func(WorkUnit) (interface{}, error) {
return func(WorkUnit) (interface{}, error) {
time.Sleep(time.Second * 1)
return i, nil
}
}
pool := NewLimited(4)
defer pool.Close()
batch := pool.Batch()
for i := 0; i < 4; i++ {
batch.Queue(newFunc(i))
}
batch.QueueComplete()
var count int
for range batch.Results() {
count++
}
Equal(t, count, 4)
}
func TestLimitedBatchGlobalPool(t *testing.T) {
newFunc := func(i int) func(WorkUnit) (interface{}, error) {
return func(WorkUnit) (interface{}, error) {
time.Sleep(time.Second * 1)
return i, nil
}
}
batch := limitedGpool.Batch()
for i := 0; i < 4; i++ {
batch.Queue(newFunc(i))
}
batch.QueueComplete()
var count int
for range batch.Results() {
count++
}
Equal(t, count, 4)
}
func TestLimitedBatchCancelItemsThrownAway(t *testing.T) {
newFunc := func(i int) func(WorkUnit) (interface{}, error) {
return func(WorkUnit) (interface{}, error) {
time.Sleep(time.Second * 1)
return i, nil
}
}
pool := NewLimited(4)
defer pool.Close()
batch := pool.Batch()
go func() {
for i := 0; i < 40; i++ {
batch.Queue(newFunc(i))
}
}()
batch.Cancel()
var count int
for range batch.Results() {
count++
}
NotEqual(t, count, 40)
}
func TestLimitedBatchCancelItemsCancelledAfterward(t *testing.T) {
newFunc := func(i int) func(WorkUnit) (interface{}, error) {
return func(WorkUnit) (interface{}, error) {
time.Sleep(time.Second * 1)
return i, nil
}
}
pool := NewLimited(4)
defer pool.Close()
batch := pool.Batch()
go func() {
for i := 0; i < 40; i++ {
batch.Queue(newFunc(i))
}
}()
time.Sleep(time.Second * 2)
batch.Cancel()
var count int
for range batch.Results() {
count++
}
Equal(t, count, 40)
}
func TestLimitedBatchWaitAll(t *testing.T) {
var count int
var m sync.Mutex
newFunc := func(i int) func(WorkUnit) (interface{}, error) {
return func(WorkUnit) (interface{}, error) {
time.Sleep(time.Second * 1)
m.Lock()
count++
m.Unlock()
return i, nil
}
}
pool := NewLimited(4)
defer pool.Close()
batch := pool.Batch()
go func() {
for i := 0; i < 10; i++ {
batch.Queue(newFunc(i))
}
batch.QueueComplete()
}()
batch.WaitAll()
Equal(t, count, 10)
}

View file

@ -1,172 +0,0 @@
package pool
import (
"sync"
"testing"
"time"
. "gopkg.in/go-playground/assert.v1"
)
// NOTES:
// - Run "go test" to run tests
// - Run "gocov test | gocov report" to report on test converage by file
// - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
//
// or
//
// -- may be a good idea to change to output path to somewherelike /tmp
// go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
//
func TestUnlimitedBatch(t *testing.T) {
newFunc := func(i int) func(WorkUnit) (interface{}, error) {
return func(WorkUnit) (interface{}, error) {
time.Sleep(time.Second * 1)
return i, nil
}
}
pool := New()
defer pool.Close()
batch := pool.Batch()
for i := 0; i < 4; i++ {
batch.Queue(newFunc(i))
}
batch.QueueComplete()
var count int
for range batch.Results() {
count++
}
Equal(t, count, 4)
}
func TestUnlimitedBatchGlobalPool(t *testing.T) {
newFunc := func(i int) func(WorkUnit) (interface{}, error) {
return func(WorkUnit) (interface{}, error) {
time.Sleep(time.Second * 1)
return i, nil
}
}
batch := unlimitedGpool.Batch()
for i := 0; i < 4; i++ {
batch.Queue(newFunc(i))
}
batch.QueueComplete()
var count int
for range batch.Results() {
count++
}
Equal(t, count, 4)
}
func TestUnlimitedBatchCancelItemsThrownAway(t *testing.T) {
newFunc := func(i int) func(WorkUnit) (interface{}, error) {
return func(WorkUnit) (interface{}, error) {
time.Sleep(time.Second * 1)
return i, nil
}
}
pool := New()
defer pool.Close()
batch := pool.Batch()
go func() {
for i := 0; i < 40; i++ {
batch.Queue(newFunc(i))
}
}()
batch.Cancel()
var count int
for range batch.Results() {
count++
}
NotEqual(t, count, 40)
}
func TestUnlimitedBatchCancelItemsCancelledAfterward(t *testing.T) {
newFunc := func(i int) func(WorkUnit) (interface{}, error) {
return func(WorkUnit) (interface{}, error) {
time.Sleep(time.Second * 1)
return i, nil
}
}
pool := New()
defer pool.Close()
batch := pool.Batch()
go func() {
for i := 0; i < 40; i++ {
batch.Queue(newFunc(i))
}
}()
time.Sleep(time.Second * 2)
batch.Cancel()
var count int
for range batch.Results() {
count++
}
Equal(t, count, 40)
}
func TestUnlimitedBatchWaitAll(t *testing.T) {
var count int
var m sync.Mutex
newFunc := func(i int) func(WorkUnit) (interface{}, error) {
return func(WorkUnit) (interface{}, error) {
time.Sleep(time.Second * 1)
m.Lock()
count++
m.Unlock()
return i, nil
}
}
pool := New()
defer pool.Close()
batch := pool.Batch()
go func() {
for i := 0; i < 10; i++ {
batch.Queue(newFunc(i))
}
batch.QueueComplete()
}()
batch.WaitAll()
Equal(t, count, 10)
}

View file

@ -1,185 +0,0 @@
package pool
import (
"testing"
"time"
)
func BenchmarkLimitedSmallRun(b *testing.B) {
res := make([]WorkUnit, 10)
b.ReportAllocs()
pool := NewLimited(10)
defer pool.Close()
fn := func(wu WorkUnit) (interface{}, error) {
time.Sleep(time.Millisecond * 500)
if wu.IsCancelled() {
return nil, nil
}
time.Sleep(time.Millisecond * 500)
return 1, nil
}
for i := 0; i < 10; i++ {
res[i] = pool.Queue(fn)
}
var count int
for _, cw := range res {
cw.Wait()
if cw.Error() == nil {
count += cw.Value().(int)
}
}
if count != 10 {
b.Fatal("Count Incorrect")
}
}
func BenchmarkLimitedSmallCancel(b *testing.B) {
res := make([]WorkUnit, 0, 20)
b.ReportAllocs()
pool := NewLimited(4)
defer pool.Close()
newFunc := func(i int) WorkFunc {
return func(wu WorkUnit) (interface{}, error) {
time.Sleep(time.Millisecond * 500)
if wu.IsCancelled() {
return nil, nil
}
time.Sleep(time.Millisecond * 500)
return i, nil
}
}
for i := 0; i < 20; i++ {
if i == 6 {
pool.Cancel()
}
res = append(res, pool.Queue(newFunc(i)))
}
for _, wrk := range res {
if wrk == nil {
continue
}
wrk.Wait()
}
}
func BenchmarkLimitedLargeCancel(b *testing.B) {
res := make([]WorkUnit, 0, 1000)
b.ReportAllocs()
pool := NewLimited(4)
defer pool.Close()
newFunc := func(i int) WorkFunc {
return func(wu WorkUnit) (interface{}, error) {
time.Sleep(time.Millisecond * 500)
if wu.IsCancelled() {
return nil, nil
}
time.Sleep(time.Millisecond * 500)
return i, nil
}
}
for i := 0; i < 1000; i++ {
if i == 6 {
pool.Cancel()
}
res = append(res, pool.Queue(newFunc(i)))
}
for _, wrk := range res {
if wrk == nil {
continue
}
wrk.Wait()
}
}
func BenchmarkLimitedOverconsumeLargeRun(b *testing.B) {
res := make([]WorkUnit, 100)
b.ReportAllocs()
pool := NewLimited(25)
defer pool.Close()
newFunc := func(i int) WorkFunc {
return func(wu WorkUnit) (interface{}, error) {
time.Sleep(time.Millisecond * 500)
if wu.IsCancelled() {
return nil, nil
}
time.Sleep(time.Millisecond * 500)
return 1, nil
}
}
for i := 0; i < 100; i++ {
res[i] = pool.Queue(newFunc(i))
}
var count int
for _, cw := range res {
cw.Wait()
count += cw.Value().(int)
}
if count != 100 {
b.Fatalf("Count Incorrect, Expected '100' Got '%d'", count)
}
}
func BenchmarkLimitedBatchSmallRun(b *testing.B) {
fn := func(wu WorkUnit) (interface{}, error) {
time.Sleep(time.Millisecond * 500)
if wu.IsCancelled() {
return nil, nil
}
time.Sleep(time.Millisecond * 500)
return 1, nil
}
pool := NewLimited(10)
defer pool.Close()
batch := pool.Batch()
for i := 0; i < 10; i++ {
batch.Queue(fn)
}
batch.QueueComplete()
var count int
for cw := range batch.Results() {
count += cw.Value().(int)
}
if count != 10 {
b.Fatal("Count Incorrect")
}
}

View file

@ -1,177 +0,0 @@
package pool
import (
"sync"
"testing"
"time"
. "gopkg.in/go-playground/assert.v1"
)
// NOTES:
// - Run "go test" to run tests
// - Run "gocov test | gocov report" to report on test converage by file
// - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
//
// or
//
// -- may be a good idea to change to output path to somewherelike /tmp
// go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
//
func TestPool(t *testing.T) {
var res []WorkUnit
pool := NewLimited(4)
defer pool.Close()
newFunc := func(d time.Duration) WorkFunc {
return func(WorkUnit) (interface{}, error) {
time.Sleep(d)
return nil, nil
}
}
for i := 0; i < 4; i++ {
wu := pool.Queue(newFunc(time.Second * 1))
res = append(res, wu)
}
var count int
for _, wu := range res {
wu.Wait()
Equal(t, wu.Error(), nil)
Equal(t, wu.Value(), nil)
count++
}
Equal(t, count, 4)
pool.Close() // testing no error occurs as Close will be called twice once defer pool.Close() fires
}
func TestCancel(t *testing.T) {
m := new(sync.RWMutex)
var closed bool
c := make(chan WorkUnit, 100)
pool := limitedGpool
defer pool.Close()
newFunc := func(d time.Duration) WorkFunc {
return func(WorkUnit) (interface{}, error) {
time.Sleep(d)
return 1, nil
}
}
go func(ch chan WorkUnit) {
for i := 0; i < 40; i++ {
go func(ch chan WorkUnit) {
m.RLock()
if closed {
m.RUnlock()
return
}
ch <- pool.Queue(newFunc(time.Second * 1))
m.RUnlock()
}(ch)
}
}(c)
time.Sleep(time.Second * 1)
pool.Cancel()
m.Lock()
closed = true
close(c)
m.Unlock()
var count int
for wu := range c {
wu.Wait()
if wu.Error() != nil {
_, ok := wu.Error().(*ErrCancelled)
if !ok {
_, ok = wu.Error().(*ErrPoolClosed)
if ok {
Equal(t, wu.Error().Error(), "ERROR: Work Unit added/run after the pool had been closed or cancelled")
}
} else {
Equal(t, wu.Error().Error(), "ERROR: Work Unit Cancelled")
}
Equal(t, ok, true)
continue
}
count += wu.Value().(int)
}
NotEqual(t, count, 40)
// reset and test again
pool.Reset()
wrk := pool.Queue(newFunc(time.Millisecond * 300))
wrk.Wait()
_, ok := wrk.Value().(int)
Equal(t, ok, true)
wrk = pool.Queue(newFunc(time.Millisecond * 300))
time.Sleep(time.Second * 1)
wrk.Cancel()
wrk.Wait() // proving we don't get stuck here after cancel
Equal(t, wrk.Error(), nil)
pool.Reset() // testing that we can do this and nothing bad will happen as it checks if pool closed
pool.Close()
wu := pool.Queue(newFunc(time.Second * 1))
wu.Wait()
NotEqual(t, wu.Error(), nil)
Equal(t, wu.Error().Error(), "ERROR: Work Unit added/run after the pool had been closed or cancelled")
}
func TestPanicRecovery(t *testing.T) {
pool := NewLimited(2)
defer pool.Close()
newFunc := func(d time.Duration, i int) WorkFunc {
return func(WorkUnit) (interface{}, error) {
if i == 1 {
panic("OMG OMG OMG! something bad happened!")
}
time.Sleep(d)
return 1, nil
}
}
var wrk WorkUnit
for i := 0; i < 4; i++ {
time.Sleep(time.Second * 1)
if i == 1 {
wrk = pool.Queue(newFunc(time.Second*1, i))
continue
}
pool.Queue(newFunc(time.Second*1, i))
}
wrk.Wait()
NotEqual(t, wrk.Error(), nil)
Equal(t, wrk.Error().Error()[0:90], "ERROR: Work Unit failed due to a recoverable error: 'OMG OMG OMG! something bad happened!'")
}
func TestBadWorkerCount(t *testing.T) {
PanicMatches(t, func() { NewLimited(0) }, "invalid workers '0'")
}

View file

@ -1,36 +0,0 @@
package pool
import (
"os"
"testing"
)
// NOTES:
// - Run "go test" to run tests
// - Run "gocov test | gocov report" to report on test converage by file
// - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
//
// or
//
// -- may be a good idea to change to output path to somewherelike /tmp
// go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
//
// global pool for testing long running pool
var limitedGpool Pool
var unlimitedGpool Pool
func TestMain(m *testing.M) {
// setup
limitedGpool = NewLimited(4)
defer limitedGpool.Close()
unlimitedGpool = New()
defer unlimitedGpool.Close()
os.Exit(m.Run())
// teardown
}

View file

@ -1,185 +0,0 @@
package pool
import (
"testing"
"time"
)
func BenchmarkUnlimitedSmallRun(b *testing.B) {
res := make([]WorkUnit, 10)
b.ReportAllocs()
pool := New()
defer pool.Close()
fn := func(wu WorkUnit) (interface{}, error) {
time.Sleep(time.Millisecond * 500)
if wu.IsCancelled() {
return nil, nil
}
time.Sleep(time.Millisecond * 500)
return 1, nil
}
for i := 0; i < 10; i++ {
res[i] = pool.Queue(fn)
}
var count int
for _, cw := range res {
cw.Wait()
if cw.Error() == nil {
count += cw.Value().(int)
}
}
if count != 10 {
b.Fatal("Count Incorrect")
}
}
func BenchmarkUnlimitedSmallCancel(b *testing.B) {
res := make([]WorkUnit, 0, 20)
b.ReportAllocs()
pool := New()
defer pool.Close()
newFunc := func(i int) WorkFunc {
return func(wu WorkUnit) (interface{}, error) {
time.Sleep(time.Millisecond * 500)
if wu.IsCancelled() {
return nil, nil
}
time.Sleep(time.Millisecond * 500)
return i, nil
}
}
for i := 0; i < 20; i++ {
if i == 6 {
pool.Cancel()
}
res = append(res, pool.Queue(newFunc(i)))
}
for _, wrk := range res {
if wrk == nil {
continue
}
wrk.Wait()
}
}
func BenchmarkUnlimitedLargeCancel(b *testing.B) {
res := make([]WorkUnit, 0, 1000)
b.ReportAllocs()
pool := New()
defer pool.Close()
newFunc := func(i int) WorkFunc {
return func(wu WorkUnit) (interface{}, error) {
time.Sleep(time.Millisecond * 500)
if wu.IsCancelled() {
return nil, nil
}
time.Sleep(time.Millisecond * 500)
return i, nil
}
}
for i := 0; i < 1000; i++ {
if i == 6 {
pool.Cancel()
}
res = append(res, pool.Queue(newFunc(i)))
}
for _, wrk := range res {
if wrk == nil {
continue
}
wrk.Wait()
}
}
func BenchmarkUnlimitedLargeRun(b *testing.B) {
res := make([]WorkUnit, 100)
b.ReportAllocs()
pool := New()
defer pool.Close()
newFunc := func(i int) WorkFunc {
return func(wu WorkUnit) (interface{}, error) {
time.Sleep(time.Millisecond * 500)
if wu.IsCancelled() {
return nil, nil
}
time.Sleep(time.Millisecond * 500)
return 1, nil
}
}
for i := 0; i < 100; i++ {
res[i] = pool.Queue(newFunc(i))
}
var count int
for _, cw := range res {
cw.Wait()
count += cw.Value().(int)
}
if count != 100 {
b.Fatalf("Count Incorrect, Expected '100' Got '%d'", count)
}
}
func BenchmarkUnlimitedBatchSmallRun(b *testing.B) {
fn := func(wu WorkUnit) (interface{}, error) {
time.Sleep(time.Millisecond * 500)
if wu.IsCancelled() {
return nil, nil
}
time.Sleep(time.Millisecond * 500)
return 1, nil
}
pool := New()
defer pool.Close()
batch := pool.Batch()
for i := 0; i < 10; i++ {
batch.Queue(fn)
}
batch.QueueComplete()
var count int
for cw := range batch.Results() {
count += cw.Value().(int)
}
if count != 10 {
b.Fatal("Count Incorrect")
}
}

View file

@ -1,194 +0,0 @@
package pool
import (
"sync"
"testing"
"time"
. "gopkg.in/go-playground/assert.v1"
)
// NOTES:
// - Run "go test" to run tests
// - Run "gocov test | gocov report" to report on test converage by file
// - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
//
// or
//
// -- may be a good idea to change to output path to somewherelike /tmp
// go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
//
func TestUnlimitedPool(t *testing.T) {
var res []WorkUnit
pool := New()
defer pool.Close()
newFunc := func(d time.Duration) WorkFunc {
return func(WorkUnit) (interface{}, error) {
time.Sleep(d)
return nil, nil
}
}
for i := 0; i < 4; i++ {
wu := pool.Queue(newFunc(time.Second * 1))
res = append(res, wu)
}
var count int
for _, wu := range res {
wu.Wait()
Equal(t, wu.Error(), nil)
Equal(t, wu.Value(), nil)
count++
}
Equal(t, count, 4)
pool.Close() // testing no error occurs as Close will be called twice once defer pool.Close() fires
}
func TestUnlimitedCancel(t *testing.T) {
m := new(sync.RWMutex)
var closed bool
c := make(chan WorkUnit, 100)
pool := unlimitedGpool
defer pool.Close()
newFunc := func(d time.Duration) WorkFunc {
return func(WorkUnit) (interface{}, error) {
time.Sleep(d)
return 1, nil
}
}
go func(ch chan WorkUnit) {
for i := 0; i < 40; i++ {
go func(ch chan WorkUnit) {
m.RLock()
if !closed {
ch <- pool.Queue(newFunc(time.Second * 1))
}
m.RUnlock()
}(ch)
}
}(c)
time.Sleep(time.Second * 1)
pool.Cancel()
m.Lock()
closed = true
close(c)
m.Unlock()
var count int
for wu := range c {
wu.Wait()
if wu.Error() != nil {
_, ok := wu.Error().(*ErrCancelled)
if !ok {
_, ok = wu.Error().(*ErrPoolClosed)
if ok {
Equal(t, wu.Error().Error(), "ERROR: Work Unit added/run after the pool had been closed or cancelled")
}
} else {
Equal(t, wu.Error().Error(), "ERROR: Work Unit Cancelled")
}
Equal(t, ok, true)
continue
}
count += wu.Value().(int)
}
NotEqual(t, count, 40)
// reset and test again
pool.Reset()
wrk := pool.Queue(newFunc(time.Millisecond * 300))
wrk.Wait()
_, ok := wrk.Value().(int)
Equal(t, ok, true)
wrk = pool.Queue(newFunc(time.Millisecond * 300))
time.Sleep(time.Second * 1)
wrk.Cancel()
wrk.Wait() // proving we don't get stuck here after cancel
Equal(t, wrk.Error(), nil)
pool.Reset() // testing that we can do this and nothing bad will happen as it checks if pool closed
pool.Close()
wu := pool.Queue(newFunc(time.Second * 1))
wu.Wait()
NotEqual(t, wu.Error(), nil)
Equal(t, wu.Error().Error(), "ERROR: Work Unit added/run after the pool had been closed or cancelled")
}
func TestCancelFromWithin(t *testing.T) {
pool := New()
defer pool.Close()
newFunc := func(d time.Duration) WorkFunc {
return func(wu WorkUnit) (interface{}, error) {
time.Sleep(d)
if wu.IsCancelled() {
return nil, nil
}
return 1, nil
}
}
q := pool.Queue(newFunc(time.Second * 5))
time.Sleep(time.Second * 2)
pool.Cancel()
Equal(t, q.Value() == nil, true)
NotEqual(t, q.Error(), nil)
Equal(t, q.Error().Error(), "ERROR: Work Unit Cancelled")
}
func TestUnlimitedPanicRecovery(t *testing.T) {
pool := New()
defer pool.Close()
newFunc := func(d time.Duration, i int) WorkFunc {
return func(WorkUnit) (interface{}, error) {
if i == 1 {
panic("OMG OMG OMG! something bad happened!")
}
time.Sleep(d)
return 1, nil
}
}
var wrk WorkUnit
for i := 0; i < 4; i++ {
time.Sleep(time.Second * 1)
if i == 1 {
wrk = pool.Queue(newFunc(time.Second*1, i))
continue
}
pool.Queue(newFunc(time.Second*1, i))
}
wrk.Wait()
NotEqual(t, wrk.Error(), nil)
Equal(t, wrk.Error().Error()[0:90], "ERROR: Work Unit failed due to a recoverable error: 'OMG OMG OMG! something bad happened!'")
}

View file

@ -1,210 +0,0 @@
package inf
import (
"fmt"
"math/big"
"math/rand"
"sync"
"testing"
)
const maxcap = 1024 * 1024
const bits = 256
const maxscale = 32
var once sync.Once
var decInput [][2]Dec
var intInput [][2]big.Int
var initBench = func() {
decInput = make([][2]Dec, maxcap)
intInput = make([][2]big.Int, maxcap)
max := new(big.Int).Lsh(big.NewInt(1), bits)
r := rand.New(rand.NewSource(0))
for i := 0; i < cap(decInput); i++ {
decInput[i][0].SetUnscaledBig(new(big.Int).Rand(r, max)).
SetScale(Scale(r.Int31n(int32(2*maxscale-1)) - int32(maxscale)))
decInput[i][1].SetUnscaledBig(new(big.Int).Rand(r, max)).
SetScale(Scale(r.Int31n(int32(2*maxscale-1)) - int32(maxscale)))
}
for i := 0; i < cap(intInput); i++ {
intInput[i][0].Rand(r, max)
intInput[i][1].Rand(r, max)
}
}
func doBenchmarkDec1(b *testing.B, f func(z *Dec)) {
once.Do(initBench)
b.ResetTimer()
b.StartTimer()
for i := 0; i < b.N; i++ {
f(&decInput[i%maxcap][0])
}
}
func doBenchmarkDec2(b *testing.B, f func(x, y *Dec)) {
once.Do(initBench)
b.ResetTimer()
b.StartTimer()
for i := 0; i < b.N; i++ {
f(&decInput[i%maxcap][0], &decInput[i%maxcap][1])
}
}
func doBenchmarkInt1(b *testing.B, f func(z *big.Int)) {
once.Do(initBench)
b.ResetTimer()
b.StartTimer()
for i := 0; i < b.N; i++ {
f(&intInput[i%maxcap][0])
}
}
func doBenchmarkInt2(b *testing.B, f func(x, y *big.Int)) {
once.Do(initBench)
b.ResetTimer()
b.StartTimer()
for i := 0; i < b.N; i++ {
f(&intInput[i%maxcap][0], &intInput[i%maxcap][1])
}
}
func Benchmark_Dec_String(b *testing.B) {
doBenchmarkDec1(b, func(x *Dec) {
x.String()
})
}
func Benchmark_Dec_StringScan(b *testing.B) {
doBenchmarkDec1(b, func(x *Dec) {
s := x.String()
d := new(Dec)
fmt.Sscan(s, d)
})
}
func Benchmark_Dec_GobEncode(b *testing.B) {
doBenchmarkDec1(b, func(x *Dec) {
x.GobEncode()
})
}
func Benchmark_Dec_GobEnDecode(b *testing.B) {
doBenchmarkDec1(b, func(x *Dec) {
g, _ := x.GobEncode()
new(Dec).GobDecode(g)
})
}
func Benchmark_Dec_Add(b *testing.B) {
doBenchmarkDec2(b, func(x, y *Dec) {
ys := y.Scale()
y.SetScale(x.Scale())
_ = new(Dec).Add(x, y)
y.SetScale(ys)
})
}
func Benchmark_Dec_AddMixed(b *testing.B) {
doBenchmarkDec2(b, func(x, y *Dec) {
_ = new(Dec).Add(x, y)
})
}
func Benchmark_Dec_Sub(b *testing.B) {
doBenchmarkDec2(b, func(x, y *Dec) {
ys := y.Scale()
y.SetScale(x.Scale())
_ = new(Dec).Sub(x, y)
y.SetScale(ys)
})
}
func Benchmark_Dec_SubMixed(b *testing.B) {
doBenchmarkDec2(b, func(x, y *Dec) {
_ = new(Dec).Sub(x, y)
})
}
func Benchmark_Dec_Mul(b *testing.B) {
doBenchmarkDec2(b, func(x, y *Dec) {
_ = new(Dec).Mul(x, y)
})
}
func Benchmark_Dec_Mul_QuoExact(b *testing.B) {
doBenchmarkDec2(b, func(x, y *Dec) {
v := new(Dec).Mul(x, y)
_ = new(Dec).QuoExact(v, y)
})
}
func Benchmark_Dec_QuoRound_Fixed_Down(b *testing.B) {
doBenchmarkDec2(b, func(x, y *Dec) {
_ = new(Dec).QuoRound(x, y, 0, RoundDown)
})
}
func Benchmark_Dec_QuoRound_Fixed_HalfUp(b *testing.B) {
doBenchmarkDec2(b, func(x, y *Dec) {
_ = new(Dec).QuoRound(x, y, 0, RoundHalfUp)
})
}
func Benchmark_Int_String(b *testing.B) {
doBenchmarkInt1(b, func(x *big.Int) {
x.String()
})
}
func Benchmark_Int_StringScan(b *testing.B) {
doBenchmarkInt1(b, func(x *big.Int) {
s := x.String()
d := new(big.Int)
fmt.Sscan(s, d)
})
}
func Benchmark_Int_GobEncode(b *testing.B) {
doBenchmarkInt1(b, func(x *big.Int) {
x.GobEncode()
})
}
func Benchmark_Int_GobEnDecode(b *testing.B) {
doBenchmarkInt1(b, func(x *big.Int) {
g, _ := x.GobEncode()
new(big.Int).GobDecode(g)
})
}
func Benchmark_Int_Add(b *testing.B) {
doBenchmarkInt2(b, func(x, y *big.Int) {
_ = new(big.Int).Add(x, y)
})
}
func Benchmark_Int_Sub(b *testing.B) {
doBenchmarkInt2(b, func(x, y *big.Int) {
_ = new(big.Int).Sub(x, y)
})
}
func Benchmark_Int_Mul(b *testing.B) {
doBenchmarkInt2(b, func(x, y *big.Int) {
_ = new(big.Int).Mul(x, y)
})
}
func Benchmark_Int_Quo(b *testing.B) {
doBenchmarkInt2(b, func(x, y *big.Int) {
_ = new(big.Int).Quo(x, y)
})
}
func Benchmark_Int_QuoRem(b *testing.B) {
doBenchmarkInt2(b, func(x, y *big.Int) {
_, _ = new(big.Int).QuoRem(x, y, new(big.Int))
})
}

2
vendor/gopkg.in/inf.v0/dec.go generated vendored
View file

@ -104,7 +104,7 @@ var bigInt = [...]*big.Int{
var exp10cache [64]big.Int = func() [64]big.Int {
e10, e10i := [64]big.Int{}, bigInt[1]
for i, _ := range e10 {
for i := range e10 {
e10[i].Set(e10i)
e10i = new(big.Int).Mul(e10i, bigInt[10])
}

View file

@ -1,33 +0,0 @@
// +build go1.2
package inf
import (
"encoding"
"encoding/json"
"testing"
)
var _ encoding.TextMarshaler = new(Dec)
var _ encoding.TextUnmarshaler = new(Dec)
type Obj struct {
Val *Dec
}
func TestDecJsonMarshalUnmarshal(t *testing.T) {
o := Obj{Val: NewDec(123, 2)}
js, err := json.Marshal(o)
if err != nil {
t.Fatalf("json.Marshal(%v): got %v, want ok", o, err)
}
o2 := &Obj{}
err = json.Unmarshal(js, o2)
if err != nil {
t.Fatalf("json.Unmarshal(%#q): got %v, want ok", js, err)
}
if o.Val.Scale() != o2.Val.Scale() ||
o.Val.UnscaledBig().Cmp(o2.Val.UnscaledBig()) != 0 {
t.Fatalf("json.Unmarshal(json.Marshal(%v)): want %v, got %v", o, o, o2)
}
}

View file

@ -1,40 +0,0 @@
package inf
import (
"math/big"
"testing"
)
var decQuoRemZZZ = []struct {
z, x, y *Dec
r *big.Rat
srA, srB int
}{
// basic examples
{NewDec(1, 0), NewDec(2, 0), NewDec(2, 0), big.NewRat(0, 1), 0, 1},
{NewDec(15, 1), NewDec(3, 0), NewDec(2, 0), big.NewRat(0, 1), 0, 1},
{NewDec(1, 1), NewDec(1, 0), NewDec(10, 0), big.NewRat(0, 1), 0, 1},
{NewDec(0, 0), NewDec(2, 0), NewDec(3, 0), big.NewRat(2, 3), 1, 1},
{NewDec(0, 0), NewDec(2, 0), NewDec(6, 0), big.NewRat(1, 3), 1, 1},
{NewDec(1, 1), NewDec(2, 0), NewDec(12, 0), big.NewRat(2, 3), 1, 1},
// examples from the Go Language Specification
{NewDec(1, 0), NewDec(5, 0), NewDec(3, 0), big.NewRat(2, 3), 1, 1},
{NewDec(-1, 0), NewDec(-5, 0), NewDec(3, 0), big.NewRat(-2, 3), -1, 1},
{NewDec(-1, 0), NewDec(5, 0), NewDec(-3, 0), big.NewRat(-2, 3), 1, -1},
{NewDec(1, 0), NewDec(-5, 0), NewDec(-3, 0), big.NewRat(2, 3), -1, -1},
}
func TestDecQuoRem(t *testing.T) {
for i, a := range decQuoRemZZZ {
z, rA, rB := new(Dec), new(big.Int), new(big.Int)
s := scaleQuoExact{}.Scale(a.x, a.y)
z.quoRem(a.x, a.y, s, true, rA, rB)
if a.z.Cmp(z) != 0 || a.r.Cmp(new(big.Rat).SetFrac(rA, rB)) != 0 {
t.Errorf("#%d QuoRemZZZ got %v, %v, %v; expected %v, %v", i, z, rA, rB, a.z, a.r)
}
if a.srA != rA.Sign() || a.srB != rB.Sign() {
t.Errorf("#%d QuoRemZZZ wrong signs, got %v, %v; expected %v, %v", i, rA.Sign(), rB.Sign(), a.srA, a.srB)
}
}
}

379
vendor/gopkg.in/inf.v0/dec_test.go generated vendored
View file

@ -1,379 +0,0 @@
package inf_test
import (
"bytes"
"encoding/gob"
"fmt"
"math/big"
"strings"
"testing"
"gopkg.in/inf.v0"
)
type decFunZZ func(z, x, y *inf.Dec) *inf.Dec
type decArgZZ struct {
z, x, y *inf.Dec
}
var decSumZZ = []decArgZZ{
{inf.NewDec(0, 0), inf.NewDec(0, 0), inf.NewDec(0, 0)},
{inf.NewDec(1, 0), inf.NewDec(1, 0), inf.NewDec(0, 0)},
{inf.NewDec(1111111110, 0), inf.NewDec(123456789, 0), inf.NewDec(987654321, 0)},
{inf.NewDec(-1, 0), inf.NewDec(-1, 0), inf.NewDec(0, 0)},
{inf.NewDec(864197532, 0), inf.NewDec(-123456789, 0), inf.NewDec(987654321, 0)},
{inf.NewDec(-1111111110, 0), inf.NewDec(-123456789, 0), inf.NewDec(-987654321, 0)},
{inf.NewDec(12, 2), inf.NewDec(1, 1), inf.NewDec(2, 2)},
}
var decProdZZ = []decArgZZ{
{inf.NewDec(0, 0), inf.NewDec(0, 0), inf.NewDec(0, 0)},
{inf.NewDec(0, 0), inf.NewDec(1, 0), inf.NewDec(0, 0)},
{inf.NewDec(1, 0), inf.NewDec(1, 0), inf.NewDec(1, 0)},
{inf.NewDec(-991*991, 0), inf.NewDec(991, 0), inf.NewDec(-991, 0)},
{inf.NewDec(2, 3), inf.NewDec(1, 1), inf.NewDec(2, 2)},
{inf.NewDec(2, -3), inf.NewDec(1, -1), inf.NewDec(2, -2)},
{inf.NewDec(2, 3), inf.NewDec(1, 1), inf.NewDec(2, 2)},
}
func TestDecSignZ(t *testing.T) {
var zero inf.Dec
for _, a := range decSumZZ {
s := a.z.Sign()
e := a.z.Cmp(&zero)
if s != e {
t.Errorf("got %d; want %d for z = %v", s, e, a.z)
}
}
}
func TestDecAbsZ(t *testing.T) {
var zero inf.Dec
for _, a := range decSumZZ {
var z inf.Dec
z.Abs(a.z)
var e inf.Dec
e.Set(a.z)
if e.Cmp(&zero) < 0 {
e.Sub(&zero, &e)
}
if z.Cmp(&e) != 0 {
t.Errorf("got z = %v; want %v", z, e)
}
}
}
func testDecFunZZ(t *testing.T, msg string, f decFunZZ, a decArgZZ) {
var z inf.Dec
f(&z, a.x, a.y)
if (&z).Cmp(a.z) != 0 {
t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z)
}
}
func TestDecSumZZ(t *testing.T) {
AddZZ := func(z, x, y *inf.Dec) *inf.Dec { return z.Add(x, y) }
SubZZ := func(z, x, y *inf.Dec) *inf.Dec { return z.Sub(x, y) }
for _, a := range decSumZZ {
arg := a
testDecFunZZ(t, "AddZZ", AddZZ, arg)
arg = decArgZZ{a.z, a.y, a.x}
testDecFunZZ(t, "AddZZ symmetric", AddZZ, arg)
arg = decArgZZ{a.x, a.z, a.y}
testDecFunZZ(t, "SubZZ", SubZZ, arg)
arg = decArgZZ{a.y, a.z, a.x}
testDecFunZZ(t, "SubZZ symmetric", SubZZ, arg)
}
}
func TestDecProdZZ(t *testing.T) {
MulZZ := func(z, x, y *inf.Dec) *inf.Dec { return z.Mul(x, y) }
for _, a := range decProdZZ {
arg := a
testDecFunZZ(t, "MulZZ", MulZZ, arg)
arg = decArgZZ{a.z, a.y, a.x}
testDecFunZZ(t, "MulZZ symmetric", MulZZ, arg)
}
}
var decUnscaledTests = []struct {
d *inf.Dec
u int64 // ignored when ok == false
ok bool
}{
{new(inf.Dec), 0, true},
{inf.NewDec(-1<<63, 0), -1 << 63, true},
{inf.NewDec(-(-1<<63 + 1), 0), -(-1<<63 + 1), true},
{new(inf.Dec).Neg(inf.NewDec(-1<<63, 0)), 0, false},
{new(inf.Dec).Sub(inf.NewDec(-1<<63, 0), inf.NewDec(1, 0)), 0, false},
{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), 0, false},
}
func TestDecUnscaled(t *testing.T) {
for i, tt := range decUnscaledTests {
u, ok := tt.d.Unscaled()
if ok != tt.ok {
t.Errorf("#%d Unscaled: got %v, expected %v", i, ok, tt.ok)
} else if ok && u != tt.u {
t.Errorf("#%d Unscaled: got %v, expected %v", i, u, tt.u)
}
}
}
var decRoundTests = [...]struct {
in *inf.Dec
s inf.Scale
r inf.Rounder
exp *inf.Dec
}{
{inf.NewDec(123424999999999993, 15), 2, inf.RoundHalfUp, inf.NewDec(12342, 2)},
{inf.NewDec(123425000000000001, 15), 2, inf.RoundHalfUp, inf.NewDec(12343, 2)},
{inf.NewDec(123424999999999993, 15), 15, inf.RoundHalfUp, inf.NewDec(123424999999999993, 15)},
{inf.NewDec(123424999999999993, 15), 16, inf.RoundHalfUp, inf.NewDec(1234249999999999930, 16)},
{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -1, inf.RoundHalfUp, inf.NewDec(1844674407370955162, -1)},
{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -2, inf.RoundHalfUp, inf.NewDec(184467440737095516, -2)},
{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -3, inf.RoundHalfUp, inf.NewDec(18446744073709552, -3)},
{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -4, inf.RoundHalfUp, inf.NewDec(1844674407370955, -4)},
{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -5, inf.RoundHalfUp, inf.NewDec(184467440737096, -5)},
{inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -6, inf.RoundHalfUp, inf.NewDec(18446744073710, -6)},
}
func TestDecRound(t *testing.T) {
for i, tt := range decRoundTests {
z := new(inf.Dec).Round(tt.in, tt.s, tt.r)
if tt.exp.Cmp(z) != 0 {
t.Errorf("#%d Round got %v; expected %v", i, z, tt.exp)
}
}
}
var decStringTests = []struct {
in string
out string
val int64
scale inf.Scale // skip SetString if negative
ok bool
scanOk bool
}{
{in: "", ok: false, scanOk: false},
{in: "a", ok: false, scanOk: false},
{in: "z", ok: false, scanOk: false},
{in: "+", ok: false, scanOk: false},
{in: "-", ok: false, scanOk: false},
{in: "g", ok: false, scanOk: false},
{in: ".", ok: false, scanOk: false},
{in: ".-0", ok: false, scanOk: false},
{in: ".+0", ok: false, scanOk: false},
// Scannable but not SetStringable
{"0b", "ignored", 0, 0, false, true},
{"0x", "ignored", 0, 0, false, true},
{"0xg", "ignored", 0, 0, false, true},
{"0.0g", "ignored", 0, 1, false, true},
// examples from godoc for Dec
{"0", "0", 0, 0, true, true},
{"0.00", "0.00", 0, 2, true, true},
{"ignored", "0", 0, -2, true, false},
{"1", "1", 1, 0, true, true},
{"1.00", "1.00", 100, 2, true, true},
{"10", "10", 10, 0, true, true},
{"ignored", "10", 1, -1, true, false},
// other tests
{"+0", "0", 0, 0, true, true},
{"-0", "0", 0, 0, true, true},
{"0.0", "0.0", 0, 1, true, true},
{"0.1", "0.1", 1, 1, true, true},
{"0.", "0", 0, 0, true, true},
{"-10", "-10", -1, -1, true, true},
{"-1", "-1", -1, 0, true, true},
{"-0.1", "-0.1", -1, 1, true, true},
{"-0.01", "-0.01", -1, 2, true, true},
{"+0.", "0", 0, 0, true, true},
{"-0.", "0", 0, 0, true, true},
{".0", "0.0", 0, 1, true, true},
{"+.0", "0.0", 0, 1, true, true},
{"-.0", "0.0", 0, 1, true, true},
{"0.0000000000", "0.0000000000", 0, 10, true, true},
{"0.0000000001", "0.0000000001", 1, 10, true, true},
{"-0.0000000000", "0.0000000000", 0, 10, true, true},
{"-0.0000000001", "-0.0000000001", -1, 10, true, true},
{"-10", "-10", -10, 0, true, true},
{"+10", "10", 10, 0, true, true},
{"00", "0", 0, 0, true, true},
{"023", "23", 23, 0, true, true}, // decimal, not octal
{"-02.3", "-2.3", -23, 1, true, true}, // decimal, not octal
}
func TestDecGetString(t *testing.T) {
z := new(inf.Dec)
for i, test := range decStringTests {
if !test.ok {
continue
}
z.SetUnscaled(test.val)
z.SetScale(test.scale)
s := z.String()
if s != test.out {
t.Errorf("#%da got %s; want %s", i, s, test.out)
}
s = fmt.Sprintf("%d", z)
if s != test.out {
t.Errorf("#%db got %s; want %s", i, s, test.out)
}
}
}
func TestDecSetString(t *testing.T) {
tmp := new(inf.Dec)
for i, test := range decStringTests {
if test.scale < 0 {
// SetString only supports scale >= 0
continue
}
// initialize to a non-zero value so that issues with parsing
// 0 are detected
tmp.Set(inf.NewDec(1234567890, 123))
n1, ok1 := new(inf.Dec).SetString(test.in)
n2, ok2 := tmp.SetString(test.in)
expected := inf.NewDec(test.val, test.scale)
if ok1 != test.ok || ok2 != test.ok {
t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
continue
}
if !ok1 {
if n1 != nil {
t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
}
continue
}
if !ok2 {
if n2 != nil {
t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
}
continue
}
if n1.Cmp(expected) != 0 {
t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
}
if n2.Cmp(expected) != 0 {
t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
}
}
}
func TestDecScan(t *testing.T) {
tmp := new(inf.Dec)
for i, test := range decStringTests {
if test.scale < 0 {
// SetString only supports scale >= 0
continue
}
// initialize to a non-zero value so that issues with parsing
// 0 are detected
tmp.Set(inf.NewDec(1234567890, 123))
n1, n2 := new(inf.Dec), tmp
nn1, err1 := fmt.Sscan(test.in, n1)
nn2, err2 := fmt.Sscan(test.in, n2)
if !test.scanOk {
if err1 == nil || err2 == nil {
t.Errorf("#%d (input '%s') ok incorrect, should be %t", i, test.in, test.scanOk)
}
continue
}
expected := inf.NewDec(test.val, test.scale)
if nn1 != 1 || err1 != nil || nn2 != 1 || err2 != nil {
t.Errorf("#%d (input '%s') error %d %v, %d %v", i, test.in, nn1, err1, nn2, err2)
continue
}
if n1.Cmp(expected) != 0 {
t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
}
if n2.Cmp(expected) != 0 {
t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
}
}
}
var decScanNextTests = []struct {
in string
ok bool
next rune
}{
{"", false, 0},
{"a", false, 'a'},
{"z", false, 'z'},
{"+", false, 0},
{"-", false, 0},
{"g", false, 'g'},
{".", false, 0},
{".-0", false, '-'},
{".+0", false, '+'},
{"0b", true, 'b'},
{"0x", true, 'x'},
{"0xg", true, 'x'},
{"0.0g", true, 'g'},
}
func TestDecScanNext(t *testing.T) {
for i, test := range decScanNextTests {
rdr := strings.NewReader(test.in)
n1 := new(inf.Dec)
nn1, _ := fmt.Fscan(rdr, n1)
if (test.ok && nn1 == 0) || (!test.ok && nn1 > 0) {
t.Errorf("#%d (input '%s') ok incorrect should be %t", i, test.in, test.ok)
continue
}
r := rune(0)
nn2, err := fmt.Fscanf(rdr, "%c", &r)
if test.next != r {
t.Errorf("#%d (input '%s') next incorrect, got %c should be %c, %d, %v", i, test.in, r, test.next, nn2, err)
}
}
}
var decGobEncodingTests = []string{
"0",
"1",
"2",
"10",
"42",
"1234567890",
"298472983472983471903246121093472394872319615612417471234712061",
}
func TestDecGobEncoding(t *testing.T) {
var medium bytes.Buffer
enc := gob.NewEncoder(&medium)
dec := gob.NewDecoder(&medium)
for i, test := range decGobEncodingTests {
for j := 0; j < 2; j++ {
for k := inf.Scale(-5); k <= 5; k++ {
medium.Reset() // empty buffer for each test case (in case of failures)
stest := test
if j != 0 {
// negative numbers
stest = "-" + test
}
var tx inf.Dec
tx.SetString(stest)
tx.SetScale(k) // test with positive, negative, and zero scale
if err := enc.Encode(&tx); err != nil {
t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err)
}
var rx inf.Dec
if err := dec.Decode(&rx); err != nil {
t.Errorf("#%d%c: decoding failed: %s", i, 'a'+j, err)
}
if rx.Cmp(&tx) != 0 {
t.Errorf("#%d%c: transmission failed: got %s want %s", i, 'a'+j, &rx, &tx)
}
}
}
}
}

View file

@ -1,62 +0,0 @@
package inf_test
import (
"fmt"
"log"
)
import "gopkg.in/inf.v0"
func ExampleDec_SetString() {
d := new(inf.Dec)
d.SetString("012345.67890") // decimal; leading 0 ignored; trailing 0 kept
fmt.Println(d)
// Output: 12345.67890
}
func ExampleDec_Scan() {
// The Scan function is rarely used directly;
// the fmt package recognizes it as an implementation of fmt.Scanner.
d := new(inf.Dec)
_, err := fmt.Sscan("184467440.73709551617", d)
if err != nil {
log.Println("error scanning value:", err)
} else {
fmt.Println(d)
}
// Output: 184467440.73709551617
}
func ExampleDec_QuoRound_scale2RoundDown() {
// 10 / 3 is an infinite decimal; it has no exact Dec representation
x, y := inf.NewDec(10, 0), inf.NewDec(3, 0)
// use 2 digits beyond the decimal point, round towards 0
z := new(inf.Dec).QuoRound(x, y, 2, inf.RoundDown)
fmt.Println(z)
// Output: 3.33
}
func ExampleDec_QuoRound_scale2RoundCeil() {
// -42 / 400 is an finite decimal with 3 digits beyond the decimal point
x, y := inf.NewDec(-42, 0), inf.NewDec(400, 0)
// use 2 digits beyond decimal point, round towards positive infinity
z := new(inf.Dec).QuoRound(x, y, 2, inf.RoundCeil)
fmt.Println(z)
// Output: -0.10
}
func ExampleDec_QuoExact_ok() {
// 1 / 25 is a finite decimal; it has exact Dec representation
x, y := inf.NewDec(1, 0), inf.NewDec(25, 0)
z := new(inf.Dec).QuoExact(x, y)
fmt.Println(z)
// Output: 0.04
}
func ExampleDec_QuoExact_fail() {
// 1 / 3 is an infinite decimal; it has no exact Dec representation
x, y := inf.NewDec(1, 0), inf.NewDec(3, 0)
z := new(inf.Dec).QuoExact(x, y)
fmt.Println(z)
// Output: <nil>
}

View file

@ -1,72 +0,0 @@
package inf_test
import (
"fmt"
"os"
"text/tabwriter"
"gopkg.in/inf.v0"
)
// This example displays the results of Dec.Round with each of the Rounders.
//
func ExampleRounder() {
var vals = []struct {
x string
s inf.Scale
}{
{"-0.18", 1}, {"-0.15", 1}, {"-0.12", 1}, {"-0.10", 1},
{"-0.08", 1}, {"-0.05", 1}, {"-0.02", 1}, {"0.00", 1},
{"0.02", 1}, {"0.05", 1}, {"0.08", 1}, {"0.10", 1},
{"0.12", 1}, {"0.15", 1}, {"0.18", 1},
}
var rounders = []struct {
name string
rounder inf.Rounder
}{
{"RoundDown", inf.RoundDown}, {"RoundUp", inf.RoundUp},
{"RoundCeil", inf.RoundCeil}, {"RoundFloor", inf.RoundFloor},
{"RoundHalfDown", inf.RoundHalfDown}, {"RoundHalfUp", inf.RoundHalfUp},
{"RoundHalfEven", inf.RoundHalfEven}, {"RoundExact", inf.RoundExact},
}
fmt.Println("The results of new(inf.Dec).Round(x, s, inf.RoundXXX):\n")
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', tabwriter.AlignRight)
fmt.Fprint(w, "x\ts\t|\t")
for _, r := range rounders {
fmt.Fprintf(w, "%s\t", r.name[5:])
}
fmt.Fprintln(w)
for _, v := range vals {
fmt.Fprintf(w, "%s\t%d\t|\t", v.x, v.s)
for _, r := range rounders {
x, _ := new(inf.Dec).SetString(v.x)
z := new(inf.Dec).Round(x, v.s, r.rounder)
fmt.Fprintf(w, "%d\t", z)
}
fmt.Fprintln(w)
}
w.Flush()
// Output:
// The results of new(inf.Dec).Round(x, s, inf.RoundXXX):
//
// x s | Down Up Ceil Floor HalfDown HalfUp HalfEven Exact
// -0.18 1 | -0.1 -0.2 -0.1 -0.2 -0.2 -0.2 -0.2 <nil>
// -0.15 1 | -0.1 -0.2 -0.1 -0.2 -0.1 -0.2 -0.2 <nil>
// -0.12 1 | -0.1 -0.2 -0.1 -0.2 -0.1 -0.1 -0.1 <nil>
// -0.10 1 | -0.1 -0.1 -0.1 -0.1 -0.1 -0.1 -0.1 -0.1
// -0.08 1 | 0.0 -0.1 0.0 -0.1 -0.1 -0.1 -0.1 <nil>
// -0.05 1 | 0.0 -0.1 0.0 -0.1 0.0 -0.1 0.0 <nil>
// -0.02 1 | 0.0 -0.1 0.0 -0.1 0.0 0.0 0.0 <nil>
// 0.00 1 | 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
// 0.02 1 | 0.0 0.1 0.1 0.0 0.0 0.0 0.0 <nil>
// 0.05 1 | 0.0 0.1 0.1 0.0 0.0 0.1 0.0 <nil>
// 0.08 1 | 0.0 0.1 0.1 0.0 0.1 0.1 0.1 <nil>
// 0.10 1 | 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
// 0.12 1 | 0.1 0.2 0.2 0.1 0.1 0.1 0.1 <nil>
// 0.15 1 | 0.1 0.2 0.2 0.1 0.1 0.2 0.2 <nil>
// 0.18 1 | 0.1 0.2 0.2 0.1 0.2 0.2 0.2 <nil>
}

View file

@ -1,109 +0,0 @@
package inf_test
import (
"math/big"
"testing"
"gopkg.in/inf.v0"
)
var decRounderInputs = [...]struct {
quo *inf.Dec
rA, rB *big.Int
}{
// examples from go language spec
{inf.NewDec(1, 0), big.NewInt(2), big.NewInt(3)}, // 5 / 3
{inf.NewDec(-1, 0), big.NewInt(-2), big.NewInt(3)}, // -5 / 3
{inf.NewDec(-1, 0), big.NewInt(2), big.NewInt(-3)}, // 5 / -3
{inf.NewDec(1, 0), big.NewInt(-2), big.NewInt(-3)}, // -5 / -3
// examples from godoc
{inf.NewDec(-1, 1), big.NewInt(-8), big.NewInt(10)},
{inf.NewDec(-1, 1), big.NewInt(-5), big.NewInt(10)},
{inf.NewDec(-1, 1), big.NewInt(-2), big.NewInt(10)},
{inf.NewDec(0, 1), big.NewInt(-8), big.NewInt(10)},
{inf.NewDec(0, 1), big.NewInt(-5), big.NewInt(10)},
{inf.NewDec(0, 1), big.NewInt(-2), big.NewInt(10)},
{inf.NewDec(0, 1), big.NewInt(0), big.NewInt(1)},
{inf.NewDec(0, 1), big.NewInt(2), big.NewInt(10)},
{inf.NewDec(0, 1), big.NewInt(5), big.NewInt(10)},
{inf.NewDec(0, 1), big.NewInt(8), big.NewInt(10)},
{inf.NewDec(1, 1), big.NewInt(2), big.NewInt(10)},
{inf.NewDec(1, 1), big.NewInt(5), big.NewInt(10)},
{inf.NewDec(1, 1), big.NewInt(8), big.NewInt(10)},
}
var decRounderResults = [...]struct {
rounder inf.Rounder
results [len(decRounderInputs)]*inf.Dec
}{
{inf.RoundExact, [...]*inf.Dec{nil, nil, nil, nil,
nil, nil, nil, nil, nil, nil,
inf.NewDec(0, 1), nil, nil, nil, nil, nil, nil}},
{inf.RoundDown, [...]*inf.Dec{
inf.NewDec(1, 0), inf.NewDec(-1, 0), inf.NewDec(-1, 0), inf.NewDec(1, 0),
inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1),
inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1),
inf.NewDec(0, 1),
inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1),
inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1)}},
{inf.RoundUp, [...]*inf.Dec{
inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0),
inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-2, 1),
inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1),
inf.NewDec(0, 1),
inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1),
inf.NewDec(2, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}},
{inf.RoundHalfDown, [...]*inf.Dec{
inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0),
inf.NewDec(-2, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1),
inf.NewDec(-1, 1), inf.NewDec(0, 1), inf.NewDec(0, 1),
inf.NewDec(0, 1),
inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(1, 1),
inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(2, 1)}},
{inf.RoundHalfUp, [...]*inf.Dec{
inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0),
inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-1, 1),
inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(0, 1),
inf.NewDec(0, 1),
inf.NewDec(0, 1), inf.NewDec(1, 1), inf.NewDec(1, 1),
inf.NewDec(1, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}},
{inf.RoundHalfEven, [...]*inf.Dec{
inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0),
inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-1, 1),
inf.NewDec(-1, 1), inf.NewDec(0, 1), inf.NewDec(0, 1),
inf.NewDec(0, 1),
inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(1, 1),
inf.NewDec(1, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}},
{inf.RoundFloor, [...]*inf.Dec{
inf.NewDec(1, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(1, 0),
inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-2, 1),
inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1),
inf.NewDec(0, 1),
inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1),
inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1)}},
{inf.RoundCeil, [...]*inf.Dec{
inf.NewDec(2, 0), inf.NewDec(-1, 0), inf.NewDec(-1, 0), inf.NewDec(2, 0),
inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1),
inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1),
inf.NewDec(0, 1),
inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1),
inf.NewDec(2, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}},
}
func TestDecRounders(t *testing.T) {
for i, a := range decRounderResults {
for j, input := range decRounderInputs {
q := new(inf.Dec).Set(input.quo)
rA, rB := new(big.Int).Set(input.rA), new(big.Int).Set(input.rB)
res := a.rounder.Round(new(inf.Dec), q, rA, rB)
if a.results[j] == nil && res == nil {
continue
}
if (a.results[j] == nil && res != nil) ||
(a.results[j] != nil && res == nil) ||
a.results[j].Cmp(res) != 0 {
t.Errorf("#%d,%d Rounder got %v; expected %v", i, j, res, a.results[j])
}
}
}
}

View file

@ -1,504 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jose
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"errors"
"io"
"math/big"
"testing"
)
func TestVectorsRSA(t *testing.T) {
// Sources:
// http://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-rsa-cryptography-standard.htm
// ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15crypt-vectors.txt
priv := &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: fromHexInt(`
a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8
ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0c
bc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bd
bf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93
ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb`),
E: 65537,
},
D: fromHexInt(`
53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf1195
17ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d
4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d6
5a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb
04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1`),
Primes: []*big.Int{
fromHexInt(`
d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262
864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c
2f26a471dcad212eac7ca39d`),
fromHexInt(`
cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb3
3d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af
72bfe9a030e860b0288b5d77`),
},
}
input := fromHexBytes(
"6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34")
expectedPKCS := fromHexBytes(`
50b4c14136bd198c2f3c3ed243fce036e168d56517984a263cd66492b808
04f169d210f2b9bdfb48b12f9ea05009c77da257cc600ccefe3a6283789d
8ea0e607ac58e2690ec4ebc10146e8cbaa5ed4d5cce6fe7b0ff9efc1eabb
564dbf498285f449ee61dd7b42ee5b5892cb90601f30cda07bf26489310b
cd23b528ceab3c31`)
expectedOAEP := fromHexBytes(`
354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad4
68fb21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618
c21a535fa9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e6
57a05a266426d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5
210035d47ac72e8a`)
// Mock random reader
randReader = bytes.NewReader(fromHexBytes(`
017341ae3875d5f87101f8cc4fa9b9bc156bb04628fccdb2f4f11e905bd3
a155d376f593bd7304210874eba08a5e22bcccb4c9d3882a93a54db022f5
03d16338b6b7ce16dc7f4bbf9a96b59772d6606e9747c7649bf9e083db98
1884a954ab3c6f18b776ea21069d69776a33e96bad48e1dda0a5ef`))
defer resetRandReader()
// RSA-PKCS1v1.5 encrypt
enc := new(rsaEncrypterVerifier)
enc.publicKey = &priv.PublicKey
encryptedPKCS, err := enc.encrypt(input, RSA1_5)
if err != nil {
t.Error("Encryption failed:", err)
return
}
if bytes.Compare(encryptedPKCS, expectedPKCS) != 0 {
t.Error("Output does not match expected value (PKCS1v1.5)")
}
// RSA-OAEP encrypt
encryptedOAEP, err := enc.encrypt(input, RSA_OAEP)
if err != nil {
t.Error("Encryption failed:", err)
return
}
if bytes.Compare(encryptedOAEP, expectedOAEP) != 0 {
t.Error("Output does not match expected value (OAEP)")
}
// Need fake cipher for PKCS1v1.5 decrypt
resetRandReader()
aes := newAESGCM(len(input))
keygen := randomKeyGenerator{
size: aes.keySize(),
}
// RSA-PKCS1v1.5 decrypt
dec := new(rsaDecrypterSigner)
dec.privateKey = priv
decryptedPKCS, err := dec.decrypt(encryptedPKCS, RSA1_5, keygen)
if err != nil {
t.Error("Decryption failed:", err)
return
}
if bytes.Compare(input, decryptedPKCS) != 0 {
t.Error("Output does not match expected value (PKCS1v1.5)")
}
// RSA-OAEP decrypt
decryptedOAEP, err := dec.decrypt(encryptedOAEP, RSA_OAEP, keygen)
if err != nil {
t.Error("decryption failed:", err)
return
}
if bytes.Compare(input, decryptedOAEP) != 0 {
t.Error("output does not match expected value (OAEP)")
}
}
func TestEd25519(t *testing.T) {
_, err := newEd25519Signer("XYZ", nil)
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
enc := new(edEncrypterVerifier)
enc.publicKey = ed25519PublicKey
err = enc.verifyPayload([]byte{}, []byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
dec := new(edDecrypterSigner)
dec.privateKey = ed25519PrivateKey
_, err = dec.signPayload([]byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
sig, err := dec.signPayload([]byte("This is a test"), "EdDSA")
if err != nil {
t.Error("should not error trying to sign payload")
}
if sig.Signature == nil {
t.Error("Check the signature")
}
err = enc.verifyPayload([]byte("This is a test"), sig.Signature, "EdDSA")
if err != nil {
t.Error("should not error trying to verify payload")
}
err = enc.verifyPayload([]byte("This is test number 2"), sig.Signature, "EdDSA")
if err == nil {
t.Error("should not error trying to verify payload")
}
}
func TestInvalidAlgorithmsRSA(t *testing.T) {
_, err := newRSARecipient("XYZ", nil)
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
_, err = newRSASigner("XYZ", nil)
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
enc := new(rsaEncrypterVerifier)
enc.publicKey = &rsaTestKey.PublicKey
_, err = enc.encryptKey([]byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
err = enc.verifyPayload([]byte{}, []byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
dec := new(rsaDecrypterSigner)
dec.privateKey = rsaTestKey
_, err = dec.decrypt(make([]byte, 256), "XYZ", randomKeyGenerator{size: 16})
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
_, err = dec.signPayload([]byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
}
type failingKeyGenerator struct{}
func (ctx failingKeyGenerator) keySize() int {
return 0
}
func (ctx failingKeyGenerator) genKey() ([]byte, rawHeader, error) {
return nil, rawHeader{}, errors.New("failed to generate key")
}
func TestPKCSKeyGeneratorFailure(t *testing.T) {
dec := new(rsaDecrypterSigner)
dec.privateKey = rsaTestKey
generator := failingKeyGenerator{}
_, err := dec.decrypt(make([]byte, 256), RSA1_5, generator)
if err != ErrCryptoFailure {
t.Error("should return error on invalid algorithm")
}
}
func TestInvalidAlgorithmsEC(t *testing.T) {
_, err := newECDHRecipient("XYZ", nil)
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
_, err = newECDSASigner("XYZ", nil)
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
enc := new(ecEncrypterVerifier)
enc.publicKey = &ecTestKey256.PublicKey
_, err = enc.encryptKey([]byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
}
func TestInvalidECKeyGen(t *testing.T) {
gen := ecKeyGenerator{
size: 16,
algID: "A128GCM",
publicKey: &ecTestKey256.PublicKey,
}
if gen.keySize() != 16 {
t.Error("ec key generator reported incorrect key size")
}
_, _, err := gen.genKey()
if err != nil {
t.Error("ec key generator failed to generate key", err)
}
}
func TestInvalidECDecrypt(t *testing.T) {
dec := ecDecrypterSigner{
privateKey: ecTestKey256,
}
generator := randomKeyGenerator{size: 16}
// Missing epk header
headers := rawHeader{}
headers.set(headerAlgorithm, ECDH_ES)
_, err := dec.decryptKey(headers, nil, generator)
if err == nil {
t.Error("ec decrypter accepted object with missing epk header")
}
// Invalid epk header
headers.set(headerEPK, &JSONWebKey{})
_, err = dec.decryptKey(headers, nil, generator)
if err == nil {
t.Error("ec decrypter accepted object with invalid epk header")
}
}
func TestDecryptWithIncorrectSize(t *testing.T) {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Error(err)
return
}
dec := new(rsaDecrypterSigner)
dec.privateKey = priv
aes := newAESGCM(16)
keygen := randomKeyGenerator{
size: aes.keySize(),
}
payload := make([]byte, 254)
_, err = dec.decrypt(payload, RSA1_5, keygen)
if err == nil {
t.Error("Invalid payload size should return error")
}
payload = make([]byte, 257)
_, err = dec.decrypt(payload, RSA1_5, keygen)
if err == nil {
t.Error("Invalid payload size should return error")
}
}
func TestPKCSDecryptNeverFails(t *testing.T) {
// We don't want RSA-PKCS1 v1.5 decryption to ever fail, in order to prevent
// side-channel timing attacks (Bleichenbacher attack in particular).
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Error(err)
return
}
dec := new(rsaDecrypterSigner)
dec.privateKey = priv
aes := newAESGCM(16)
keygen := randomKeyGenerator{
size: aes.keySize(),
}
for i := 1; i < 50; i++ {
payload := make([]byte, 256)
_, err := io.ReadFull(rand.Reader, payload)
if err != nil {
t.Error("Unable to get random data:", err)
return
}
_, err = dec.decrypt(payload, RSA1_5, keygen)
if err != nil {
t.Error("PKCS1v1.5 decrypt should never fail:", err)
return
}
}
}
func BenchmarkPKCSDecryptWithValidPayloads(b *testing.B) {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
enc := new(rsaEncrypterVerifier)
enc.publicKey = &priv.PublicKey
dec := new(rsaDecrypterSigner)
dec.privateKey = priv
aes := newAESGCM(32)
b.StopTimer()
b.ResetTimer()
for i := 0; i < b.N; i++ {
plaintext := make([]byte, 32)
_, err = io.ReadFull(rand.Reader, plaintext)
if err != nil {
panic(err)
}
ciphertext, err := enc.encrypt(plaintext, RSA1_5)
if err != nil {
panic(err)
}
keygen := randomKeyGenerator{
size: aes.keySize(),
}
b.StartTimer()
_, err = dec.decrypt(ciphertext, RSA1_5, keygen)
b.StopTimer()
if err != nil {
panic(err)
}
}
}
func BenchmarkPKCSDecryptWithInvalidPayloads(b *testing.B) {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
enc := new(rsaEncrypterVerifier)
enc.publicKey = &priv.PublicKey
dec := new(rsaDecrypterSigner)
dec.privateKey = priv
aes := newAESGCM(16)
keygen := randomKeyGenerator{
size: aes.keySize(),
}
b.StopTimer()
b.ResetTimer()
for i := 0; i < b.N; i++ {
plaintext := make([]byte, 16)
_, err = io.ReadFull(rand.Reader, plaintext)
if err != nil {
panic(err)
}
ciphertext, err := enc.encrypt(plaintext, RSA1_5)
if err != nil {
panic(err)
}
// Do some simple scrambling
ciphertext[128] ^= 0xFF
b.StartTimer()
_, err = dec.decrypt(ciphertext, RSA1_5, keygen)
b.StopTimer()
if err != nil {
panic(err)
}
}
}
func TestInvalidEllipticCurve(t *testing.T) {
signer256 := ecDecrypterSigner{privateKey: ecTestKey256}
signer384 := ecDecrypterSigner{privateKey: ecTestKey384}
signer521 := ecDecrypterSigner{privateKey: ecTestKey521}
_, err := signer256.signPayload([]byte{}, ES384)
if err == nil {
t.Error("should not generate ES384 signature with P-256 key")
}
_, err = signer256.signPayload([]byte{}, ES512)
if err == nil {
t.Error("should not generate ES512 signature with P-256 key")
}
_, err = signer384.signPayload([]byte{}, ES256)
if err == nil {
t.Error("should not generate ES256 signature with P-384 key")
}
_, err = signer384.signPayload([]byte{}, ES512)
if err == nil {
t.Error("should not generate ES512 signature with P-384 key")
}
_, err = signer521.signPayload([]byte{}, ES256)
if err == nil {
t.Error("should not generate ES256 signature with P-521 key")
}
_, err = signer521.signPayload([]byte{}, ES384)
if err == nil {
t.Error("should not generate ES384 signature with P-521 key")
}
}
func estInvalidECPublicKey(t *testing.T) {
// Invalid key
invalid := &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: elliptic.P256(),
X: fromBase64Int("MTEx"),
Y: fromBase64Int("MTEx"),
},
D: fromBase64Int("0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo"),
}
headers := rawHeader{}
headers.set(headerAlgorithm, ECDH_ES)
headers.set(headerEPK, &JSONWebKey{
Key: &invalid.PublicKey,
})
dec := ecDecrypterSigner{
privateKey: ecTestKey256,
}
_, err := dec.decryptKey(headers, nil, randomKeyGenerator{size: 16})
if err == nil {
t.Fatal("decrypter accepted JWS with invalid ECDH public key")
}
}
func TestInvalidAlgorithmEC(t *testing.T) {
err := ecEncrypterVerifier{publicKey: &ecTestKey256.PublicKey}.verifyPayload([]byte{}, []byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Fatal("should not accept invalid/unsupported algorithm")
}
}

View file

@ -1,498 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package josecipher
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
"strings"
"testing"
)
func TestInvalidInputs(t *testing.T) {
key := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}
nonce := []byte{
92, 80, 104, 49, 133, 25, 161, 215, 173, 101, 219, 211, 136, 91, 210, 145}
aead, _ := NewCBCHMAC(key, aes.NewCipher)
ciphertext := aead.Seal(nil, nonce, []byte("plaintext"), []byte("aad"))
// Changed AAD, must fail
_, err := aead.Open(nil, nonce, ciphertext, []byte("INVALID"))
if err == nil {
t.Error("must detect invalid aad")
}
// Empty ciphertext, must fail
_, err = aead.Open(nil, nonce, []byte{}, []byte("aad"))
if err == nil {
t.Error("must detect invalid/empty ciphertext")
}
// Corrupt ciphertext, must fail
corrupt := make([]byte, len(ciphertext))
copy(corrupt, ciphertext)
corrupt[0] ^= 0xFF
_, err = aead.Open(nil, nonce, corrupt, []byte("aad"))
if err == nil {
t.Error("must detect corrupt ciphertext")
}
// Corrupt authtag, must fail
copy(corrupt, ciphertext)
corrupt[len(ciphertext)-1] ^= 0xFF
_, err = aead.Open(nil, nonce, corrupt, []byte("aad"))
if err == nil {
t.Error("must detect corrupt authtag")
}
// Truncated data, must fail
_, err = aead.Open(nil, nonce, ciphertext[:10], []byte("aad"))
if err == nil {
t.Error("must detect corrupt authtag")
}
}
func TestVectorsAESCBC128(t *testing.T) {
// Source: http://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-29#appendix-A.2
plaintext := []byte{
76, 105, 118, 101, 32, 108, 111, 110, 103, 32, 97, 110, 100, 32,
112, 114, 111, 115, 112, 101, 114, 46}
aad := []byte{
101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 48, 69,
120, 88, 122, 85, 105, 76, 67, 74, 108, 98, 109, 77, 105, 79, 105,
74, 66, 77, 84, 73, 52, 81, 48, 74, 68, 76, 85, 104, 84, 77, 106, 85,
50, 73, 110, 48}
expectedCiphertext := []byte{
40, 57, 83, 181, 119, 33, 133, 148, 198, 185, 243, 24, 152, 230, 6,
75, 129, 223, 127, 19, 210, 82, 183, 230, 168, 33, 215, 104, 143,
112, 56, 102}
expectedAuthtag := []byte{
246, 17, 244, 190, 4, 95, 98, 3, 231, 0, 115, 157, 242, 203, 100,
191}
key := []byte{
4, 211, 31, 197, 84, 157, 252, 254, 11, 100, 157, 250, 63, 170, 106, 206,
107, 124, 212, 45, 111, 107, 9, 219, 200, 177, 0, 240, 143, 156, 44, 207}
nonce := []byte{
3, 22, 60, 12, 43, 67, 104, 105, 108, 108, 105, 99, 111, 116, 104, 101}
enc, err := NewCBCHMAC(key, aes.NewCipher)
out := enc.Seal(nil, nonce, plaintext, aad)
if err != nil {
t.Error("Unable to encrypt:", err)
return
}
if bytes.Compare(out[:len(out)-16], expectedCiphertext) != 0 {
t.Error("Ciphertext did not match")
}
if bytes.Compare(out[len(out)-16:], expectedAuthtag) != 0 {
t.Error("Auth tag did not match")
}
}
func TestVectorsAESCBC256(t *testing.T) {
// Source: https://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05#section-5.4
plaintext := []byte{
0x41, 0x20, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
0x6d, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75,
0x69, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65,
0x74, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62,
0x65, 0x20, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x20, 0x69,
0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x6f, 0x66,
0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x65, 0x6d, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f,
0x75, 0x74, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x6e, 0x69, 0x65, 0x6e, 0x63, 0x65}
aad := []byte{
0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x63,
0x69, 0x70, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x65, 0x20,
0x4b, 0x65, 0x72, 0x63, 0x6b, 0x68, 0x6f, 0x66, 0x66, 0x73}
expectedCiphertext := []byte{
0x4a, 0xff, 0xaa, 0xad, 0xb7, 0x8c, 0x31, 0xc5, 0xda, 0x4b, 0x1b, 0x59, 0x0d, 0x10, 0xff, 0xbd,
0x3d, 0xd8, 0xd5, 0xd3, 0x02, 0x42, 0x35, 0x26, 0x91, 0x2d, 0xa0, 0x37, 0xec, 0xbc, 0xc7, 0xbd,
0x82, 0x2c, 0x30, 0x1d, 0xd6, 0x7c, 0x37, 0x3b, 0xcc, 0xb5, 0x84, 0xad, 0x3e, 0x92, 0x79, 0xc2,
0xe6, 0xd1, 0x2a, 0x13, 0x74, 0xb7, 0x7f, 0x07, 0x75, 0x53, 0xdf, 0x82, 0x94, 0x10, 0x44, 0x6b,
0x36, 0xeb, 0xd9, 0x70, 0x66, 0x29, 0x6a, 0xe6, 0x42, 0x7e, 0xa7, 0x5c, 0x2e, 0x08, 0x46, 0xa1,
0x1a, 0x09, 0xcc, 0xf5, 0x37, 0x0d, 0xc8, 0x0b, 0xfe, 0xcb, 0xad, 0x28, 0xc7, 0x3f, 0x09, 0xb3,
0xa3, 0xb7, 0x5e, 0x66, 0x2a, 0x25, 0x94, 0x41, 0x0a, 0xe4, 0x96, 0xb2, 0xe2, 0xe6, 0x60, 0x9e,
0x31, 0xe6, 0xe0, 0x2c, 0xc8, 0x37, 0xf0, 0x53, 0xd2, 0x1f, 0x37, 0xff, 0x4f, 0x51, 0x95, 0x0b,
0xbe, 0x26, 0x38, 0xd0, 0x9d, 0xd7, 0xa4, 0x93, 0x09, 0x30, 0x80, 0x6d, 0x07, 0x03, 0xb1, 0xf6}
expectedAuthtag := []byte{
0x4d, 0xd3, 0xb4, 0xc0, 0x88, 0xa7, 0xf4, 0x5c, 0x21, 0x68, 0x39, 0x64, 0x5b, 0x20, 0x12, 0xbf,
0x2e, 0x62, 0x69, 0xa8, 0xc5, 0x6a, 0x81, 0x6d, 0xbc, 0x1b, 0x26, 0x77, 0x61, 0x95, 0x5b, 0xc5}
key := []byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}
nonce := []byte{
0x1a, 0xf3, 0x8c, 0x2d, 0xc2, 0xb9, 0x6f, 0xfd, 0xd8, 0x66, 0x94, 0x09, 0x23, 0x41, 0xbc, 0x04}
enc, err := NewCBCHMAC(key, aes.NewCipher)
out := enc.Seal(nil, nonce, plaintext, aad)
if err != nil {
t.Error("Unable to encrypt:", err)
return
}
if bytes.Compare(out[:len(out)-32], expectedCiphertext) != 0 {
t.Error("Ciphertext did not match, got", out[:len(out)-32], "wanted", expectedCiphertext)
}
if bytes.Compare(out[len(out)-32:], expectedAuthtag) != 0 {
t.Error("Auth tag did not match, got", out[len(out)-32:], "wanted", expectedAuthtag)
}
}
func TestAESCBCRoundtrip(t *testing.T) {
key128 := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
key192 := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7}
key256 := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
nonce := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
RunRoundtrip(t, key128, nonce)
RunRoundtrip(t, key192, nonce)
RunRoundtrip(t, key256, nonce)
}
func RunRoundtrip(t *testing.T, key, nonce []byte) {
aead, err := NewCBCHMAC(key, aes.NewCipher)
if err != nil {
panic(err)
}
if aead.NonceSize() != len(nonce) {
panic("invalid nonce")
}
// Test pre-existing data in dst buffer
dst := []byte{15, 15, 15, 15}
plaintext := []byte{0, 0, 0, 0}
aad := []byte{4, 3, 2, 1}
result := aead.Seal(dst, nonce, plaintext, aad)
if bytes.Compare(dst, result[:4]) != 0 {
t.Error("Existing data in dst not preserved")
}
// Test pre-existing (empty) dst buffer with sufficient capacity
dst = make([]byte, 256)[:0]
result, err = aead.Open(dst, nonce, result[4:], aad)
if err != nil {
panic(err)
}
if bytes.Compare(result, plaintext) != 0 {
t.Error("Plaintext does not match output")
}
}
func TestAESCBCOverhead(t *testing.T) {
aead, err := NewCBCHMAC(make([]byte, 32), aes.NewCipher)
if err != nil {
panic(err)
}
if aead.Overhead() != 32 {
t.Error("CBC-HMAC reports incorrect overhead value")
}
}
func TestPadding(t *testing.T) {
for i := 0; i < 256; i++ {
slice := make([]byte, i)
padded := padBuffer(slice, 16)
if len(padded)%16 != 0 {
t.Error("failed to pad slice properly", i)
return
}
unpadded, err := unpadBuffer(padded, 16)
if err != nil || len(unpadded) != i {
t.Error("failed to unpad slice properly", i)
return
}
}
}
func TestInvalidKey(t *testing.T) {
key := make([]byte, 30)
_, err := NewCBCHMAC(key, aes.NewCipher)
if err == nil {
t.Error("should not be able to instantiate CBC-HMAC with invalid key")
}
}
func TestTruncatedCiphertext(t *testing.T) {
key := make([]byte, 32)
nonce := make([]byte, 16)
data := make([]byte, 32)
io.ReadFull(rand.Reader, key)
io.ReadFull(rand.Reader, nonce)
aead, err := NewCBCHMAC(key, aes.NewCipher)
if err != nil {
panic(err)
}
ctx := aead.(*cbcAEAD)
ct := aead.Seal(nil, nonce, data, nil)
// Truncated ciphertext, but with correct auth tag
truncated, tail := resize(ct[:len(ct)-ctx.authtagBytes-2], uint64(len(ct))-2)
copy(tail, ctx.computeAuthTag(nil, nonce, truncated[:len(truncated)-ctx.authtagBytes]))
// Open should fail
_, err = aead.Open(nil, nonce, truncated, nil)
if err == nil {
t.Error("open on truncated ciphertext should fail")
}
}
func TestInvalidPaddingOpen(t *testing.T) {
key := make([]byte, 32)
nonce := make([]byte, 16)
// Plaintext with invalid padding
plaintext := padBuffer(make([]byte, 28), aes.BlockSize)
plaintext[len(plaintext)-1] = 0xFF
io.ReadFull(rand.Reader, key)
io.ReadFull(rand.Reader, nonce)
block, _ := aes.NewCipher(key)
cbc := cipher.NewCBCEncrypter(block, nonce)
buffer := append([]byte{}, plaintext...)
cbc.CryptBlocks(buffer, buffer)
aead, _ := NewCBCHMAC(key, aes.NewCipher)
ctx := aead.(*cbcAEAD)
// Mutated ciphertext, but with correct auth tag
size := uint64(len(buffer))
ciphertext, tail := resize(buffer, size+(uint64(len(key))/2))
copy(tail, ctx.computeAuthTag(nil, nonce, ciphertext[:size]))
// Open should fail (b/c of invalid padding, even though tag matches)
_, err := aead.Open(nil, nonce, ciphertext, nil)
if err == nil || !strings.Contains(err.Error(), "invalid padding") {
t.Error("no or unexpected error on open with invalid padding:", err)
}
}
func TestInvalidPadding(t *testing.T) {
for i := 0; i < 256; i++ {
slice := make([]byte, i)
padded := padBuffer(slice, 16)
if len(padded)%16 != 0 {
t.Error("failed to pad slice properly", i)
return
}
paddingBytes := 16 - (i % 16)
// Mutate padding for testing
for j := 1; j <= paddingBytes; j++ {
mutated := make([]byte, len(padded))
copy(mutated, padded)
mutated[len(mutated)-j] ^= 0xFF
_, err := unpadBuffer(mutated, 16)
if err == nil {
t.Error("unpad on invalid padding should fail", i)
return
}
}
// Test truncated padding
_, err := unpadBuffer(padded[:len(padded)-1], 16)
if err == nil {
t.Error("unpad on truncated padding should fail", i)
return
}
}
}
func TestZeroLengthPadding(t *testing.T) {
data := make([]byte, 16)
data, err := unpadBuffer(data, 16)
if err == nil {
t.Error("padding with 0x00 should never be valid")
}
}
func benchEncryptCBCHMAC(b *testing.B, keySize, chunkSize int) {
key := make([]byte, keySize*2)
nonce := make([]byte, 16)
io.ReadFull(rand.Reader, key)
io.ReadFull(rand.Reader, nonce)
chunk := make([]byte, chunkSize)
aead, err := NewCBCHMAC(key, aes.NewCipher)
if err != nil {
panic(err)
}
b.SetBytes(int64(chunkSize))
b.ResetTimer()
for i := 0; i < b.N; i++ {
aead.Seal(nil, nonce, chunk, nil)
}
}
func benchDecryptCBCHMAC(b *testing.B, keySize, chunkSize int) {
key := make([]byte, keySize*2)
nonce := make([]byte, 16)
io.ReadFull(rand.Reader, key)
io.ReadFull(rand.Reader, nonce)
chunk := make([]byte, chunkSize)
aead, err := NewCBCHMAC(key, aes.NewCipher)
if err != nil {
panic(err)
}
out := aead.Seal(nil, nonce, chunk, nil)
b.SetBytes(int64(chunkSize))
b.ResetTimer()
for i := 0; i < b.N; i++ {
aead.Open(nil, nonce, out, nil)
}
}
func BenchmarkEncryptAES128_CBCHMAC_1k(b *testing.B) {
benchEncryptCBCHMAC(b, 16, 1024)
}
func BenchmarkEncryptAES128_CBCHMAC_64k(b *testing.B) {
benchEncryptCBCHMAC(b, 16, 65536)
}
func BenchmarkEncryptAES128_CBCHMAC_1MB(b *testing.B) {
benchEncryptCBCHMAC(b, 16, 1048576)
}
func BenchmarkEncryptAES128_CBCHMAC_64MB(b *testing.B) {
benchEncryptCBCHMAC(b, 16, 67108864)
}
func BenchmarkDecryptAES128_CBCHMAC_1k(b *testing.B) {
benchDecryptCBCHMAC(b, 16, 1024)
}
func BenchmarkDecryptAES128_CBCHMAC_64k(b *testing.B) {
benchDecryptCBCHMAC(b, 16, 65536)
}
func BenchmarkDecryptAES128_CBCHMAC_1MB(b *testing.B) {
benchDecryptCBCHMAC(b, 16, 1048576)
}
func BenchmarkDecryptAES128_CBCHMAC_64MB(b *testing.B) {
benchDecryptCBCHMAC(b, 16, 67108864)
}
func BenchmarkEncryptAES192_CBCHMAC_64k(b *testing.B) {
benchEncryptCBCHMAC(b, 24, 65536)
}
func BenchmarkEncryptAES192_CBCHMAC_1MB(b *testing.B) {
benchEncryptCBCHMAC(b, 24, 1048576)
}
func BenchmarkEncryptAES192_CBCHMAC_64MB(b *testing.B) {
benchEncryptCBCHMAC(b, 24, 67108864)
}
func BenchmarkDecryptAES192_CBCHMAC_1k(b *testing.B) {
benchDecryptCBCHMAC(b, 24, 1024)
}
func BenchmarkDecryptAES192_CBCHMAC_64k(b *testing.B) {
benchDecryptCBCHMAC(b, 24, 65536)
}
func BenchmarkDecryptAES192_CBCHMAC_1MB(b *testing.B) {
benchDecryptCBCHMAC(b, 24, 1048576)
}
func BenchmarkDecryptAES192_CBCHMAC_64MB(b *testing.B) {
benchDecryptCBCHMAC(b, 24, 67108864)
}
func BenchmarkEncryptAES256_CBCHMAC_64k(b *testing.B) {
benchEncryptCBCHMAC(b, 32, 65536)
}
func BenchmarkEncryptAES256_CBCHMAC_1MB(b *testing.B) {
benchEncryptCBCHMAC(b, 32, 1048576)
}
func BenchmarkEncryptAES256_CBCHMAC_64MB(b *testing.B) {
benchEncryptCBCHMAC(b, 32, 67108864)
}
func BenchmarkDecryptAES256_CBCHMAC_1k(b *testing.B) {
benchDecryptCBCHMAC(b, 32, 1032)
}
func BenchmarkDecryptAES256_CBCHMAC_64k(b *testing.B) {
benchDecryptCBCHMAC(b, 32, 65536)
}
func BenchmarkDecryptAES256_CBCHMAC_1MB(b *testing.B) {
benchDecryptCBCHMAC(b, 32, 1048576)
}
func BenchmarkDecryptAES256_CBCHMAC_64MB(b *testing.B) {
benchDecryptCBCHMAC(b, 32, 67108864)
}

View file

@ -1,150 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package josecipher
import (
"bytes"
"crypto"
"testing"
)
// Taken from: https://tools.ietf.org/id/draft-ietf-jose-json-web-algorithms-38.txt
func TestVectorConcatKDF(t *testing.T) {
z := []byte{
158, 86, 217, 29, 129, 113, 53, 211, 114, 131, 66, 131, 191, 132,
38, 156, 251, 49, 110, 163, 218, 128, 106, 72, 246, 218, 167, 121,
140, 254, 144, 196}
algID := []byte{0, 0, 0, 7, 65, 49, 50, 56, 71, 67, 77}
ptyUInfo := []byte{0, 0, 0, 5, 65, 108, 105, 99, 101}
ptyVInfo := []byte{0, 0, 0, 3, 66, 111, 98}
supPubInfo := []byte{0, 0, 0, 128}
supPrivInfo := []byte{}
expected := []byte{
86, 170, 141, 234, 248, 35, 109, 32, 92, 34, 40, 205, 113, 167, 16, 26}
ckdf := NewConcatKDF(crypto.SHA256, z, algID, ptyUInfo, ptyVInfo, supPubInfo, supPrivInfo)
out0 := make([]byte, 9)
out1 := make([]byte, 7)
read0, err := ckdf.Read(out0)
if err != nil {
t.Error("error when reading from concat kdf reader", err)
return
}
read1, err := ckdf.Read(out1)
if err != nil {
t.Error("error when reading from concat kdf reader", err)
return
}
if read0+read1 != len(out0)+len(out1) {
t.Error("did not receive enough bytes from concat kdf reader")
return
}
out := []byte{}
out = append(out, out0...)
out = append(out, out1...)
if bytes.Compare(out, expected) != 0 {
t.Error("did not receive expected output from concat kdf reader")
return
}
}
func TestCache(t *testing.T) {
z := []byte{
158, 86, 217, 29, 129, 113, 53, 211, 114, 131, 66, 131, 191, 132,
38, 156, 251, 49, 110, 163, 218, 128, 106, 72, 246, 218, 167, 121,
140, 254, 144, 196}
algID := []byte{1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4}
ptyUInfo := []byte{1, 2, 3, 4}
ptyVInfo := []byte{4, 3, 2, 1}
supPubInfo := []byte{}
supPrivInfo := []byte{}
outputs := [][]byte{}
// Read the same amount of data in different chunk sizes
chunkSizes := []int{1, 2, 4, 8, 16, 32, 64, 128, 256, 512}
for _, c := range chunkSizes {
out := make([]byte, 1024)
reader := NewConcatKDF(crypto.SHA256, z, algID, ptyUInfo, ptyVInfo, supPubInfo, supPrivInfo)
for i := 0; i < 1024; i += c {
_, _ = reader.Read(out[i : i+c])
}
outputs = append(outputs, out)
}
for i := range outputs {
if bytes.Compare(outputs[i], outputs[(i+1)%len(outputs)]) != 0 {
t.Error("not all outputs from KDF matched")
}
}
}
func benchmarkKDF(b *testing.B, total int) {
z := []byte{
158, 86, 217, 29, 129, 113, 53, 211, 114, 131, 66, 131, 191, 132,
38, 156, 251, 49, 110, 163, 218, 128, 106, 72, 246, 218, 167, 121,
140, 254, 144, 196}
algID := []byte{1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4}
ptyUInfo := []byte{1, 2, 3, 4}
ptyVInfo := []byte{4, 3, 2, 1}
supPubInfo := []byte{}
supPrivInfo := []byte{}
out := make([]byte, total)
reader := NewConcatKDF(crypto.SHA256, z, algID, ptyUInfo, ptyVInfo, supPubInfo, supPrivInfo)
b.ResetTimer()
b.SetBytes(int64(total))
for i := 0; i < b.N; i++ {
_, _ = reader.Read(out)
}
}
func BenchmarkConcatKDF_1k(b *testing.B) {
benchmarkKDF(b, 1024)
}
func BenchmarkConcatKDF_64k(b *testing.B) {
benchmarkKDF(b, 65536)
}
func BenchmarkConcatKDF_1MB(b *testing.B) {
benchmarkKDF(b, 1048576)
}
func BenchmarkConcatKDF_64MB(b *testing.B) {
benchmarkKDF(b, 67108864)
}

View file

@ -1,115 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package josecipher
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"encoding/base64"
"math/big"
"testing"
)
// Example keys from JWA, Appendix C
var aliceKey = &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: elliptic.P256(),
X: fromBase64Int("gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0="),
Y: fromBase64Int("SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps="),
},
D: fromBase64Int("0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo="),
}
var bobKey = &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: elliptic.P256(),
X: fromBase64Int("weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ="),
Y: fromBase64Int("e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck="),
},
D: fromBase64Int("VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw="),
}
// Build big int from base64-encoded string. Strips whitespace (for testing).
func fromBase64Int(data string) *big.Int {
val, err := base64.URLEncoding.DecodeString(data)
if err != nil {
panic("Invalid test data: " + err.Error())
}
return new(big.Int).SetBytes(val)
}
func TestVectorECDHES(t *testing.T) {
apuData := []byte("Alice")
apvData := []byte("Bob")
expected := []byte{
86, 170, 141, 234, 248, 35, 109, 32, 92, 34, 40, 205, 113, 167, 16, 26}
output := DeriveECDHES("A128GCM", apuData, apvData, bobKey, &aliceKey.PublicKey, 16)
if bytes.Compare(output, expected) != 0 {
t.Error("output did not match what we expect, got", output, "wanted", expected)
}
}
func TestInvalidECPublicKey(t *testing.T) {
defer func() { recover() }()
// Invalid key
invalid := &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: elliptic.P256(),
X: fromBase64Int("MTEx"),
Y: fromBase64Int("MTEx"),
},
D: fromBase64Int("0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo="),
}
DeriveECDHES("A128GCM", []byte{}, []byte{}, bobKey, &invalid.PublicKey, 16)
t.Fatal("should panic if public key was invalid")
}
func BenchmarkECDHES_128(b *testing.B) {
apuData := []byte("APU")
apvData := []byte("APV")
b.ResetTimer()
for i := 0; i < b.N; i++ {
DeriveECDHES("ID", apuData, apvData, bobKey, &aliceKey.PublicKey, 16)
}
}
func BenchmarkECDHES_192(b *testing.B) {
apuData := []byte("APU")
apvData := []byte("APV")
b.ResetTimer()
for i := 0; i < b.N; i++ {
DeriveECDHES("ID", apuData, apvData, bobKey, &aliceKey.PublicKey, 24)
}
}
func BenchmarkECDHES_256(b *testing.B) {
apuData := []byte("APU")
apvData := []byte("APV")
b.ResetTimer()
for i := 0; i < b.N; i++ {
DeriveECDHES("ID", apuData, apvData, bobKey, &aliceKey.PublicKey, 32)
}
}

View file

@ -1,133 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package josecipher
import (
"bytes"
"crypto/aes"
"encoding/hex"
"testing"
)
func TestAesKeyWrap(t *testing.T) {
// Test vectors from: http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf
kek0, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F")
cek0, _ := hex.DecodeString("00112233445566778899AABBCCDDEEFF")
expected0, _ := hex.DecodeString("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5")
kek1, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F1011121314151617")
cek1, _ := hex.DecodeString("00112233445566778899AABBCCDDEEFF")
expected1, _ := hex.DecodeString("96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D")
kek2, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")
cek2, _ := hex.DecodeString("00112233445566778899AABBCCDDEEFF0001020304050607")
expected2, _ := hex.DecodeString("A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1")
block0, _ := aes.NewCipher(kek0)
block1, _ := aes.NewCipher(kek1)
block2, _ := aes.NewCipher(kek2)
out0, _ := KeyWrap(block0, cek0)
out1, _ := KeyWrap(block1, cek1)
out2, _ := KeyWrap(block2, cek2)
if bytes.Compare(out0, expected0) != 0 {
t.Error("output 0 not as expected, got", out0, "wanted", expected0)
}
if bytes.Compare(out1, expected1) != 0 {
t.Error("output 1 not as expected, got", out1, "wanted", expected1)
}
if bytes.Compare(out2, expected2) != 0 {
t.Error("output 2 not as expected, got", out2, "wanted", expected2)
}
unwrap0, _ := KeyUnwrap(block0, out0)
unwrap1, _ := KeyUnwrap(block1, out1)
unwrap2, _ := KeyUnwrap(block2, out2)
if bytes.Compare(unwrap0, cek0) != 0 {
t.Error("key unwrap did not return original input, got", unwrap0, "wanted", cek0)
}
if bytes.Compare(unwrap1, cek1) != 0 {
t.Error("key unwrap did not return original input, got", unwrap1, "wanted", cek1)
}
if bytes.Compare(unwrap2, cek2) != 0 {
t.Error("key unwrap did not return original input, got", unwrap2, "wanted", cek2)
}
}
func TestAesKeyWrapInvalid(t *testing.T) {
kek, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F")
// Invalid unwrap input (bit flipped)
input0, _ := hex.DecodeString("1EA68C1A8112B447AEF34BD8FB5A7B828D3E862371D2CFE5")
block, _ := aes.NewCipher(kek)
_, err := KeyUnwrap(block, input0)
if err == nil {
t.Error("key unwrap failed to detect invalid input")
}
// Invalid unwrap input (truncated)
input1, _ := hex.DecodeString("1EA68C1A8112B447AEF34BD8FB5A7B828D3E862371D2CF")
_, err = KeyUnwrap(block, input1)
if err == nil {
t.Error("key unwrap failed to detect truncated input")
}
// Invalid wrap input (not multiple of 8)
input2, _ := hex.DecodeString("0123456789ABCD")
_, err = KeyWrap(block, input2)
if err == nil {
t.Error("key wrap accepted invalid input")
}
}
func BenchmarkAesKeyWrap(b *testing.B) {
kek, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F")
key, _ := hex.DecodeString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
block, _ := aes.NewCipher(kek)
b.ResetTimer()
for i := 0; i < b.N; i++ {
KeyWrap(block, key)
}
}
func BenchmarkAesKeyUnwrap(b *testing.B) {
kek, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F")
input, _ := hex.DecodeString("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5")
block, _ := aes.NewCipher(kek)
b.ResetTimer()
for i := 0; i < b.N; i++ {
KeyUnwrap(block, input)
}
}

View file

@ -1,838 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jose
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"fmt"
"io"
"reflect"
"testing"
"golang.org/x/crypto/ed25519"
)
// We generate only a single RSA and EC key for testing, speeds up tests.
var rsaTestKey, _ = rsa.GenerateKey(rand.Reader, 2048)
var ecTestKey256, _ = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
var ecTestKey384, _ = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
var ecTestKey521, _ = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
var ed25519PublicKey, ed25519PrivateKey, _ = ed25519.GenerateKey(rand.Reader)
func RoundtripJWE(keyAlg KeyAlgorithm, encAlg ContentEncryption, compressionAlg CompressionAlgorithm, serializer func(*JSONWebEncryption) (string, error), corrupter func(*JSONWebEncryption) bool, aad []byte, encryptionKey interface{}, decryptionKey interface{}) error {
enc, err := NewEncrypter(encAlg, Recipient{Algorithm: keyAlg, Key: encryptionKey}, &EncrypterOptions{Compression: compressionAlg})
if err != nil {
return fmt.Errorf("error on new encrypter: %s", err)
}
input := []byte("Lorem ipsum dolor sit amet")
obj, err := enc.EncryptWithAuthData(input, aad)
if err != nil {
return fmt.Errorf("error in encrypt: %s", err)
}
msg, err := serializer(obj)
if err != nil {
return fmt.Errorf("error in serializer: %s", err)
}
parsed, err := ParseEncrypted(msg)
if err != nil {
return fmt.Errorf("error in parse: %s, on msg '%s'", err, msg)
}
// (Maybe) mangle object
skip := corrupter(parsed)
if skip {
return fmt.Errorf("corrupter indicated message should be skipped")
}
if bytes.Compare(parsed.GetAuthData(), aad) != 0 {
return fmt.Errorf("auth data in parsed object does not match")
}
output, err := parsed.Decrypt(decryptionKey)
if err != nil {
return fmt.Errorf("error on decrypt: %s", err)
}
if bytes.Compare(input, output) != 0 {
return fmt.Errorf("Decrypted output does not match input, got '%s' but wanted '%s'", output, input)
}
return nil
}
func TestRoundtripsJWE(t *testing.T) {
// Test matrix
keyAlgs := []KeyAlgorithm{
DIRECT, ECDH_ES, ECDH_ES_A128KW, ECDH_ES_A192KW, ECDH_ES_A256KW, A128KW, A192KW, A256KW,
RSA1_5, RSA_OAEP, RSA_OAEP_256, A128GCMKW, A192GCMKW, A256GCMKW}
encAlgs := []ContentEncryption{A128GCM, A192GCM, A256GCM, A128CBC_HS256, A192CBC_HS384, A256CBC_HS512}
zipAlgs := []CompressionAlgorithm{NONE, DEFLATE}
serializers := []func(*JSONWebEncryption) (string, error){
func(obj *JSONWebEncryption) (string, error) { return obj.CompactSerialize() },
func(obj *JSONWebEncryption) (string, error) { return obj.FullSerialize(), nil },
}
corrupter := func(obj *JSONWebEncryption) bool { return false }
// Note: can't use AAD with compact serialization
aads := [][]byte{
nil,
[]byte("Ut enim ad minim veniam"),
}
// Test all different configurations
for _, alg := range keyAlgs {
for _, enc := range encAlgs {
for _, key := range generateTestKeys(alg, enc) {
for _, zip := range zipAlgs {
for i, serializer := range serializers {
err := RoundtripJWE(alg, enc, zip, serializer, corrupter, aads[i], key.enc, key.dec)
if err != nil {
t.Error(err, alg, enc, zip, i)
}
}
}
}
}
}
}
func TestRoundtripsJWECorrupted(t *testing.T) {
// Test matrix
keyAlgs := []KeyAlgorithm{DIRECT, ECDH_ES, ECDH_ES_A128KW, A128KW, RSA1_5, RSA_OAEP, RSA_OAEP_256, A128GCMKW}
encAlgs := []ContentEncryption{A128GCM, A192GCM, A256GCM, A128CBC_HS256, A192CBC_HS384, A256CBC_HS512}
zipAlgs := []CompressionAlgorithm{NONE, DEFLATE}
serializers := []func(*JSONWebEncryption) (string, error){
func(obj *JSONWebEncryption) (string, error) { return obj.CompactSerialize() },
func(obj *JSONWebEncryption) (string, error) { return obj.FullSerialize(), nil },
}
bitflip := func(slice []byte) bool {
if len(slice) > 0 {
slice[0] ^= 0xFF
return false
}
return true
}
corrupters := []func(*JSONWebEncryption) bool{
func(obj *JSONWebEncryption) bool {
// Set invalid ciphertext
return bitflip(obj.ciphertext)
},
func(obj *JSONWebEncryption) bool {
// Set invalid auth tag
return bitflip(obj.tag)
},
func(obj *JSONWebEncryption) bool {
// Set invalid AAD
return bitflip(obj.aad)
},
func(obj *JSONWebEncryption) bool {
// Mess with encrypted key
return bitflip(obj.recipients[0].encryptedKey)
},
func(obj *JSONWebEncryption) bool {
// Mess with GCM-KW auth tag
tag, _ := obj.protected.getTag()
skip := bitflip(tag.bytes())
if skip {
return true
}
obj.protected.set(headerTag, tag)
return false
},
}
// Note: can't use AAD with compact serialization
aads := [][]byte{
nil,
[]byte("Ut enim ad minim veniam"),
}
// Test all different configurations
for _, alg := range keyAlgs {
for _, enc := range encAlgs {
for _, key := range generateTestKeys(alg, enc) {
for _, zip := range zipAlgs {
for i, serializer := range serializers {
for j, corrupter := range corrupters {
err := RoundtripJWE(alg, enc, zip, serializer, corrupter, aads[i], key.enc, key.dec)
if err == nil {
t.Error("failed to detect corrupt data", err, alg, enc, zip, i, j)
}
}
}
}
}
}
}
}
func TestEncrypterWithJWKAndKeyID(t *testing.T) {
enc, err := NewEncrypter(A128GCM, Recipient{Algorithm: A128KW, Key: &JSONWebKey{
KeyID: "test-id",
Key: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
}}, nil)
if err != nil {
t.Error(err)
}
ciphertext, _ := enc.Encrypt([]byte("Lorem ipsum dolor sit amet"))
serialized1, _ := ciphertext.CompactSerialize()
serialized2 := ciphertext.FullSerialize()
parsed1, _ := ParseEncrypted(serialized1)
parsed2, _ := ParseEncrypted(serialized2)
if parsed1.Header.KeyID != "test-id" {
t.Errorf("expected message to have key id from JWK, but found '%s' instead", parsed1.Header.KeyID)
}
if parsed2.Header.KeyID != "test-id" {
t.Errorf("expected message to have key id from JWK, but found '%s' instead", parsed2.Header.KeyID)
}
}
func TestEncrypterWithBrokenRand(t *testing.T) {
keyAlgs := []KeyAlgorithm{ECDH_ES_A128KW, A128KW, RSA1_5, RSA_OAEP, RSA_OAEP_256, A128GCMKW}
encAlgs := []ContentEncryption{A128GCM, A192GCM, A256GCM, A128CBC_HS256, A192CBC_HS384, A256CBC_HS512}
serializer := func(obj *JSONWebEncryption) (string, error) { return obj.CompactSerialize() }
corrupter := func(obj *JSONWebEncryption) bool { return false }
// Break rand reader
readers := []func() io.Reader{
// Totally broken
func() io.Reader { return bytes.NewReader([]byte{}) },
// Not enough bytes
func() io.Reader { return io.LimitReader(rand.Reader, 20) },
}
defer resetRandReader()
for _, alg := range keyAlgs {
for _, enc := range encAlgs {
for _, key := range generateTestKeys(alg, enc) {
for i, getReader := range readers {
randReader = getReader()
err := RoundtripJWE(alg, enc, NONE, serializer, corrupter, nil, key.enc, key.dec)
if err == nil {
t.Error("encrypter should fail if rand is broken", i)
}
}
}
}
}
}
func TestNewEncrypterErrors(t *testing.T) {
_, err := NewEncrypter("XYZ", Recipient{}, nil)
if err == nil {
t.Error("was able to instantiate encrypter with invalid cipher")
}
_, err = NewMultiEncrypter("XYZ", []Recipient{}, nil)
if err == nil {
t.Error("was able to instantiate multi-encrypter with invalid cipher")
}
_, err = NewEncrypter(A128GCM, Recipient{Algorithm: DIRECT, Key: nil}, nil)
if err == nil {
t.Error("was able to instantiate encrypter with invalid direct key")
}
_, err = NewEncrypter(A128GCM, Recipient{Algorithm: ECDH_ES, Key: nil}, nil)
if err == nil {
t.Error("was able to instantiate encrypter with invalid EC key")
}
}
func TestMultiRecipientJWE(t *testing.T) {
sharedKey := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}
enc, err := NewMultiEncrypter(A128GCM, []Recipient{
{Algorithm: RSA_OAEP, Key: &rsaTestKey.PublicKey},
{Algorithm: A256GCMKW, Key: sharedKey},
}, nil)
if err != nil {
panic(err)
}
input := []byte("Lorem ipsum dolor sit amet")
obj, err := enc.Encrypt(input)
if err != nil {
t.Fatal("error in encrypt: ", err)
}
msg := obj.FullSerialize()
parsed, err := ParseEncrypted(msg)
if err != nil {
t.Fatal("error in parse: ", err)
}
i, _, output, err := parsed.DecryptMulti(rsaTestKey)
if err != nil {
t.Fatal("error on decrypt with RSA: ", err)
}
if i != 0 {
t.Fatal("recipient index should be 0 for RSA key")
}
if bytes.Compare(input, output) != 0 {
t.Fatal("Decrypted output does not match input: ", output, input)
}
i, _, output, err = parsed.DecryptMulti(sharedKey)
if err != nil {
t.Fatal("error on decrypt with AES: ", err)
}
if i != 1 {
t.Fatal("recipient index should be 1 for shared key")
}
if bytes.Compare(input, output) != 0 {
t.Fatal("Decrypted output does not match input", output, input)
}
}
func TestMultiRecipientErrors(t *testing.T) {
_, err := NewMultiEncrypter(A128GCM, []Recipient{}, nil)
if err == nil {
t.Error("should fail to instantiate with zero recipients")
}
}
func TestEncrypterOptions(t *testing.T) {
sharedKey := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}
opts := &EncrypterOptions{
Compression: DEFLATE,
}
opts.WithType("JWT")
opts.WithContentType("JWT")
enc, err := NewEncrypter(A256GCM, Recipient{Algorithm: A256GCMKW, Key: sharedKey}, opts)
if err != nil {
fmt.Println(err)
t.Error("Failed to create encrypter")
}
if !reflect.DeepEqual(*opts, enc.Options()) {
t.Error("Encrypter options do not match")
}
}
// Test that extra headers are generated and parsed in a round trip.
func TestEncrypterExtraHeaderInclusion(t *testing.T) {
sharedKey := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}
opts := &EncrypterOptions{
Compression: DEFLATE,
}
opts.WithType("JWT")
opts.WithContentType("JWT")
opts.WithHeader(HeaderKey("myCustomHeader"), "xyz")
enc, err := NewEncrypter(A256GCM, Recipient{Algorithm: A256GCMKW, Key: sharedKey}, opts)
if err != nil {
fmt.Println(err)
t.Error("Failed to create encrypter")
}
if !reflect.DeepEqual(*opts, enc.Options()) {
t.Error("Encrypter options do not match")
}
input := []byte("Lorem ipsum dolor sit amet")
obj, err := enc.Encrypt(input)
if err != nil {
t.Fatal("error in encrypt: ", err)
}
parsed, err := ParseEncrypted(obj.FullSerialize())
if err != nil {
t.Fatal("error in parse: ", err)
}
output, err := parsed.Decrypt(sharedKey)
if err != nil {
t.Fatal("error on decrypt: ", err)
}
if bytes.Compare(input, output) != 0 {
t.Fatal("Decrypted output does not match input: ", output, input)
}
if parsed.Header.ExtraHeaders[HeaderType] != "JWT" ||
parsed.Header.ExtraHeaders[HeaderContentType] != "JWT" ||
parsed.Header.ExtraHeaders[HeaderKey("myCustomHeader")] != "xyz" {
t.Fatalf("Mismatch in extra headers: %#v", parsed.Header.ExtraHeaders)
}
}
type testKey struct {
enc, dec interface{}
}
func symmetricTestKey(size int) []testKey {
key, _, _ := randomKeyGenerator{size: size}.genKey()
return []testKey{
{
enc: key,
dec: key,
},
{
enc: &JSONWebKey{KeyID: "test", Key: key},
dec: &JSONWebKey{KeyID: "test", Key: key},
},
}
}
func generateTestKeys(keyAlg KeyAlgorithm, encAlg ContentEncryption) []testKey {
switch keyAlg {
case DIRECT:
return symmetricTestKey(getContentCipher(encAlg).keySize())
case ECDH_ES, ECDH_ES_A128KW, ECDH_ES_A192KW, ECDH_ES_A256KW:
return []testKey{
{
dec: ecTestKey256,
enc: &ecTestKey256.PublicKey,
},
{
dec: ecTestKey384,
enc: &ecTestKey384.PublicKey,
},
{
dec: ecTestKey521,
enc: &ecTestKey521.PublicKey,
},
{
dec: &JSONWebKey{KeyID: "test", Key: ecTestKey256},
enc: &JSONWebKey{KeyID: "test", Key: &ecTestKey256.PublicKey},
},
}
case A128GCMKW, A128KW:
return symmetricTestKey(16)
case A192GCMKW, A192KW:
return symmetricTestKey(24)
case A256GCMKW, A256KW:
return symmetricTestKey(32)
case RSA1_5, RSA_OAEP, RSA_OAEP_256:
return []testKey{{
dec: rsaTestKey,
enc: &rsaTestKey.PublicKey,
}}
}
panic("Must update test case")
}
func RunRoundtripsJWE(b *testing.B, alg KeyAlgorithm, enc ContentEncryption, zip CompressionAlgorithm, priv, pub interface{}) {
serializer := func(obj *JSONWebEncryption) (string, error) {
return obj.CompactSerialize()
}
corrupter := func(obj *JSONWebEncryption) bool { return false }
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := RoundtripJWE(alg, enc, zip, serializer, corrupter, nil, pub, priv)
if err != nil {
b.Error(err)
}
}
}
var (
chunks = map[string][]byte{
"1B": make([]byte, 1),
"64B": make([]byte, 64),
"1KB": make([]byte, 1024),
"64KB": make([]byte, 65536),
"1MB": make([]byte, 1048576),
"64MB": make([]byte, 67108864),
}
symKey, _, _ = randomKeyGenerator{size: 32}.genKey()
encrypters = map[string]Encrypter{
"OAEPAndGCM": mustEncrypter(RSA_OAEP, A128GCM, &rsaTestKey.PublicKey),
"PKCSAndGCM": mustEncrypter(RSA1_5, A128GCM, &rsaTestKey.PublicKey),
"OAEPAndCBC": mustEncrypter(RSA_OAEP, A128CBC_HS256, &rsaTestKey.PublicKey),
"PKCSAndCBC": mustEncrypter(RSA1_5, A128CBC_HS256, &rsaTestKey.PublicKey),
"DirectGCM128": mustEncrypter(DIRECT, A128GCM, symKey),
"DirectCBC128": mustEncrypter(DIRECT, A128CBC_HS256, symKey),
"DirectGCM256": mustEncrypter(DIRECT, A256GCM, symKey),
"DirectCBC256": mustEncrypter(DIRECT, A256CBC_HS512, symKey),
"AESKWAndGCM128": mustEncrypter(A128KW, A128GCM, symKey),
"AESKWAndCBC256": mustEncrypter(A256KW, A256GCM, symKey),
"ECDHOnP256AndGCM128": mustEncrypter(ECDH_ES, A128GCM, &ecTestKey256.PublicKey),
"ECDHOnP384AndGCM128": mustEncrypter(ECDH_ES, A128GCM, &ecTestKey384.PublicKey),
"ECDHOnP521AndGCM128": mustEncrypter(ECDH_ES, A128GCM, &ecTestKey521.PublicKey),
}
)
func BenchmarkEncrypt1BWithOAEPAndGCM(b *testing.B) { benchEncrypt("1B", "OAEPAndGCM", b) }
func BenchmarkEncrypt64BWithOAEPAndGCM(b *testing.B) { benchEncrypt("64B", "OAEPAndGCM", b) }
func BenchmarkEncrypt1KBWithOAEPAndGCM(b *testing.B) { benchEncrypt("1KB", "OAEPAndGCM", b) }
func BenchmarkEncrypt64KBWithOAEPAndGCM(b *testing.B) { benchEncrypt("64KB", "OAEPAndGCM", b) }
func BenchmarkEncrypt1MBWithOAEPAndGCM(b *testing.B) { benchEncrypt("1MB", "OAEPAndGCM", b) }
func BenchmarkEncrypt64MBWithOAEPAndGCM(b *testing.B) { benchEncrypt("64MB", "OAEPAndGCM", b) }
func BenchmarkEncrypt1BWithPKCSAndGCM(b *testing.B) { benchEncrypt("1B", "PKCSAndGCM", b) }
func BenchmarkEncrypt64BWithPKCSAndGCM(b *testing.B) { benchEncrypt("64B", "PKCSAndGCM", b) }
func BenchmarkEncrypt1KBWithPKCSAndGCM(b *testing.B) { benchEncrypt("1KB", "PKCSAndGCM", b) }
func BenchmarkEncrypt64KBWithPKCSAndGCM(b *testing.B) { benchEncrypt("64KB", "PKCSAndGCM", b) }
func BenchmarkEncrypt1MBWithPKCSAndGCM(b *testing.B) { benchEncrypt("1MB", "PKCSAndGCM", b) }
func BenchmarkEncrypt64MBWithPKCSAndGCM(b *testing.B) { benchEncrypt("64MB", "PKCSAndGCM", b) }
func BenchmarkEncrypt1BWithOAEPAndCBC(b *testing.B) { benchEncrypt("1B", "OAEPAndCBC", b) }
func BenchmarkEncrypt64BWithOAEPAndCBC(b *testing.B) { benchEncrypt("64B", "OAEPAndCBC", b) }
func BenchmarkEncrypt1KBWithOAEPAndCBC(b *testing.B) { benchEncrypt("1KB", "OAEPAndCBC", b) }
func BenchmarkEncrypt64KBWithOAEPAndCBC(b *testing.B) { benchEncrypt("64KB", "OAEPAndCBC", b) }
func BenchmarkEncrypt1MBWithOAEPAndCBC(b *testing.B) { benchEncrypt("1MB", "OAEPAndCBC", b) }
func BenchmarkEncrypt64MBWithOAEPAndCBC(b *testing.B) { benchEncrypt("64MB", "OAEPAndCBC", b) }
func BenchmarkEncrypt1BWithPKCSAndCBC(b *testing.B) { benchEncrypt("1B", "PKCSAndCBC", b) }
func BenchmarkEncrypt64BWithPKCSAndCBC(b *testing.B) { benchEncrypt("64B", "PKCSAndCBC", b) }
func BenchmarkEncrypt1KBWithPKCSAndCBC(b *testing.B) { benchEncrypt("1KB", "PKCSAndCBC", b) }
func BenchmarkEncrypt64KBWithPKCSAndCBC(b *testing.B) { benchEncrypt("64KB", "PKCSAndCBC", b) }
func BenchmarkEncrypt1MBWithPKCSAndCBC(b *testing.B) { benchEncrypt("1MB", "PKCSAndCBC", b) }
func BenchmarkEncrypt64MBWithPKCSAndCBC(b *testing.B) { benchEncrypt("64MB", "PKCSAndCBC", b) }
func BenchmarkEncrypt1BWithDirectGCM128(b *testing.B) { benchEncrypt("1B", "DirectGCM128", b) }
func BenchmarkEncrypt64BWithDirectGCM128(b *testing.B) { benchEncrypt("64B", "DirectGCM128", b) }
func BenchmarkEncrypt1KBWithDirectGCM128(b *testing.B) { benchEncrypt("1KB", "DirectGCM128", b) }
func BenchmarkEncrypt64KBWithDirectGCM128(b *testing.B) { benchEncrypt("64KB", "DirectGCM128", b) }
func BenchmarkEncrypt1MBWithDirectGCM128(b *testing.B) { benchEncrypt("1MB", "DirectGCM128", b) }
func BenchmarkEncrypt64MBWithDirectGCM128(b *testing.B) { benchEncrypt("64MB", "DirectGCM128", b) }
func BenchmarkEncrypt1BWithDirectCBC128(b *testing.B) { benchEncrypt("1B", "DirectCBC128", b) }
func BenchmarkEncrypt64BWithDirectCBC128(b *testing.B) { benchEncrypt("64B", "DirectCBC128", b) }
func BenchmarkEncrypt1KBWithDirectCBC128(b *testing.B) { benchEncrypt("1KB", "DirectCBC128", b) }
func BenchmarkEncrypt64KBWithDirectCBC128(b *testing.B) { benchEncrypt("64KB", "DirectCBC128", b) }
func BenchmarkEncrypt1MBWithDirectCBC128(b *testing.B) { benchEncrypt("1MB", "DirectCBC128", b) }
func BenchmarkEncrypt64MBWithDirectCBC128(b *testing.B) { benchEncrypt("64MB", "DirectCBC128", b) }
func BenchmarkEncrypt1BWithDirectGCM256(b *testing.B) { benchEncrypt("1B", "DirectGCM256", b) }
func BenchmarkEncrypt64BWithDirectGCM256(b *testing.B) { benchEncrypt("64B", "DirectGCM256", b) }
func BenchmarkEncrypt1KBWithDirectGCM256(b *testing.B) { benchEncrypt("1KB", "DirectGCM256", b) }
func BenchmarkEncrypt64KBWithDirectGCM256(b *testing.B) { benchEncrypt("64KB", "DirectGCM256", b) }
func BenchmarkEncrypt1MBWithDirectGCM256(b *testing.B) { benchEncrypt("1MB", "DirectGCM256", b) }
func BenchmarkEncrypt64MBWithDirectGCM256(b *testing.B) { benchEncrypt("64MB", "DirectGCM256", b) }
func BenchmarkEncrypt1BWithDirectCBC256(b *testing.B) { benchEncrypt("1B", "DirectCBC256", b) }
func BenchmarkEncrypt64BWithDirectCBC256(b *testing.B) { benchEncrypt("64B", "DirectCBC256", b) }
func BenchmarkEncrypt1KBWithDirectCBC256(b *testing.B) { benchEncrypt("1KB", "DirectCBC256", b) }
func BenchmarkEncrypt64KBWithDirectCBC256(b *testing.B) { benchEncrypt("64KB", "DirectCBC256", b) }
func BenchmarkEncrypt1MBWithDirectCBC256(b *testing.B) { benchEncrypt("1MB", "DirectCBC256", b) }
func BenchmarkEncrypt64MBWithDirectCBC256(b *testing.B) { benchEncrypt("64MB", "DirectCBC256", b) }
func BenchmarkEncrypt1BWithAESKWAndGCM128(b *testing.B) { benchEncrypt("1B", "AESKWAndGCM128", b) }
func BenchmarkEncrypt64BWithAESKWAndGCM128(b *testing.B) { benchEncrypt("64B", "AESKWAndGCM128", b) }
func BenchmarkEncrypt1KBWithAESKWAndGCM128(b *testing.B) { benchEncrypt("1KB", "AESKWAndGCM128", b) }
func BenchmarkEncrypt64KBWithAESKWAndGCM128(b *testing.B) { benchEncrypt("64KB", "AESKWAndGCM128", b) }
func BenchmarkEncrypt1MBWithAESKWAndGCM128(b *testing.B) { benchEncrypt("1MB", "AESKWAndGCM128", b) }
func BenchmarkEncrypt64MBWithAESKWAndGCM128(b *testing.B) { benchEncrypt("64MB", "AESKWAndGCM128", b) }
func BenchmarkEncrypt1BWithAESKWAndCBC256(b *testing.B) { benchEncrypt("1B", "AESKWAndCBC256", b) }
func BenchmarkEncrypt64BWithAESKWAndCBC256(b *testing.B) { benchEncrypt("64B", "AESKWAndCBC256", b) }
func BenchmarkEncrypt1KBWithAESKWAndCBC256(b *testing.B) { benchEncrypt("1KB", "AESKWAndCBC256", b) }
func BenchmarkEncrypt64KBWithAESKWAndCBC256(b *testing.B) { benchEncrypt("64KB", "AESKWAndCBC256", b) }
func BenchmarkEncrypt1MBWithAESKWAndCBC256(b *testing.B) { benchEncrypt("1MB", "AESKWAndCBC256", b) }
func BenchmarkEncrypt64MBWithAESKWAndCBC256(b *testing.B) { benchEncrypt("64MB", "AESKWAndCBC256", b) }
func BenchmarkEncrypt1BWithECDHOnP256AndGCM128(b *testing.B) {
benchEncrypt("1B", "ECDHOnP256AndGCM128", b)
}
func BenchmarkEncrypt64BWithECDHOnP256AndGCM128(b *testing.B) {
benchEncrypt("64B", "ECDHOnP256AndGCM128", b)
}
func BenchmarkEncrypt1KBWithECDHOnP256AndGCM128(b *testing.B) {
benchEncrypt("1KB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkEncrypt64KBWithECDHOnP256AndGCM128(b *testing.B) {
benchEncrypt("64KB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkEncrypt1MBWithECDHOnP256AndGCM128(b *testing.B) {
benchEncrypt("1MB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkEncrypt64MBWithECDHOnP256AndGCM128(b *testing.B) {
benchEncrypt("64MB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkEncrypt1BWithECDHOnP384AndGCM128(b *testing.B) {
benchEncrypt("1B", "ECDHOnP384AndGCM128", b)
}
func BenchmarkEncrypt64BWithECDHOnP384AndGCM128(b *testing.B) {
benchEncrypt("64B", "ECDHOnP384AndGCM128", b)
}
func BenchmarkEncrypt1KBWithECDHOnP384AndGCM128(b *testing.B) {
benchEncrypt("1KB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkEncrypt64KBWithECDHOnP384AndGCM128(b *testing.B) {
benchEncrypt("64KB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkEncrypt1MBWithECDHOnP384AndGCM128(b *testing.B) {
benchEncrypt("1MB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkEncrypt64MBWithECDHOnP384AndGCM128(b *testing.B) {
benchEncrypt("64MB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkEncrypt1BWithECDHOnP521AndGCM128(b *testing.B) {
benchEncrypt("1B", "ECDHOnP521AndGCM128", b)
}
func BenchmarkEncrypt64BWithECDHOnP521AndGCM128(b *testing.B) {
benchEncrypt("64B", "ECDHOnP521AndGCM128", b)
}
func BenchmarkEncrypt1KBWithECDHOnP521AndGCM128(b *testing.B) {
benchEncrypt("1KB", "ECDHOnP521AndGCM128", b)
}
func BenchmarkEncrypt64KBWithECDHOnP521AndGCM128(b *testing.B) {
benchEncrypt("64KB", "ECDHOnP521AndGCM128", b)
}
func BenchmarkEncrypt1MBWithECDHOnP521AndGCM128(b *testing.B) {
benchEncrypt("1MB", "ECDHOnP521AndGCM128", b)
}
func BenchmarkEncrypt64MBWithECDHOnP521AndGCM128(b *testing.B) {
benchEncrypt("64MB", "ECDHOnP521AndGCM128", b)
}
func benchEncrypt(chunkKey, primKey string, b *testing.B) {
data, ok := chunks[chunkKey]
if !ok {
b.Fatalf("unknown chunk size %s", chunkKey)
}
enc, ok := encrypters[primKey]
if !ok {
b.Fatalf("unknown encrypter %s", primKey)
}
b.SetBytes(int64(len(data)))
for i := 0; i < b.N; i++ {
enc.Encrypt(data)
}
}
var (
decryptionKeys = map[string]interface{}{
"OAEPAndGCM": rsaTestKey,
"PKCSAndGCM": rsaTestKey,
"OAEPAndCBC": rsaTestKey,
"PKCSAndCBC": rsaTestKey,
"DirectGCM128": symKey,
"DirectCBC128": symKey,
"DirectGCM256": symKey,
"DirectCBC256": symKey,
"AESKWAndGCM128": symKey,
"AESKWAndCBC256": symKey,
"ECDHOnP256AndGCM128": ecTestKey256,
"ECDHOnP384AndGCM128": ecTestKey384,
"ECDHOnP521AndGCM128": ecTestKey521,
}
)
func BenchmarkDecrypt1BWithOAEPAndGCM(b *testing.B) { benchDecrypt("1B", "OAEPAndGCM", b) }
func BenchmarkDecrypt64BWithOAEPAndGCM(b *testing.B) { benchDecrypt("64B", "OAEPAndGCM", b) }
func BenchmarkDecrypt1KBWithOAEPAndGCM(b *testing.B) { benchDecrypt("1KB", "OAEPAndGCM", b) }
func BenchmarkDecrypt64KBWithOAEPAndGCM(b *testing.B) { benchDecrypt("64KB", "OAEPAndGCM", b) }
func BenchmarkDecrypt1MBWithOAEPAndGCM(b *testing.B) { benchDecrypt("1MB", "OAEPAndGCM", b) }
func BenchmarkDecrypt64MBWithOAEPAndGCM(b *testing.B) { benchDecrypt("64MB", "OAEPAndGCM", b) }
func BenchmarkDecrypt1BWithPKCSAndGCM(b *testing.B) { benchDecrypt("1B", "PKCSAndGCM", b) }
func BenchmarkDecrypt64BWithPKCSAndGCM(b *testing.B) { benchDecrypt("64B", "PKCSAndGCM", b) }
func BenchmarkDecrypt1KBWithPKCSAndGCM(b *testing.B) { benchDecrypt("1KB", "PKCSAndGCM", b) }
func BenchmarkDecrypt64KBWithPKCSAndGCM(b *testing.B) { benchDecrypt("64KB", "PKCSAndGCM", b) }
func BenchmarkDecrypt1MBWithPKCSAndGCM(b *testing.B) { benchDecrypt("1MB", "PKCSAndGCM", b) }
func BenchmarkDecrypt64MBWithPKCSAndGCM(b *testing.B) { benchDecrypt("64MB", "PKCSAndGCM", b) }
func BenchmarkDecrypt1BWithOAEPAndCBC(b *testing.B) { benchDecrypt("1B", "OAEPAndCBC", b) }
func BenchmarkDecrypt64BWithOAEPAndCBC(b *testing.B) { benchDecrypt("64B", "OAEPAndCBC", b) }
func BenchmarkDecrypt1KBWithOAEPAndCBC(b *testing.B) { benchDecrypt("1KB", "OAEPAndCBC", b) }
func BenchmarkDecrypt64KBWithOAEPAndCBC(b *testing.B) { benchDecrypt("64KB", "OAEPAndCBC", b) }
func BenchmarkDecrypt1MBWithOAEPAndCBC(b *testing.B) { benchDecrypt("1MB", "OAEPAndCBC", b) }
func BenchmarkDecrypt64MBWithOAEPAndCBC(b *testing.B) { benchDecrypt("64MB", "OAEPAndCBC", b) }
func BenchmarkDecrypt1BWithPKCSAndCBC(b *testing.B) { benchDecrypt("1B", "PKCSAndCBC", b) }
func BenchmarkDecrypt64BWithPKCSAndCBC(b *testing.B) { benchDecrypt("64B", "PKCSAndCBC", b) }
func BenchmarkDecrypt1KBWithPKCSAndCBC(b *testing.B) { benchDecrypt("1KB", "PKCSAndCBC", b) }
func BenchmarkDecrypt64KBWithPKCSAndCBC(b *testing.B) { benchDecrypt("64KB", "PKCSAndCBC", b) }
func BenchmarkDecrypt1MBWithPKCSAndCBC(b *testing.B) { benchDecrypt("1MB", "PKCSAndCBC", b) }
func BenchmarkDecrypt64MBWithPKCSAndCBC(b *testing.B) { benchDecrypt("64MB", "PKCSAndCBC", b) }
func BenchmarkDecrypt1BWithDirectGCM128(b *testing.B) { benchDecrypt("1B", "DirectGCM128", b) }
func BenchmarkDecrypt64BWithDirectGCM128(b *testing.B) { benchDecrypt("64B", "DirectGCM128", b) }
func BenchmarkDecrypt1KBWithDirectGCM128(b *testing.B) { benchDecrypt("1KB", "DirectGCM128", b) }
func BenchmarkDecrypt64KBWithDirectGCM128(b *testing.B) { benchDecrypt("64KB", "DirectGCM128", b) }
func BenchmarkDecrypt1MBWithDirectGCM128(b *testing.B) { benchDecrypt("1MB", "DirectGCM128", b) }
func BenchmarkDecrypt64MBWithDirectGCM128(b *testing.B) { benchDecrypt("64MB", "DirectGCM128", b) }
func BenchmarkDecrypt1BWithDirectCBC128(b *testing.B) { benchDecrypt("1B", "DirectCBC128", b) }
func BenchmarkDecrypt64BWithDirectCBC128(b *testing.B) { benchDecrypt("64B", "DirectCBC128", b) }
func BenchmarkDecrypt1KBWithDirectCBC128(b *testing.B) { benchDecrypt("1KB", "DirectCBC128", b) }
func BenchmarkDecrypt64KBWithDirectCBC128(b *testing.B) { benchDecrypt("64KB", "DirectCBC128", b) }
func BenchmarkDecrypt1MBWithDirectCBC128(b *testing.B) { benchDecrypt("1MB", "DirectCBC128", b) }
func BenchmarkDecrypt64MBWithDirectCBC128(b *testing.B) { benchDecrypt("64MB", "DirectCBC128", b) }
func BenchmarkDecrypt1BWithDirectGCM256(b *testing.B) { benchDecrypt("1B", "DirectGCM256", b) }
func BenchmarkDecrypt64BWithDirectGCM256(b *testing.B) { benchDecrypt("64B", "DirectGCM256", b) }
func BenchmarkDecrypt1KBWithDirectGCM256(b *testing.B) { benchDecrypt("1KB", "DirectGCM256", b) }
func BenchmarkDecrypt64KBWithDirectGCM256(b *testing.B) { benchDecrypt("64KB", "DirectGCM256", b) }
func BenchmarkDecrypt1MBWithDirectGCM256(b *testing.B) { benchDecrypt("1MB", "DirectGCM256", b) }
func BenchmarkDecrypt64MBWithDirectGCM256(b *testing.B) { benchDecrypt("64MB", "DirectGCM256", b) }
func BenchmarkDecrypt1BWithDirectCBC256(b *testing.B) { benchDecrypt("1B", "DirectCBC256", b) }
func BenchmarkDecrypt64BWithDirectCBC256(b *testing.B) { benchDecrypt("64B", "DirectCBC256", b) }
func BenchmarkDecrypt1KBWithDirectCBC256(b *testing.B) { benchDecrypt("1KB", "DirectCBC256", b) }
func BenchmarkDecrypt64KBWithDirectCBC256(b *testing.B) { benchDecrypt("64KB", "DirectCBC256", b) }
func BenchmarkDecrypt1MBWithDirectCBC256(b *testing.B) { benchDecrypt("1MB", "DirectCBC256", b) }
func BenchmarkDecrypt64MBWithDirectCBC256(b *testing.B) { benchDecrypt("64MB", "DirectCBC256", b) }
func BenchmarkDecrypt1BWithAESKWAndGCM128(b *testing.B) { benchDecrypt("1B", "AESKWAndGCM128", b) }
func BenchmarkDecrypt64BWithAESKWAndGCM128(b *testing.B) { benchDecrypt("64B", "AESKWAndGCM128", b) }
func BenchmarkDecrypt1KBWithAESKWAndGCM128(b *testing.B) { benchDecrypt("1KB", "AESKWAndGCM128", b) }
func BenchmarkDecrypt64KBWithAESKWAndGCM128(b *testing.B) { benchDecrypt("64KB", "AESKWAndGCM128", b) }
func BenchmarkDecrypt1MBWithAESKWAndGCM128(b *testing.B) { benchDecrypt("1MB", "AESKWAndGCM128", b) }
func BenchmarkDecrypt64MBWithAESKWAndGCM128(b *testing.B) { benchDecrypt("64MB", "AESKWAndGCM128", b) }
func BenchmarkDecrypt1BWithAESKWAndCBC256(b *testing.B) { benchDecrypt("1B", "AESKWAndCBC256", b) }
func BenchmarkDecrypt64BWithAESKWAndCBC256(b *testing.B) { benchDecrypt("64B", "AESKWAndCBC256", b) }
func BenchmarkDecrypt1KBWithAESKWAndCBC256(b *testing.B) { benchDecrypt("1KB", "AESKWAndCBC256", b) }
func BenchmarkDecrypt64KBWithAESKWAndCBC256(b *testing.B) { benchDecrypt("64KB", "AESKWAndCBC256", b) }
func BenchmarkDecrypt1MBWithAESKWAndCBC256(b *testing.B) { benchDecrypt("1MB", "AESKWAndCBC256", b) }
func BenchmarkDecrypt64MBWithAESKWAndCBC256(b *testing.B) { benchDecrypt("64MB", "AESKWAndCBC256", b) }
func BenchmarkDecrypt1BWithECDHOnP256AndGCM128(b *testing.B) {
benchDecrypt("1B", "ECDHOnP256AndGCM128", b)
}
func BenchmarkDecrypt64BWithECDHOnP256AndGCM128(b *testing.B) {
benchDecrypt("64B", "ECDHOnP256AndGCM128", b)
}
func BenchmarkDecrypt1KBWithECDHOnP256AndGCM128(b *testing.B) {
benchDecrypt("1KB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkDecrypt64KBWithECDHOnP256AndGCM128(b *testing.B) {
benchDecrypt("64KB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkDecrypt1MBWithECDHOnP256AndGCM128(b *testing.B) {
benchDecrypt("1MB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkDecrypt64MBWithECDHOnP256AndGCM128(b *testing.B) {
benchDecrypt("64MB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkDecrypt1BWithECDHOnP384AndGCM128(b *testing.B) {
benchDecrypt("1B", "ECDHOnP384AndGCM128", b)
}
func BenchmarkDecrypt64BWithECDHOnP384AndGCM128(b *testing.B) {
benchDecrypt("64B", "ECDHOnP384AndGCM128", b)
}
func BenchmarkDecrypt1KBWithECDHOnP384AndGCM128(b *testing.B) {
benchDecrypt("1KB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkDecrypt64KBWithECDHOnP384AndGCM128(b *testing.B) {
benchDecrypt("64KB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkDecrypt1MBWithECDHOnP384AndGCM128(b *testing.B) {
benchDecrypt("1MB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkDecrypt64MBWithECDHOnP384AndGCM128(b *testing.B) {
benchDecrypt("64MB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkDecrypt1BWithECDHOnP521AndGCM128(b *testing.B) {
benchDecrypt("1B", "ECDHOnP521AndGCM128", b)
}
func BenchmarkDecrypt64BWithECDHOnP521AndGCM128(b *testing.B) {
benchDecrypt("64B", "ECDHOnP521AndGCM128", b)
}
func BenchmarkDecrypt1KBWithECDHOnP521AndGCM128(b *testing.B) {
benchDecrypt("1KB", "ECDHOnP521AndGCM128", b)
}
func BenchmarkDecrypt64KBWithECDHOnP521AndGCM128(b *testing.B) {
benchDecrypt("64KB", "ECDHOnP521AndGCM128", b)
}
func BenchmarkDecrypt1MBWithECDHOnP521AndGCM128(b *testing.B) {
benchDecrypt("1MB", "ECDHOnP521AndGCM128", b)
}
func BenchmarkDecrypt64MBWithECDHOnP521AndGCM128(b *testing.B) {
benchDecrypt("64MB", "ECDHOnP521AndGCM128", b)
}
func benchDecrypt(chunkKey, primKey string, b *testing.B) {
chunk, ok := chunks[chunkKey]
if !ok {
b.Fatalf("unknown chunk size %s", chunkKey)
}
enc, ok := encrypters[primKey]
if !ok {
b.Fatalf("unknown encrypter %s", primKey)
}
dec, ok := decryptionKeys[primKey]
if !ok {
b.Fatalf("unknown decryption key %s", primKey)
}
data, err := enc.Encrypt(chunk)
if err != nil {
b.Fatal(err)
}
b.SetBytes(int64(len(chunk)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
data.Decrypt(dec)
}
}
func mustEncrypter(keyAlg KeyAlgorithm, encAlg ContentEncryption, encryptionKey interface{}) Encrypter {
enc, err := NewEncrypter(encAlg, Recipient{Algorithm: keyAlg, Key: encryptionKey}, nil)
if err != nil {
panic(err)
}
return enc
}

View file

@ -1,201 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jose
import (
"crypto/ecdsa"
"crypto/rand"
"crypto/rsa"
"fmt"
)
// Dummy encrypter for use in examples
var encrypter Encrypter
func Example_jWE() {
// Generate a public/private key pair to use for this example.
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
// Instantiate an encrypter using RSA-OAEP with AES128-GCM. An error would
// indicate that the selected algorithm(s) are not currently supported.
publicKey := &privateKey.PublicKey
encrypter, err := NewEncrypter(A128GCM, Recipient{Algorithm: RSA_OAEP, Key: publicKey}, nil)
if err != nil {
panic(err)
}
// Encrypt a sample plaintext. Calling the encrypter returns an encrypted
// JWE object, which can then be serialized for output afterwards. An error
// would indicate a problem in an underlying cryptographic primitive.
var plaintext = []byte("Lorem ipsum dolor sit amet")
object, err := encrypter.Encrypt(plaintext)
if err != nil {
panic(err)
}
// Serialize the encrypted object using the full serialization format.
// Alternatively you can also use the compact format here by calling
// object.CompactSerialize() instead.
serialized := object.FullSerialize()
// Parse the serialized, encrypted JWE object. An error would indicate that
// the given input did not represent a valid message.
object, err = ParseEncrypted(serialized)
if err != nil {
panic(err)
}
// Now we can decrypt and get back our original plaintext. An error here
// would indicate the the message failed to decrypt, e.g. because the auth
// tag was broken or the message was tampered with.
decrypted, err := object.Decrypt(privateKey)
if err != nil {
panic(err)
}
fmt.Printf(string(decrypted))
// output: Lorem ipsum dolor sit amet
}
func Example_jWS() {
// Generate a public/private key pair to use for this example.
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
// Instantiate a signer using RSASSA-PSS (SHA512) with the given private key.
signer, err := NewSigner(SigningKey{Algorithm: PS512, Key: privateKey}, nil)
if err != nil {
panic(err)
}
// Sign a sample payload. Calling the signer returns a protected JWS object,
// which can then be serialized for output afterwards. An error would
// indicate a problem in an underlying cryptographic primitive.
var payload = []byte("Lorem ipsum dolor sit amet")
object, err := signer.Sign(payload)
if err != nil {
panic(err)
}
// Serialize the encrypted object using the full serialization format.
// Alternatively you can also use the compact format here by calling
// object.CompactSerialize() instead.
serialized := object.FullSerialize()
// Parse the serialized, protected JWS object. An error would indicate that
// the given input did not represent a valid message.
object, err = ParseSigned(serialized)
if err != nil {
panic(err)
}
// Now we can verify the signature on the payload. An error here would
// indicate the the message failed to verify, e.g. because the signature was
// broken or the message was tampered with.
output, err := object.Verify(&privateKey.PublicKey)
if err != nil {
panic(err)
}
fmt.Printf(string(output))
// output: Lorem ipsum dolor sit amet
}
func ExampleNewEncrypter_publicKey() {
var publicKey *rsa.PublicKey
// Instantiate an encrypter using RSA-OAEP with AES128-GCM.
NewEncrypter(A128GCM, Recipient{Algorithm: RSA_OAEP, Key: publicKey}, nil)
// Instantiate an encrypter using RSA-PKCS1v1.5 with AES128-CBC+HMAC.
NewEncrypter(A128CBC_HS256, Recipient{Algorithm: RSA1_5, Key: publicKey}, nil)
}
func ExampleNewEncrypter_symmetric() {
var sharedKey []byte
// Instantiate an encrypter using AES128-GCM with AES-GCM key wrap.
NewEncrypter(A128GCM, Recipient{Algorithm: A128GCMKW, Key: sharedKey}, nil)
// Instantiate an encrypter using AES128-GCM directly, w/o key wrapping.
NewEncrypter(A128GCM, Recipient{Algorithm: DIRECT, Key: sharedKey}, nil)
}
func ExampleNewSigner_publicKey() {
var rsaPrivateKey *rsa.PrivateKey
var ecdsaPrivateKey *ecdsa.PrivateKey
// Instantiate a signer using RSA-PKCS#1v1.5 with SHA-256.
NewSigner(SigningKey{Algorithm: RS256, Key: rsaPrivateKey}, nil)
// Instantiate a signer using ECDSA with SHA-384.
NewSigner(SigningKey{Algorithm: ES384, Key: ecdsaPrivateKey}, nil)
}
func ExampleNewSigner_symmetric() {
var sharedKey []byte
// Instantiate an signer using HMAC-SHA256.
NewSigner(SigningKey{Algorithm: HS256, Key: sharedKey}, nil)
// Instantiate an signer using HMAC-SHA512.
NewSigner(SigningKey{Algorithm: HS512, Key: sharedKey}, nil)
}
func ExampleNewMultiEncrypter() {
var publicKey *rsa.PublicKey
var sharedKey []byte
// Instantiate an encrypter using AES-GCM.
NewMultiEncrypter(A128GCM, []Recipient{
{Algorithm: A128GCMKW, Key: sharedKey},
{Algorithm: RSA_OAEP, Key: publicKey},
}, nil)
}
func ExampleNewMultiSigner() {
var privateKey *rsa.PrivateKey
var sharedKey []byte
// Instantiate a signer for multiple recipients.
NewMultiSigner([]SigningKey{
{Algorithm: HS256, Key: sharedKey},
{Algorithm: PS384, Key: privateKey},
}, nil)
}
func ExampleEncrypter_encrypt() {
// Encrypt a plaintext in order to get an encrypted JWE object.
var plaintext = []byte("This is a secret message")
encrypter.Encrypt(plaintext)
}
func ExampleEncrypter_encryptWithAuthData() {
// Encrypt a plaintext in order to get an encrypted JWE object. Also attach
// some additional authenticated data (AAD) to the object. Note that objects
// with attached AAD can only be represented using full serialization.
var plaintext = []byte("This is a secret message")
var aad = []byte("This is authenticated, but public data")
encrypter.EncryptWithAuthData(plaintext, aad)
}

View file

@ -1,122 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jose
import (
"bytes"
"strings"
"testing"
)
func TestDeflateRoundtrip(t *testing.T) {
original := []byte("Lorem ipsum dolor sit amet")
compressed, err := deflate(original)
if err != nil {
panic(err)
}
output, err := inflate(compressed)
if err != nil {
panic(err)
}
if bytes.Compare(output, original) != 0 {
t.Error("Input and output do not match")
}
}
func TestInvalidCompression(t *testing.T) {
_, err := compress("XYZ", []byte{})
if err == nil {
t.Error("should not accept invalid algorithm")
}
_, err = decompress("XYZ", []byte{})
if err == nil {
t.Error("should not accept invalid algorithm")
}
_, err = decompress(DEFLATE, []byte{1, 2, 3, 4})
if err == nil {
t.Error("should not accept invalid data")
}
}
func TestByteBufferTrim(t *testing.T) {
buf := newBufferFromInt(1)
if !bytes.Equal(buf.data, []byte{1}) {
t.Error("Byte buffer for integer '1' should contain [0x01]")
}
buf = newBufferFromInt(65537)
if !bytes.Equal(buf.data, []byte{1, 0, 1}) {
t.Error("Byte buffer for integer '65537' should contain [0x01, 0x00, 0x01]")
}
}
func TestFixedSizeBuffer(t *testing.T) {
data0 := []byte{}
data1 := []byte{1}
data2 := []byte{1, 2}
data3 := []byte{1, 2, 3}
data4 := []byte{1, 2, 3, 4}
buf0 := newFixedSizeBuffer(data0, 4)
buf1 := newFixedSizeBuffer(data1, 4)
buf2 := newFixedSizeBuffer(data2, 4)
buf3 := newFixedSizeBuffer(data3, 4)
buf4 := newFixedSizeBuffer(data4, 4)
if !bytes.Equal(buf0.data, []byte{0, 0, 0, 0}) {
t.Error("Invalid padded buffer for buf0")
}
if !bytes.Equal(buf1.data, []byte{0, 0, 0, 1}) {
t.Error("Invalid padded buffer for buf1")
}
if !bytes.Equal(buf2.data, []byte{0, 0, 1, 2}) {
t.Error("Invalid padded buffer for buf2")
}
if !bytes.Equal(buf3.data, []byte{0, 1, 2, 3}) {
t.Error("Invalid padded buffer for buf3")
}
if !bytes.Equal(buf4.data, []byte{1, 2, 3, 4}) {
t.Error("Invalid padded buffer for buf4")
}
}
func TestSerializeJSONRejectsNil(t *testing.T) {
defer func() {
r := recover()
if r == nil || !strings.Contains(r.(string), "nil pointer") {
t.Error("serialize function should not accept nil pointer")
}
}()
mustSerializeJSON(nil)
}
func TestFixedSizeBufferTooLarge(t *testing.T) {
defer func() {
r := recover()
if r == nil {
t.Error("should not be able to create fixed size buffer with oversized data")
}
}()
newFixedSizeBuffer(make([]byte, 2), 1)
}

View file

@ -1,223 +0,0 @@
// Copyright 2011 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.
// Large data benchmark.
// The JSON data is a summary of agl's changes in the
// go, webkit, and chromium open source projects.
// We benchmark converting between the JSON form
// and in-memory data structures.
package json
import (
"bytes"
"compress/gzip"
"io/ioutil"
"os"
"strings"
"testing"
)
type codeResponse struct {
Tree *codeNode `json:"tree"`
Username string `json:"username"`
}
type codeNode struct {
Name string `json:"name"`
Kids []*codeNode `json:"kids"`
CLWeight float64 `json:"cl_weight"`
Touches int `json:"touches"`
MinT int64 `json:"min_t"`
MaxT int64 `json:"max_t"`
MeanT int64 `json:"mean_t"`
}
var codeJSON []byte
var codeStruct codeResponse
func codeInit() {
f, err := os.Open("testdata/code.json.gz")
if err != nil {
panic(err)
}
defer f.Close()
gz, err := gzip.NewReader(f)
if err != nil {
panic(err)
}
data, err := ioutil.ReadAll(gz)
if err != nil {
panic(err)
}
codeJSON = data
if err := Unmarshal(codeJSON, &codeStruct); err != nil {
panic("unmarshal code.json: " + err.Error())
}
if data, err = Marshal(&codeStruct); err != nil {
panic("marshal code.json: " + err.Error())
}
if !bytes.Equal(data, codeJSON) {
println("different lengths", len(data), len(codeJSON))
for i := 0; i < len(data) && i < len(codeJSON); i++ {
if data[i] != codeJSON[i] {
println("re-marshal: changed at byte", i)
println("orig: ", string(codeJSON[i-10:i+10]))
println("new: ", string(data[i-10:i+10]))
break
}
}
panic("re-marshal code.json: different result")
}
}
func BenchmarkCodeEncoder(b *testing.B) {
if codeJSON == nil {
b.StopTimer()
codeInit()
b.StartTimer()
}
enc := NewEncoder(ioutil.Discard)
for i := 0; i < b.N; i++ {
if err := enc.Encode(&codeStruct); err != nil {
b.Fatal("Encode:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
}
func BenchmarkCodeMarshal(b *testing.B) {
if codeJSON == nil {
b.StopTimer()
codeInit()
b.StartTimer()
}
for i := 0; i < b.N; i++ {
if _, err := Marshal(&codeStruct); err != nil {
b.Fatal("Marshal:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
}
func BenchmarkCodeDecoder(b *testing.B) {
if codeJSON == nil {
b.StopTimer()
codeInit()
b.StartTimer()
}
var buf bytes.Buffer
dec := NewDecoder(&buf)
var r codeResponse
for i := 0; i < b.N; i++ {
buf.Write(codeJSON)
// hide EOF
buf.WriteByte('\n')
buf.WriteByte('\n')
buf.WriteByte('\n')
if err := dec.Decode(&r); err != nil {
b.Fatal("Decode:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
}
func BenchmarkDecoderStream(b *testing.B) {
b.StopTimer()
var buf bytes.Buffer
dec := NewDecoder(&buf)
buf.WriteString(`"` + strings.Repeat("x", 1000000) + `"` + "\n\n\n")
var x interface{}
if err := dec.Decode(&x); err != nil {
b.Fatal("Decode:", err)
}
ones := strings.Repeat(" 1\n", 300000) + "\n\n\n"
b.StartTimer()
for i := 0; i < b.N; i++ {
if i%300000 == 0 {
buf.WriteString(ones)
}
x = nil
if err := dec.Decode(&x); err != nil || x != 1.0 {
b.Fatalf("Decode: %v after %d", err, i)
}
}
}
func BenchmarkCodeUnmarshal(b *testing.B) {
if codeJSON == nil {
b.StopTimer()
codeInit()
b.StartTimer()
}
for i := 0; i < b.N; i++ {
var r codeResponse
if err := Unmarshal(codeJSON, &r); err != nil {
b.Fatal("Unmmarshal:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
}
func BenchmarkCodeUnmarshalReuse(b *testing.B) {
if codeJSON == nil {
b.StopTimer()
codeInit()
b.StartTimer()
}
var r codeResponse
for i := 0; i < b.N; i++ {
if err := Unmarshal(codeJSON, &r); err != nil {
b.Fatal("Unmmarshal:", err)
}
}
}
func BenchmarkUnmarshalString(b *testing.B) {
data := []byte(`"hello, world"`)
var s string
for i := 0; i < b.N; i++ {
if err := Unmarshal(data, &s); err != nil {
b.Fatal("Unmarshal:", err)
}
}
}
func BenchmarkUnmarshalFloat64(b *testing.B) {
var f float64
data := []byte(`3.14`)
for i := 0; i < b.N; i++ {
if err := Unmarshal(data, &f); err != nil {
b.Fatal("Unmarshal:", err)
}
}
}
func BenchmarkUnmarshalInt64(b *testing.B) {
var x int64
data := []byte(`3`)
for i := 0; i < b.N; i++ {
if err := Unmarshal(data, &x); err != nil {
b.Fatal("Unmarshal:", err)
}
}
}
func BenchmarkIssue10335(b *testing.B) {
b.ReportAllocs()
var s struct{}
j := []byte(`{"a":{ }}`)
for n := 0; n < b.N; n++ {
if err := Unmarshal(j, &s); err != nil {
b.Fatal(err)
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,538 +0,0 @@
// Copyright 2011 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 json
import (
"bytes"
"math"
"reflect"
"testing"
"unicode"
)
type Optionals struct {
Sr string `json:"sr"`
So string `json:"so,omitempty"`
Sw string `json:"-"`
Ir int `json:"omitempty"` // actually named omitempty, not an option
Io int `json:"io,omitempty"`
Slr []string `json:"slr,random"`
Slo []string `json:"slo,omitempty"`
Mr map[string]interface{} `json:"mr"`
Mo map[string]interface{} `json:",omitempty"`
Fr float64 `json:"fr"`
Fo float64 `json:"fo,omitempty"`
Br bool `json:"br"`
Bo bool `json:"bo,omitempty"`
Ur uint `json:"ur"`
Uo uint `json:"uo,omitempty"`
Str struct{} `json:"str"`
Sto struct{} `json:"sto,omitempty"`
}
var optionalsExpected = `{
"sr": "",
"omitempty": 0,
"slr": null,
"mr": {},
"fr": 0,
"br": false,
"ur": 0,
"str": {},
"sto": {}
}`
func TestOmitEmpty(t *testing.T) {
var o Optionals
o.Sw = "something"
o.Mr = map[string]interface{}{}
o.Mo = map[string]interface{}{}
got, err := MarshalIndent(&o, "", " ")
if err != nil {
t.Fatal(err)
}
if got := string(got); got != optionalsExpected {
t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected)
}
}
type StringTag struct {
BoolStr bool `json:",string"`
IntStr int64 `json:",string"`
StrStr string `json:",string"`
}
var stringTagExpected = `{
"BoolStr": "true",
"IntStr": "42",
"StrStr": "\"xzbit\""
}`
func TestStringTag(t *testing.T) {
var s StringTag
s.BoolStr = true
s.IntStr = 42
s.StrStr = "xzbit"
got, err := MarshalIndent(&s, "", " ")
if err != nil {
t.Fatal(err)
}
if got := string(got); got != stringTagExpected {
t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected)
}
// Verify that it round-trips.
var s2 StringTag
err = NewDecoder(bytes.NewReader(got)).Decode(&s2)
if err != nil {
t.Fatalf("Decode: %v", err)
}
if !reflect.DeepEqual(s, s2) {
t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2)
}
}
// byte slices are special even if they're renamed types.
type renamedByte byte
type renamedByteSlice []byte
type renamedRenamedByteSlice []renamedByte
func TestEncodeRenamedByteSlice(t *testing.T) {
s := renamedByteSlice("abc")
result, err := Marshal(s)
if err != nil {
t.Fatal(err)
}
expect := `"YWJj"`
if string(result) != expect {
t.Errorf(" got %s want %s", result, expect)
}
r := renamedRenamedByteSlice("abc")
result, err = Marshal(r)
if err != nil {
t.Fatal(err)
}
if string(result) != expect {
t.Errorf(" got %s want %s", result, expect)
}
}
var unsupportedValues = []interface{}{
math.NaN(),
math.Inf(-1),
math.Inf(1),
}
func TestUnsupportedValues(t *testing.T) {
for _, v := range unsupportedValues {
if _, err := Marshal(v); err != nil {
if _, ok := err.(*UnsupportedValueError); !ok {
t.Errorf("for %v, got %T want UnsupportedValueError", v, err)
}
} else {
t.Errorf("for %v, expected error", v)
}
}
}
// Ref has Marshaler and Unmarshaler methods with pointer receiver.
type Ref int
func (*Ref) MarshalJSON() ([]byte, error) {
return []byte(`"ref"`), nil
}
func (r *Ref) UnmarshalJSON([]byte) error {
*r = 12
return nil
}
// Val has Marshaler methods with value receiver.
type Val int
func (Val) MarshalJSON() ([]byte, error) {
return []byte(`"val"`), nil
}
// RefText has Marshaler and Unmarshaler methods with pointer receiver.
type RefText int
func (*RefText) MarshalText() ([]byte, error) {
return []byte(`"ref"`), nil
}
func (r *RefText) UnmarshalText([]byte) error {
*r = 13
return nil
}
// ValText has Marshaler methods with value receiver.
type ValText int
func (ValText) MarshalText() ([]byte, error) {
return []byte(`"val"`), nil
}
func TestRefValMarshal(t *testing.T) {
var s = struct {
R0 Ref
R1 *Ref
R2 RefText
R3 *RefText
V0 Val
V1 *Val
V2 ValText
V3 *ValText
}{
R0: 12,
R1: new(Ref),
R2: 14,
R3: new(RefText),
V0: 13,
V1: new(Val),
V2: 15,
V3: new(ValText),
}
const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}`
b, err := Marshal(&s)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if got := string(b); got != want {
t.Errorf("got %q, want %q", got, want)
}
}
// C implements Marshaler and returns unescaped JSON.
type C int
func (C) MarshalJSON() ([]byte, error) {
return []byte(`"<&>"`), nil
}
// CText implements Marshaler and returns unescaped text.
type CText int
func (CText) MarshalText() ([]byte, error) {
return []byte(`"<&>"`), nil
}
func TestMarshalerEscaping(t *testing.T) {
var c C
want := `"\u003c\u0026\u003e"`
b, err := Marshal(c)
if err != nil {
t.Fatalf("Marshal(c): %v", err)
}
if got := string(b); got != want {
t.Errorf("Marshal(c) = %#q, want %#q", got, want)
}
var ct CText
want = `"\"\u003c\u0026\u003e\""`
b, err = Marshal(ct)
if err != nil {
t.Fatalf("Marshal(ct): %v", err)
}
if got := string(b); got != want {
t.Errorf("Marshal(ct) = %#q, want %#q", got, want)
}
}
type IntType int
type MyStruct struct {
IntType
}
func TestAnonymousNonstruct(t *testing.T) {
var i IntType = 11
a := MyStruct{i}
const want = `{"IntType":11}`
b, err := Marshal(a)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if got := string(b); got != want {
t.Errorf("got %q, want %q", got, want)
}
}
type BugA struct {
S string
}
type BugB struct {
BugA
S string
}
type BugC struct {
S string
}
// Legal Go: We never use the repeated embedded field (S).
type BugX struct {
A int
BugA
BugB
}
// Issue 5245.
func TestEmbeddedBug(t *testing.T) {
v := BugB{
BugA{"A"},
"B",
}
b, err := Marshal(v)
if err != nil {
t.Fatal("Marshal:", err)
}
want := `{"S":"B"}`
got := string(b)
if got != want {
t.Fatalf("Marshal: got %s want %s", got, want)
}
// Now check that the duplicate field, S, does not appear.
x := BugX{
A: 23,
}
b, err = Marshal(x)
if err != nil {
t.Fatal("Marshal:", err)
}
want = `{"A":23}`
got = string(b)
if got != want {
t.Fatalf("Marshal: got %s want %s", got, want)
}
}
type BugD struct { // Same as BugA after tagging.
XXX string `json:"S"`
}
// BugD's tagged S field should dominate BugA's.
type BugY struct {
BugA
BugD
}
// Test that a field with a tag dominates untagged fields.
func TestTaggedFieldDominates(t *testing.T) {
v := BugY{
BugA{"BugA"},
BugD{"BugD"},
}
b, err := Marshal(v)
if err != nil {
t.Fatal("Marshal:", err)
}
want := `{"S":"BugD"}`
got := string(b)
if got != want {
t.Fatalf("Marshal: got %s want %s", got, want)
}
}
// There are no tags here, so S should not appear.
type BugZ struct {
BugA
BugC
BugY // Contains a tagged S field through BugD; should not dominate.
}
func TestDuplicatedFieldDisappears(t *testing.T) {
v := BugZ{
BugA{"BugA"},
BugC{"BugC"},
BugY{
BugA{"nested BugA"},
BugD{"nested BugD"},
},
}
b, err := Marshal(v)
if err != nil {
t.Fatal("Marshal:", err)
}
want := `{}`
got := string(b)
if got != want {
t.Fatalf("Marshal: got %s want %s", got, want)
}
}
func TestStringBytes(t *testing.T) {
// Test that encodeState.stringBytes and encodeState.string use the same encoding.
es := &encodeState{}
var r []rune
for i := '\u0000'; i <= unicode.MaxRune; i++ {
r = append(r, i)
}
s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too
es.string(s)
esBytes := &encodeState{}
esBytes.stringBytes([]byte(s))
enc := es.Buffer.String()
encBytes := esBytes.Buffer.String()
if enc != encBytes {
i := 0
for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] {
i++
}
enc = enc[i:]
encBytes = encBytes[i:]
i = 0
for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] {
i++
}
enc = enc[:len(enc)-i]
encBytes = encBytes[:len(encBytes)-i]
if len(enc) > 20 {
enc = enc[:20] + "..."
}
if len(encBytes) > 20 {
encBytes = encBytes[:20] + "..."
}
t.Errorf("encodings differ at %#q vs %#q", enc, encBytes)
}
}
func TestIssue6458(t *testing.T) {
type Foo struct {
M RawMessage
}
x := Foo{RawMessage(`"foo"`)}
b, err := Marshal(&x)
if err != nil {
t.Fatal(err)
}
if want := `{"M":"foo"}`; string(b) != want {
t.Errorf("Marshal(&x) = %#q; want %#q", b, want)
}
b, err = Marshal(x)
if err != nil {
t.Fatal(err)
}
if want := `{"M":"ImZvbyI="}`; string(b) != want {
t.Errorf("Marshal(x) = %#q; want %#q", b, want)
}
}
func TestIssue10281(t *testing.T) {
type Foo struct {
N Number
}
x := Foo{Number(`invalid`)}
b, err := Marshal(&x)
if err == nil {
t.Errorf("Marshal(&x) = %#q; want error", b)
}
}
func TestHTMLEscape(t *testing.T) {
var b, want bytes.Buffer
m := `{"M":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}`
want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`))
HTMLEscape(&b, []byte(m))
if !bytes.Equal(b.Bytes(), want.Bytes()) {
t.Errorf("HTMLEscape(&b, []byte(m)) = %s; want %s", b.Bytes(), want.Bytes())
}
}
// golang.org/issue/8582
func TestEncodePointerString(t *testing.T) {
type stringPointer struct {
N *int64 `json:"n,string"`
}
var n int64 = 42
b, err := Marshal(stringPointer{N: &n})
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if got, want := string(b), `{"n":"42"}`; got != want {
t.Errorf("Marshal = %s, want %s", got, want)
}
var back stringPointer
err = Unmarshal(b, &back)
if err != nil {
t.Fatalf("Unmarshal: %v", err)
}
if back.N == nil {
t.Fatalf("Unmarshalled nil N field")
}
if *back.N != 42 {
t.Fatalf("*N = %d; want 42", *back.N)
}
}
var encodeStringTests = []struct {
in string
out string
}{
{"\x00", `"\u0000"`},
{"\x01", `"\u0001"`},
{"\x02", `"\u0002"`},
{"\x03", `"\u0003"`},
{"\x04", `"\u0004"`},
{"\x05", `"\u0005"`},
{"\x06", `"\u0006"`},
{"\x07", `"\u0007"`},
{"\x08", `"\u0008"`},
{"\x09", `"\t"`},
{"\x0a", `"\n"`},
{"\x0b", `"\u000b"`},
{"\x0c", `"\u000c"`},
{"\x0d", `"\r"`},
{"\x0e", `"\u000e"`},
{"\x0f", `"\u000f"`},
{"\x10", `"\u0010"`},
{"\x11", `"\u0011"`},
{"\x12", `"\u0012"`},
{"\x13", `"\u0013"`},
{"\x14", `"\u0014"`},
{"\x15", `"\u0015"`},
{"\x16", `"\u0016"`},
{"\x17", `"\u0017"`},
{"\x18", `"\u0018"`},
{"\x19", `"\u0019"`},
{"\x1a", `"\u001a"`},
{"\x1b", `"\u001b"`},
{"\x1c", `"\u001c"`},
{"\x1d", `"\u001d"`},
{"\x1e", `"\u001e"`},
{"\x1f", `"\u001f"`},
}
func TestEncodeString(t *testing.T) {
for _, tt := range encodeStringTests {
b, err := Marshal(tt.in)
if err != nil {
t.Errorf("Marshal(%q): %v", tt.in, err)
continue
}
out := string(b)
if out != tt.out {
t.Errorf("Marshal(%q) = %#q, want %#q", tt.in, out, tt.out)
}
}
}

View file

@ -1,133 +0,0 @@
// Copyright 2011 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 json
import (
"regexp"
"testing"
)
func TestNumberIsValid(t *testing.T) {
// From: http://stackoverflow.com/a/13340826
var jsonNumberRegexp = regexp.MustCompile(`^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$`)
validTests := []string{
"0",
"-0",
"1",
"-1",
"0.1",
"-0.1",
"1234",
"-1234",
"12.34",
"-12.34",
"12E0",
"12E1",
"12e34",
"12E-0",
"12e+1",
"12e-34",
"-12E0",
"-12E1",
"-12e34",
"-12E-0",
"-12e+1",
"-12e-34",
"1.2E0",
"1.2E1",
"1.2e34",
"1.2E-0",
"1.2e+1",
"1.2e-34",
"-1.2E0",
"-1.2E1",
"-1.2e34",
"-1.2E-0",
"-1.2e+1",
"-1.2e-34",
"0E0",
"0E1",
"0e34",
"0E-0",
"0e+1",
"0e-34",
"-0E0",
"-0E1",
"-0e34",
"-0E-0",
"-0e+1",
"-0e-34",
}
for _, test := range validTests {
if !isValidNumber(test) {
t.Errorf("%s should be valid", test)
}
var f float64
if err := Unmarshal([]byte(test), &f); err != nil {
t.Errorf("%s should be valid but Unmarshal failed: %v", test, err)
}
if !jsonNumberRegexp.MatchString(test) {
t.Errorf("%s should be valid but regexp does not match", test)
}
}
invalidTests := []string{
"",
"invalid",
"1.0.1",
"1..1",
"-1-2",
"012a42",
"01.2",
"012",
"12E12.12",
"1e2e3",
"1e+-2",
"1e--23",
"1e",
"e1",
"1e+",
"1ea",
"1a",
"1.a",
"1.",
"01",
"1.e1",
}
for _, test := range invalidTests {
if isValidNumber(test) {
t.Errorf("%s should be invalid", test)
}
var f float64
if err := Unmarshal([]byte(test), &f); err == nil {
t.Errorf("%s should be invalid but unmarshal wrote %v", test, f)
}
if jsonNumberRegexp.MatchString(test) {
t.Errorf("%s should be invalid but matches regexp", test)
}
}
}
func BenchmarkNumberIsValid(b *testing.B) {
s := "-61657.61667E+61673"
for i := 0; i < b.N; i++ {
isValidNumber(s)
}
}
func BenchmarkNumberIsValidRegexp(b *testing.B) {
var jsonNumberRegexp = regexp.MustCompile(`^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$`)
s := "-61657.61667E+61673"
for i := 0; i < b.N; i++ {
jsonNumberRegexp.MatchString(s)
}
}

View file

@ -1,316 +0,0 @@
// Copyright 2010 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 json
import (
"bytes"
"math"
"math/rand"
"reflect"
"testing"
)
// Tests of simple examples.
type example struct {
compact string
indent string
}
var examples = []example{
{`1`, `1`},
{`{}`, `{}`},
{`[]`, `[]`},
{`{"":2}`, "{\n\t\"\": 2\n}"},
{`[3]`, "[\n\t3\n]"},
{`[1,2,3]`, "[\n\t1,\n\t2,\n\t3\n]"},
{`{"x":1}`, "{\n\t\"x\": 1\n}"},
{ex1, ex1i},
}
var ex1 = `[true,false,null,"x",1,1.5,0,-5e+2]`
var ex1i = `[
true,
false,
null,
"x",
1,
1.5,
0,
-5e+2
]`
func TestCompact(t *testing.T) {
var buf bytes.Buffer
for _, tt := range examples {
buf.Reset()
if err := Compact(&buf, []byte(tt.compact)); err != nil {
t.Errorf("Compact(%#q): %v", tt.compact, err)
} else if s := buf.String(); s != tt.compact {
t.Errorf("Compact(%#q) = %#q, want original", tt.compact, s)
}
buf.Reset()
if err := Compact(&buf, []byte(tt.indent)); err != nil {
t.Errorf("Compact(%#q): %v", tt.indent, err)
continue
} else if s := buf.String(); s != tt.compact {
t.Errorf("Compact(%#q) = %#q, want %#q", tt.indent, s, tt.compact)
}
}
}
func TestCompactSeparators(t *testing.T) {
// U+2028 and U+2029 should be escaped inside strings.
// They should not appear outside strings.
tests := []struct {
in, compact string
}{
{"{\"\u2028\": 1}", `{"\u2028":1}`},
{"{\"\u2029\" :2}", `{"\u2029":2}`},
}
for _, tt := range tests {
var buf bytes.Buffer
if err := Compact(&buf, []byte(tt.in)); err != nil {
t.Errorf("Compact(%q): %v", tt.in, err)
} else if s := buf.String(); s != tt.compact {
t.Errorf("Compact(%q) = %q, want %q", tt.in, s, tt.compact)
}
}
}
func TestIndent(t *testing.T) {
var buf bytes.Buffer
for _, tt := range examples {
buf.Reset()
if err := Indent(&buf, []byte(tt.indent), "", "\t"); err != nil {
t.Errorf("Indent(%#q): %v", tt.indent, err)
} else if s := buf.String(); s != tt.indent {
t.Errorf("Indent(%#q) = %#q, want original", tt.indent, s)
}
buf.Reset()
if err := Indent(&buf, []byte(tt.compact), "", "\t"); err != nil {
t.Errorf("Indent(%#q): %v", tt.compact, err)
continue
} else if s := buf.String(); s != tt.indent {
t.Errorf("Indent(%#q) = %#q, want %#q", tt.compact, s, tt.indent)
}
}
}
// Tests of a large random structure.
func TestCompactBig(t *testing.T) {
initBig()
var buf bytes.Buffer
if err := Compact(&buf, jsonBig); err != nil {
t.Fatalf("Compact: %v", err)
}
b := buf.Bytes()
if !bytes.Equal(b, jsonBig) {
t.Error("Compact(jsonBig) != jsonBig")
diff(t, b, jsonBig)
return
}
}
func TestIndentBig(t *testing.T) {
initBig()
var buf bytes.Buffer
if err := Indent(&buf, jsonBig, "", "\t"); err != nil {
t.Fatalf("Indent1: %v", err)
}
b := buf.Bytes()
if len(b) == len(jsonBig) {
// jsonBig is compact (no unnecessary spaces);
// indenting should make it bigger
t.Fatalf("Indent(jsonBig) did not get bigger")
}
// should be idempotent
var buf1 bytes.Buffer
if err := Indent(&buf1, b, "", "\t"); err != nil {
t.Fatalf("Indent2: %v", err)
}
b1 := buf1.Bytes()
if !bytes.Equal(b1, b) {
t.Error("Indent(Indent(jsonBig)) != Indent(jsonBig)")
diff(t, b1, b)
return
}
// should get back to original
buf1.Reset()
if err := Compact(&buf1, b); err != nil {
t.Fatalf("Compact: %v", err)
}
b1 = buf1.Bytes()
if !bytes.Equal(b1, jsonBig) {
t.Error("Compact(Indent(jsonBig)) != jsonBig")
diff(t, b1, jsonBig)
return
}
}
type indentErrorTest struct {
in string
err error
}
var indentErrorTests = []indentErrorTest{
{`{"X": "foo", "Y"}`, &SyntaxError{"invalid character '}' after object key", 17}},
{`{"X": "foo" "Y": "bar"}`, &SyntaxError{"invalid character '\"' after object key:value pair", 13}},
}
func TestIndentErrors(t *testing.T) {
for i, tt := range indentErrorTests {
slice := make([]uint8, 0)
buf := bytes.NewBuffer(slice)
if err := Indent(buf, []uint8(tt.in), "", ""); err != nil {
if !reflect.DeepEqual(err, tt.err) {
t.Errorf("#%d: Indent: %#v", i, err)
continue
}
}
}
}
func TestNextValueBig(t *testing.T) {
initBig()
var scan scanner
item, rest, err := nextValue(jsonBig, &scan)
if err != nil {
t.Fatalf("nextValue: %s", err)
}
if len(item) != len(jsonBig) || &item[0] != &jsonBig[0] {
t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
}
if len(rest) != 0 {
t.Errorf("invalid rest: %d", len(rest))
}
item, rest, err = nextValue(append(jsonBig, "HELLO WORLD"...), &scan)
if err != nil {
t.Fatalf("nextValue extra: %s", err)
}
if len(item) != len(jsonBig) {
t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
}
if string(rest) != "HELLO WORLD" {
t.Errorf("invalid rest: %d", len(rest))
}
}
var benchScan scanner
func BenchmarkSkipValue(b *testing.B) {
initBig()
b.ResetTimer()
for i := 0; i < b.N; i++ {
nextValue(jsonBig, &benchScan)
}
b.SetBytes(int64(len(jsonBig)))
}
func diff(t *testing.T, a, b []byte) {
for i := 0; ; i++ {
if i >= len(a) || i >= len(b) || a[i] != b[i] {
j := i - 10
if j < 0 {
j = 0
}
t.Errorf("diverge at %d: «%s» vs «%s»", i, trim(a[j:]), trim(b[j:]))
return
}
}
}
func trim(b []byte) []byte {
if len(b) > 20 {
return b[0:20]
}
return b
}
// Generate a random JSON object.
var jsonBig []byte
func initBig() {
n := 10000
if testing.Short() {
n = 100
}
b, err := Marshal(genValue(n))
if err != nil {
panic(err)
}
jsonBig = b
}
func genValue(n int) interface{} {
if n > 1 {
switch rand.Intn(2) {
case 0:
return genArray(n)
case 1:
return genMap(n)
}
}
switch rand.Intn(3) {
case 0:
return rand.Intn(2) == 0
case 1:
return rand.NormFloat64()
case 2:
return genString(30)
}
panic("unreachable")
}
func genString(stddev float64) string {
n := int(math.Abs(rand.NormFloat64()*stddev + stddev/2))
c := make([]rune, n)
for i := range c {
f := math.Abs(rand.NormFloat64()*64 + 32)
if f > 0x10ffff {
f = 0x10ffff
}
c[i] = rune(f)
}
return string(c)
}
func genArray(n int) []interface{} {
f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2)))
if f > n {
f = n
}
if f < 1 {
f = 1
}
x := make([]interface{}, f)
for i := range x {
x[i] = genValue(((i+1)*n)/f - (i*n)/f)
}
return x
}
func genMap(n int) map[string]interface{} {
f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2)))
if f > n {
f = n
}
if n > 0 && f == 0 {
f = 1
}
x := make(map[string]interface{})
for i := 0; i < f; i++ {
x[genString(10)] = genValue(((i+1)*n)/f - (i*n)/f)
}
return x
}

View file

@ -1,354 +0,0 @@
// Copyright 2010 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 json
import (
"bytes"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"net/http/httptest"
"reflect"
"strings"
"testing"
)
// Test values for the stream test.
// One of each JSON kind.
var streamTest = []interface{}{
0.1,
"hello",
nil,
true,
false,
[]interface{}{"a", "b", "c"},
map[string]interface{}{"": "Kelvin", "ß": "long s"},
3.14, // another value to make sure something can follow map
}
var streamEncoded = `0.1
"hello"
null
true
false
["a","b","c"]
{"ß":"long s","":"Kelvin"}
3.14
`
func TestEncoder(t *testing.T) {
for i := 0; i <= len(streamTest); i++ {
var buf bytes.Buffer
enc := NewEncoder(&buf)
for j, v := range streamTest[0:i] {
if err := enc.Encode(v); err != nil {
t.Fatalf("encode #%d: %v", j, err)
}
}
if have, want := buf.String(), nlines(streamEncoded, i); have != want {
t.Errorf("encoding %d items: mismatch", i)
diff(t, []byte(have), []byte(want))
break
}
}
}
func TestDecoder(t *testing.T) {
for i := 0; i <= len(streamTest); i++ {
// Use stream without newlines as input,
// just to stress the decoder even more.
// Our test input does not include back-to-back numbers.
// Otherwise stripping the newlines would
// merge two adjacent JSON values.
var buf bytes.Buffer
for _, c := range nlines(streamEncoded, i) {
if c != '\n' {
buf.WriteRune(c)
}
}
out := make([]interface{}, i)
dec := NewDecoder(&buf)
for j := range out {
if err := dec.Decode(&out[j]); err != nil {
t.Fatalf("decode #%d/%d: %v", j, i, err)
}
}
if !reflect.DeepEqual(out, streamTest[0:i]) {
t.Errorf("decoding %d items: mismatch", i)
for j := range out {
if !reflect.DeepEqual(out[j], streamTest[j]) {
t.Errorf("#%d: have %v want %v", j, out[j], streamTest[j])
}
}
break
}
}
}
func TestDecoderBuffered(t *testing.T) {
r := strings.NewReader(`{"Name": "Gopher"} extra `)
var m struct {
Name string
}
d := NewDecoder(r)
err := d.Decode(&m)
if err != nil {
t.Fatal(err)
}
if m.Name != "Gopher" {
t.Errorf("Name = %q; want Gopher", m.Name)
}
rest, err := ioutil.ReadAll(d.Buffered())
if err != nil {
t.Fatal(err)
}
if g, w := string(rest), " extra "; g != w {
t.Errorf("Remaining = %q; want %q", g, w)
}
}
func nlines(s string, n int) string {
if n <= 0 {
return ""
}
for i, c := range s {
if c == '\n' {
if n--; n == 0 {
return s[0 : i+1]
}
}
}
return s
}
func TestRawMessage(t *testing.T) {
// TODO(rsc): Should not need the * in *RawMessage
var data struct {
X float64
Id *RawMessage
Y float32
}
const raw = `["\u0056",null]`
const msg = `{"X":0.1,"Id":["\u0056",null],"Y":0.2}`
err := Unmarshal([]byte(msg), &data)
if err != nil {
t.Fatalf("Unmarshal: %v", err)
}
if string([]byte(*data.Id)) != raw {
t.Fatalf("Raw mismatch: have %#q want %#q", []byte(*data.Id), raw)
}
b, err := Marshal(&data)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if string(b) != msg {
t.Fatalf("Marshal: have %#q want %#q", b, msg)
}
}
func TestNullRawMessage(t *testing.T) {
// TODO(rsc): Should not need the * in *RawMessage
var data struct {
X float64
Id *RawMessage
Y float32
}
data.Id = new(RawMessage)
const msg = `{"X":0.1,"Id":null,"Y":0.2}`
err := Unmarshal([]byte(msg), &data)
if err != nil {
t.Fatalf("Unmarshal: %v", err)
}
if data.Id != nil {
t.Fatalf("Raw mismatch: have non-nil, want nil")
}
b, err := Marshal(&data)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if string(b) != msg {
t.Fatalf("Marshal: have %#q want %#q", b, msg)
}
}
var blockingTests = []string{
`{"x": 1}`,
`[1, 2, 3]`,
}
func TestBlocking(t *testing.T) {
for _, enc := range blockingTests {
r, w := net.Pipe()
go w.Write([]byte(enc))
var val interface{}
// If Decode reads beyond what w.Write writes above,
// it will block, and the test will deadlock.
if err := NewDecoder(r).Decode(&val); err != nil {
t.Errorf("decoding %s: %v", enc, err)
}
r.Close()
w.Close()
}
}
func BenchmarkEncoderEncode(b *testing.B) {
b.ReportAllocs()
type T struct {
X, Y string
}
v := &T{"foo", "bar"}
for i := 0; i < b.N; i++ {
if err := NewEncoder(ioutil.Discard).Encode(v); err != nil {
b.Fatal(err)
}
}
}
type tokenStreamCase struct {
json string
expTokens []interface{}
}
type decodeThis struct {
v interface{}
}
var tokenStreamCases []tokenStreamCase = []tokenStreamCase{
// streaming token cases
{json: `10`, expTokens: []interface{}{float64(10)}},
{json: ` [10] `, expTokens: []interface{}{
Delim('['), float64(10), Delim(']')}},
{json: ` [false,10,"b"] `, expTokens: []interface{}{
Delim('['), false, float64(10), "b", Delim(']')}},
{json: `{ "a": 1 }`, expTokens: []interface{}{
Delim('{'), "a", float64(1), Delim('}')}},
{json: `{"a": 1, "b":"3"}`, expTokens: []interface{}{
Delim('{'), "a", float64(1), "b", "3", Delim('}')}},
{json: ` [{"a": 1},{"a": 2}] `, expTokens: []interface{}{
Delim('['),
Delim('{'), "a", float64(1), Delim('}'),
Delim('{'), "a", float64(2), Delim('}'),
Delim(']')}},
{json: `{"obj": {"a": 1}}`, expTokens: []interface{}{
Delim('{'), "obj", Delim('{'), "a", float64(1), Delim('}'),
Delim('}')}},
{json: `{"obj": [{"a": 1}]}`, expTokens: []interface{}{
Delim('{'), "obj", Delim('['),
Delim('{'), "a", float64(1), Delim('}'),
Delim(']'), Delim('}')}},
// streaming tokens with intermittent Decode()
{json: `{ "a": 1 }`, expTokens: []interface{}{
Delim('{'), "a",
decodeThis{float64(1)},
Delim('}')}},
{json: ` [ { "a" : 1 } ] `, expTokens: []interface{}{
Delim('['),
decodeThis{map[string]interface{}{"a": float64(1)}},
Delim(']')}},
{json: ` [{"a": 1},{"a": 2}] `, expTokens: []interface{}{
Delim('['),
decodeThis{map[string]interface{}{"a": float64(1)}},
decodeThis{map[string]interface{}{"a": float64(2)}},
Delim(']')}},
{json: `{ "obj" : [ { "a" : 1 } ] }`, expTokens: []interface{}{
Delim('{'), "obj", Delim('['),
decodeThis{map[string]interface{}{"a": float64(1)}},
Delim(']'), Delim('}')}},
{json: `{"obj": {"a": 1}}`, expTokens: []interface{}{
Delim('{'), "obj",
decodeThis{map[string]interface{}{"a": float64(1)}},
Delim('}')}},
{json: `{"obj": [{"a": 1}]}`, expTokens: []interface{}{
Delim('{'), "obj",
decodeThis{[]interface{}{
map[string]interface{}{"a": float64(1)},
}},
Delim('}')}},
{json: ` [{"a": 1} {"a": 2}] `, expTokens: []interface{}{
Delim('['),
decodeThis{map[string]interface{}{"a": float64(1)}},
decodeThis{&SyntaxError{"expected comma after array element", 0}},
}},
{json: `{ "a" 1 }`, expTokens: []interface{}{
Delim('{'), "a",
decodeThis{&SyntaxError{"expected colon after object key", 0}},
}},
}
func TestDecodeInStream(t *testing.T) {
for ci, tcase := range tokenStreamCases {
dec := NewDecoder(strings.NewReader(tcase.json))
for i, etk := range tcase.expTokens {
var tk interface{}
var err error
if dt, ok := etk.(decodeThis); ok {
etk = dt.v
err = dec.Decode(&tk)
} else {
tk, err = dec.Token()
}
if experr, ok := etk.(error); ok {
if err == nil || err.Error() != experr.Error() {
t.Errorf("case %v: Expected error %v in %q, but was %v", ci, experr, tcase.json, err)
}
break
} else if err == io.EOF {
t.Errorf("case %v: Unexpected EOF in %q", ci, tcase.json)
break
} else if err != nil {
t.Errorf("case %v: Unexpected error '%v' in %q", ci, err, tcase.json)
break
}
if !reflect.DeepEqual(tk, etk) {
t.Errorf(`case %v: %q @ %v expected %T(%v) was %T(%v)`, ci, tcase.json, i, etk, etk, tk, tk)
break
}
}
}
}
// Test from golang.org/issue/11893
func TestHTTPDecoding(t *testing.T) {
const raw = `{ "foo": "bar" }`
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(raw))
}))
defer ts.Close()
res, err := http.Get(ts.URL)
if err != nil {
log.Fatalf("GET failed: %v", err)
}
defer res.Body.Close()
foo := struct {
Foo string `json:"foo"`
}{}
d := NewDecoder(res.Body)
err = d.Decode(&foo)
if err != nil {
t.Fatalf("Decode: %v", err)
}
if foo.Foo != "bar" {
t.Errorf("decoded %q; want \"bar\"", foo.Foo)
}
// make sure we get the EOF the second time
err = d.Decode(&foo)
if err != io.EOF {
t.Errorf("err = %v; want io.EOF", err)
}
}

View file

@ -1,115 +0,0 @@
// Copyright 2011 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 json
import (
"testing"
)
type basicLatin2xTag struct {
V string `json:"$%-/"`
}
type basicLatin3xTag struct {
V string `json:"0123456789"`
}
type basicLatin4xTag struct {
V string `json:"ABCDEFGHIJKLMO"`
}
type basicLatin5xTag struct {
V string `json:"PQRSTUVWXYZ_"`
}
type basicLatin6xTag struct {
V string `json:"abcdefghijklmno"`
}
type basicLatin7xTag struct {
V string `json:"pqrstuvwxyz"`
}
type miscPlaneTag struct {
V string `json:"色は匂へど"`
}
type percentSlashTag struct {
V string `json:"text/html%"` // https://golang.org/issue/2718
}
type punctuationTag struct {
V string `json:"!#$%&()*+-./:<=>?@[]^_{|}~"` // https://golang.org/issue/3546
}
type emptyTag struct {
W string
}
type misnamedTag struct {
X string `jsom:"Misnamed"`
}
type badFormatTag struct {
Y string `:"BadFormat"`
}
type badCodeTag struct {
Z string `json:" !\"#&'()*+,."`
}
type spaceTag struct {
Q string `json:"With space"`
}
type unicodeTag struct {
W string `json:"Ελλάδα"`
}
var structTagObjectKeyTests = []struct {
raw interface{}
value string
key string
}{
{basicLatin2xTag{"2x"}, "2x", "$%-/"},
{basicLatin3xTag{"3x"}, "3x", "0123456789"},
{basicLatin4xTag{"4x"}, "4x", "ABCDEFGHIJKLMO"},
{basicLatin5xTag{"5x"}, "5x", "PQRSTUVWXYZ_"},
{basicLatin6xTag{"6x"}, "6x", "abcdefghijklmno"},
{basicLatin7xTag{"7x"}, "7x", "pqrstuvwxyz"},
{miscPlaneTag{"いろはにほへと"}, "いろはにほへと", "色は匂へど"},
{emptyTag{"Pour Moi"}, "Pour Moi", "W"},
{misnamedTag{"Animal Kingdom"}, "Animal Kingdom", "X"},
{badFormatTag{"Orfevre"}, "Orfevre", "Y"},
{badCodeTag{"Reliable Man"}, "Reliable Man", "Z"},
{percentSlashTag{"brut"}, "brut", "text/html%"},
{punctuationTag{"Union Rags"}, "Union Rags", "!#$%&()*+-./:<=>?@[]^_{|}~"},
{spaceTag{"Perreddu"}, "Perreddu", "With space"},
{unicodeTag{"Loukanikos"}, "Loukanikos", "Ελλάδα"},
}
func TestStructTagObjectKey(t *testing.T) {
for _, tt := range structTagObjectKeyTests {
b, err := Marshal(tt.raw)
if err != nil {
t.Fatalf("Marshal(%#q) failed: %v", tt.raw, err)
}
var f interface{}
err = Unmarshal(b, &f)
if err != nil {
t.Fatalf("Unmarshal(%#q) failed: %v", b, err)
}
for i, v := range f.(map[string]interface{}) {
switch i {
case tt.key:
if s, ok := v.(string); !ok || s != tt.value {
t.Fatalf("Unexpected value: %#q, want %v", s, tt.value)
}
default:
t.Fatalf("Unexpected key: %#q, from %#q", i, b)
}
}
}
}

View file

@ -1,28 +0,0 @@
// Copyright 2011 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 json
import (
"testing"
)
func TestTagParsing(t *testing.T) {
name, opts := parseTag("field,foobar,foo")
if name != "field" {
t.Fatalf("name = %q, want field", name)
}
for _, tt := range []struct {
opt string
want bool
}{
{"foobar", true},
{"foo", true},
{"bar", false},
} {
if opts.Contains(tt.opt) != tt.want {
t.Errorf("Contains(%q) = %v", tt.opt, !tt.want)
}
}
}

View file

@ -1,543 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jose
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"math/big"
"testing"
)
func TestCompactParseJWE(t *testing.T) {
// Should parse
msg := "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.dGVzdA"
_, err := ParseEncrypted(msg)
if err != nil {
t.Error("Unable to parse valid message:", err)
}
// Messages that should fail to parse
failures := []string{
// Too many parts
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
// Not enough parts
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA",
// Invalid encrypted key
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.//////.dGVzdA.dGVzdA.dGVzdA",
// Invalid IV
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.//////.dGVzdA.dGVzdA",
// Invalid ciphertext
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.//////.dGVzdA",
// Invalid tag
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.//////",
// Invalid header
"W10.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
// Invalid header
"######.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
// Missing alc/enc params
"e30.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
}
for _, msg := range failures {
_, err = ParseEncrypted(msg)
if err == nil {
t.Error("Able to parse invalid message", msg)
}
}
}
func TestFullParseJWE(t *testing.T) {
// Messages that should succeed to parse
successes := []string{
// Flattened serialization, single recipient
"{\"protected\":\"eyJhbGciOiJYWVoiLCJlbmMiOiJYWVoifQo\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
// Unflattened serialization, single recipient
"{\"protected\":\"\",\"unprotected\":{\"enc\":\"XYZ\"},\"recipients\":[{\"header\":{\"alg\":\"XYZ\"},\"encrypted_key\":\"QUJD\"}],\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
}
for i := range successes {
_, err := ParseEncrypted(successes[i])
if err != nil {
t.Error("Unble to parse valid message", err, successes[i])
}
}
// Messages that should fail to parse
failures := []string{
// Empty
"{}",
// Invalid JSON
"{XX",
// Invalid protected header
"{\"protected\":\"###\"}",
// Invalid protected header
"{\"protected\":\"e1gK\"}",
// Invalid encrypted key
"{\"protected\":\"e30\",\"encrypted_key\":\"###\"}",
// Invalid IV
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"###\"}",
// Invalid ciphertext
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"###\"}",
// Invalid tag
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"###\"}",
// Invalid AAD
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\",\"aad\":\"###\"}",
// Missing alg/enc headers
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
// Missing enc header
"{\"protected\":\"eyJhbGciOiJYWVoifQ\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
// Missing alg header
"{\"protected\":\"eyJlbmMiOiJYWVoifQ\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
// Unflattened serialization, single recipient, invalid encrypted_key
"{\"protected\":\"\",\"recipients\":[{\"header\":{\"alg\":\"XYZ\", \"enc\":\"XYZ\"},\"encrypted_key\":\"###\"}],\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
// Unflattened serialization, single recipient, missing alg
"{\"protected\":\"eyJhbGciOiJYWVoifQ\",\"recipients\":[{\"encrypted_key\":\"QUJD\"}],\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
}
for i := range failures {
_, err := ParseEncrypted(failures[i])
if err == nil {
t.Error("Able to parse invalid message", err, failures[i])
}
}
}
func TestMissingInvalidHeaders(t *testing.T) {
protected := &rawHeader{}
protected.set(headerEncryption, A128GCM)
obj := &JSONWebEncryption{
protected: protected,
unprotected: &rawHeader{},
recipients: []recipientInfo{
{},
},
}
_, err := obj.Decrypt(nil)
if err != ErrUnsupportedKeyType {
t.Error("should detect invalid key")
}
obj.unprotected.set(headerCritical, []string{"1", "2"})
_, err = obj.Decrypt(nil)
if err == nil {
t.Error("should reject message with crit header")
}
obj.unprotected.set(headerCritical, nil)
obj.protected = &rawHeader{}
obj.protected.set(headerAlgorithm, RSA1_5)
_, err = obj.Decrypt(rsaTestKey)
if err == nil || err == ErrCryptoFailure {
t.Error("should detect missing enc header")
}
}
func TestRejectUnprotectedJWENonce(t *testing.T) {
// No need to test compact, since that's always protected
// Flattened JSON
input := `{
"header": {
"alg": "XYZ", "enc": "XYZ",
"nonce": "should-cause-an-error"
},
"encrypted_key": "does-not-matter",
"aad": "does-not-matter",
"iv": "does-not-matter",
"ciphertext": "does-not-matter",
"tag": "does-not-matter"
}`
_, err := ParseEncrypted(input)
if err == nil {
t.Error("JWE with an unprotected nonce parsed as valid.")
} else if err.Error() != "square/go-jose: Nonce parameter included in unprotected header" {
t.Errorf("Improper error for unprotected nonce: %v", err)
}
input = `{
"unprotected": {
"alg": "XYZ", "enc": "XYZ",
"nonce": "should-cause-an-error"
},
"encrypted_key": "does-not-matter",
"aad": "does-not-matter",
"iv": "does-not-matter",
"ciphertext": "does-not-matter",
"tag": "does-not-matter"
}`
_, err = ParseEncrypted(input)
if err == nil {
t.Error("JWE with an unprotected nonce parsed as valid.")
} else if err.Error() != "square/go-jose: Nonce parameter included in unprotected header" {
t.Errorf("Improper error for unprotected nonce: %v", err)
}
// Full JSON
input = `{
"header": { "alg": "XYZ", "enc": "XYZ" },
"aad": "does-not-matter",
"iv": "does-not-matter",
"ciphertext": "does-not-matter",
"tag": "does-not-matter",
"recipients": [{
"header": { "nonce": "should-cause-an-error" },
"encrypted_key": "does-not-matter"
}]
}`
_, err = ParseEncrypted(input)
if err == nil {
t.Error("JWS with an unprotected nonce parsed as valid.")
} else if err.Error() != "square/go-jose: Nonce parameter included in unprotected header" {
t.Errorf("Improper error for unprotected nonce: %v", err)
}
}
func TestCompactSerialize(t *testing.T) {
// Compact serialization must fail if we have unprotected headers
obj := &JSONWebEncryption{
unprotected: &rawHeader{},
}
obj.unprotected.set(headerAlgorithm, "XYZ")
_, err := obj.CompactSerialize()
if err == nil {
t.Error("Object with unprotected headers can't be compact serialized")
}
}
func TestVectorsJWE(t *testing.T) {
plaintext := []byte("The true sign of intelligence is not knowledge but imagination.")
publicKey := &rsa.PublicKey{
N: fromBase64Int(`
oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUW
cJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3S
psk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2a
sbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMS
tPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2dj
YgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw`),
E: 65537,
}
expectedCompact := stripWhitespace(`
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.ROQCfge4JPm_
yACxv1C1NSXmwNbL6kvmCuyxBRGpW57DvlwByjyjsb6g8m7wtLMqKEyhFCn
tV7sjippEePIlKln6BvVnz5ZLXHNYQgmubuNq8MC0KTwcaGJ_C0z_T8j4PZ
a1nfpbhSe-ePYaALrf_nIsSRKu7cWsrwOSlaRPecRnYeDd_ytAxEQWYEKFi
Pszc70fP9geZOB_09y9jq0vaOF0jGmpIAmgk71lCcUpSdrhNokTKo5y8MH8
3NcbIvmuZ51cjXQj1f0_AwM9RW3oCh2Hu0z0C5l4BujZVsDuGgMsGZsjUhS
RZsAQSXHCAmlJ2NlnN60U7y4SPJhKv5tKYw.48V1_ALb6US04U3b.5eym8T
W_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiS
diwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ`)
expectedFull := stripWhitespace(`
{ "protected":"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ",
"encrypted_key":
"ROQCfge4JPm_yACxv1C1NSXmwNbL6kvmCuyxBRGpW57DvlwByjyjsb
6g8m7wtLMqKEyhFCntV7sjippEePIlKln6BvVnz5ZLXHNYQgmubuNq
8MC0KTwcaGJ_C0z_T8j4PZa1nfpbhSe-ePYaALrf_nIsSRKu7cWsrw
OSlaRPecRnYeDd_ytAxEQWYEKFiPszc70fP9geZOB_09y9jq0vaOF0
jGmpIAmgk71lCcUpSdrhNokTKo5y8MH83NcbIvmuZ51cjXQj1f0_Aw
M9RW3oCh2Hu0z0C5l4BujZVsDuGgMsGZsjUhSRZsAQSXHCAmlJ2Nln
N60U7y4SPJhKv5tKYw",
"iv": "48V1_ALb6US04U3b",
"ciphertext":
"5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFS
hS8iB7j6jiSdiwkIr3ajwQzaBtQD_A",
"tag":"XFBoMYUZodetZdvTiFvSkQ" }`)
// Mock random reader
randReader = bytes.NewReader([]byte{
// Encryption key
177, 161, 244, 128, 84, 143, 225, 115, 63, 180, 3, 255, 107, 154,
212, 246, 138, 7, 110, 91, 112, 46, 34, 105, 47, 130, 203, 46, 122,
234, 64, 252,
// Randomness for RSA-OAEP
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Initialization vector
227, 197, 117, 252, 2, 219, 233, 68, 180, 225, 77, 219})
defer resetRandReader()
// Encrypt with a dummy key
encrypter, err := NewEncrypter(A256GCM, Recipient{Algorithm: RSA_OAEP, Key: publicKey}, nil)
if err != nil {
panic(err)
}
object, err := encrypter.Encrypt(plaintext)
if err != nil {
panic(err)
}
serialized, err := object.CompactSerialize()
if serialized != expectedCompact {
t.Error("Compact serialization is not what we expected", serialized, expectedCompact)
}
serialized = object.FullSerialize()
if serialized != expectedFull {
t.Error("Full serialization is not what we expected")
}
}
func TestVectorsJWECorrupt(t *testing.T) {
priv := &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: fromHexInt(`
a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8
ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0c
bc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bd
bf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93
ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb`),
E: 65537,
},
D: fromHexInt(`
53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf1195
17ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d
4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d6
5a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb
04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1`),
Primes: []*big.Int{
fromHexInt(`
d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262
864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c
2f26a471dcad212eac7ca39d`),
fromHexInt(`
cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb3
3d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af
72bfe9a030e860b0288b5d77`),
},
}
corruptCiphertext := stripWhitespace(`
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.NFl09dehy
IR2Oh5iSsvEa82Ps7DLjRHeo0RnuTuSR45OsaIP6U8yu7vLlWaZKSZMy
B2qRBSujf-5XIRoNhtyIyjk81eJRXGa_Bxaor1XBCMyyhGchW2H2P71f
PhDO6ufSC7kV4bNqgHR-4ziS7KXwzN83_5kogXqxUpymUoJDNc.tk-GT
W_VVhiTIKFF.D_BE6ImZUl9F.52a-zFnRb3YQwIC7UrhVyQ`)
corruptAuthtag := stripWhitespace(`
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.NFl09dehy
IR2Oh5iSsvEa82Ps7DLjRHeo0RnuTuSR45OsaIP6U8yu7vLlWaZKSZMy
B2qRBSujf-5XIRoNhtyIyjk81eJRXGa_Bxaor1XBCMyyhGchW2H2P71f
PhDO6ufSC7kV4bNqgHR-4ziS7KNwzN83_5kogXqxUpymUoJDNc.tk-GT
W_VVhiTIKFF.D_BE6ImZUl9F.52a-zFnRb3YQwiC7UrhVyQ`)
msg, _ := ParseEncrypted(corruptCiphertext)
_, err := msg.Decrypt(priv)
if err != ErrCryptoFailure {
t.Error("should detect corrupt ciphertext")
}
msg, _ = ParseEncrypted(corruptAuthtag)
_, err = msg.Decrypt(priv)
if err != ErrCryptoFailure {
t.Error("should detect corrupt auth tag")
}
}
// Test vectors generated with nimbus-jose-jwt
func TestSampleNimbusJWEMessagesRSA(t *testing.T) {
rsaPrivateKey, err := x509.ParsePKCS8PrivateKey(fromBase64Bytes(`
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCNRCEmf5PlbXKuT4uwnb
wGKvFrtpi+bDYxOZxxqxdVkZM/bYATAnD1fg9pNvLMKeF+MWJ9kPIMmDgOh9RdnRdLvQGb
BzhLmxwhhcua2QYiHEZizXmiaXvNP12bzEBhebdX7ObW8izMVW0p0lqHPNzkK3K75B0Sxo
FMVKkZ7KtBHgepBT5yPhPPcNe5lXQeTne5bo3I60DRcN9jTBgMJOXdq0I9o4y6ZmoXdNTm
0EyLzn9/EYiHqBxtKFh791EHR7wYgyi/t+nOKr4sO74NbEByP0mHDil+mPvZSzFW4l7fPx
OclRZvpRIKIub2TroZA9s2WsshGf79eqqXYbBB9NNRAgMBAAECggEAIExbZ/nzTplfhwsY
3SCzRJW87OuqsJ79JPQPGM4NX7sQ94eJqM7+FKLl0yCFErjgnYGdCyiArvB+oJPdsimgke
h83X0hGeg03lVA3/6OsG3WifCAxulnLN44AM8KST8S9D9t5+cm5vEBLHazzAfWWTS13s+g
9hH8rf8NSqgZ36EutjKlvLdHx1mWcKX7SREFVHT8FWPAbdhTLEHUjoWHrfSektnczaSHnt
q8fFJy6Ld13QkF1ZJRUhtA24XrD+qLTc+M36IuedjeZaLHFB+KyhYR3YvXEtrbCug7dCRd
uG6uTlDCSaSy7xHeTPolWtWo9F202jal54otxiAJFGUHgQKBgQDRAT0s6YQZUfwE0wluXV
k0JdhDdCo8sC1aMmKlRKWUkBAqrDl7BI3MF56VOr4ybr90buuscshFf9TtrtBOjHSGcfDI
tSKfhhkW5ewQKB0YqyHzoD6UKT0/XAshFY3esc3uCxuJ/6vOiXV0og9o7eFvr51O0TfDFh
mcTvW4wirKlQKBgQCtB7UAu8I9Nn8czkd6oXLDRyTWYviuiqFmxR+PM9klgZtsumkeSxO1
lkfFoj9+G8nFaqYEBA9sPeNtJVTSROCvj/iQtoqpV2NiI/wWeVszpBwsswx2mlks4LJa8a
Yz9xrsfNoroKYVppefc/MCoSx4M+99RSm3FSpLGZQHAUGyzQKBgQDMQmq4JuuMF1y2lk0E
SESyuz21BqV0tDVOjilsHT+5hmXWXoS6nkO6L2czrrpM7YE82F6JJZBmo7zEIXHBInGLJ3
XLoYLZ5qNEhqYDUEDHaBCBWZ1vDTKnZlwWFEuXVavNNZvPbUhKTHq25t8qjDki/r09Vykp
BsM2yNBKpbBOVQKBgCJyUVd3CaFUExQyAMrqD0XPCQdhJq7gzGcAQVsp8EXmOoH3zmuIeM
ECzQEMXuWFNLMHm0tbX5Kl83vMHcnKioyI9ewhWxOBYTitf0ceG8j5F97SOl32NmCXzwoJ
55Oa0xJXfLuIvOe8hZzp4WwZmBfKBxiCR166aPQQgIawelrVAoGAEJsHomfCI4epxH4oMw
qYJMCGy95zloB+2+c86BZCOJAGwnfzbtc2eutWZw61/9sSO8sQCfzA8oX+5HwAgnFVzwW4
lNMZohppYcpwN9EyjkPaCXuALC7p5rF2o63wY7JLvnjS2aYZliknh2yW6X6fSB0PK0Cpvd
lAIyRw6Kud0zI=`))
if err != nil {
panic(err)
}
rsaSampleMessages := []string{
"eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBMV81In0.EW0KOhHeoAxTBnLjYhh2T6HjwI-srNs6RpcSdZvE-GJ5iww3EYWBCmeGGj1UVz6OcBfwW3wllZ6GPOHU-hxVQH5KYpVOjkmrFIYU6-8BHhxBP_PjSJEBCZzjOgsCm9Th4-zmlO7UWTdK_UtwE7nk4X-kkmEy-aZBCShA8nFe2MVvqD5F7nvEWNFBOHh8ae_juo-kvycoIzvxLV9g1B0Zn8K9FAlu8YF1KiL5NFekn76f3jvAwlExuRbFPUx4gJN6CeBDK_D57ABsY2aBVDSiQceuYZxvCIAajqSS6dMT382FNJzAiQhToOpo_1w5FnnBjzJLLEKDk_I-Eo2YCWxxsQ.5mCMuxJqLRuPXGAr.Ghe4INeBhP3MDWGvyNko7qanKdZIzKjfeiU.ja3UlVWJXKNFJ-rZsJWycw",
"eyJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiUlNBMV81In0.JsJeYoP0St1bRYNUaAmA34DAA27usE7RNuC2grGikBRmh1xrwUOpnEIXXpwr7fjVmNi52zzWkNHC8JkkRTrLcCh2VXvnOnarpH8DCr9qM6440bSrahzbxIvDds8z8q0wT1W4kjVnq1mGwGxg8RQNBWTV6Sp2FLQkZyjzt_aXsgYzr3zEmLZxB-d41lBS81Mguk_hdFJIg_WO4ao54lozvxkCn_uMiIZ8eLb8qHy0h-N21tiHGCaiC2vV8KXomwoqbJ0SXrEH4r9_R2J844H80TBZdbvNBd8whvoQNHvOX659LNs9EQ9xxvHU2kqGZekXBu7sDXXTjctMkMITobGSzw.1v5govaDvanP3LGp.llwYNBDrD7MwVLaFHesljlratfmndWs4XPQ.ZGT1zk9_yIKi2GzW6CuAyA",
"eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBMV81In0.fBv3fA3TMS3ML8vlsCuvwdsKvB0ym8R30jJrlOiqkWKk7WVUkjDInFzr1zw3Owla6c5BqOJNoACXt4IWbkLbkoWV3tweXlWwpafuaWPkjLOUH_K31rS2fCX5x-MTj8_hScquVQXpbz3vk2EfulRmGXZc_8JU2NqQCAsYy3a28houqP3rDe5jEAvZS2SOFvJkKW--f5S-z39t1D7fNz1N8Btd9SmXWQzjbul5YNxI9ctqxhJpkKYpxOLlvrzdA6YdJjOlDx3n6S-HnSZGM6kQd_xKtAf8l1EGwhQmhbXhMhjVxMvGwE5BX7PAb8Ccde5bzOCJx-PVbVetuLb169ZYqQ._jiZbOPRR82FEWMZ.88j68LI-K2KT6FMBEdlz6amG5nvaJU8a-90.EnEbUTJsWNqJYKzfO0x4Yw",
"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiUlNBMV81In0.bN6FN0qmGxhkESiVukrCaDVG3woL0xE-0bHN_Mu0WZXTQWbzzT-7jOvaN1xhGK8nzi8qpCSRgE5onONNB9i8OnJm3MMIxF7bUUEAXO9SUAFn2v--wNc4drPc5OjIu0RiJrDVDkkGjNrBDIuBaEQcke7A0v91PH58dXE7o4TLPzC8UJmRtXWhUSwjXVF3-UmYRMht2rjHJlvRbtm6Tu2LMBIopRL0zj6tlPP4Dm7I7sz9OEB3VahYAhpXnFR7D_f8RjLSXQmBvB1FiI5l_vMz2NFt2hYUmQF3EJMLIEdHvvPp3iHDGiXC1obJrDID_CCf3qs9UY7DMYL622KLvP2NIg.qb72oxECzxd_aNuHVR0aNg.Gwet9Ms8hB8rKEb0h4RGdFNRq97Qs2LQaJM0HWrCqoI.03ljVThOFvgXzMmQJ79VjQ",
"eyJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiUlNBMV81In0.ZbEOP6rqdiIP4g7Nl1PL5gwhgDwv9RinyiUQxZXPOmD7kwEZrZ093dJnhqI9kEd3QGFlHDpB7HgNz53d27z2zmEj1-27v6miizq6tH4sN2MoeZLwSyk16O1_n3bVdDmROawsTYYFJfHsuLwyVJxPd37duIYnbUCFO9J8lLIv-2VI50KJ1t47YfE4P-Wt9jVzxP2CVUQaJwTlcwfiDLJTagYmfyrDjf525WlQFlgfJGqsJKp8BX9gmKvAo-1iCBAM8VpEjS0u0_hW9VSye36yh8BthVV-VJkhJ-0tMpto3bbBmj7M25Xf4gbTrrVU7Nz6wb18YZuhHZWmj2Y2nHV6Jg.AjnS44blTrIIfFlqVw0_Mg.muCRgaEXNKKpW8rMfW7jf7Zpn3VwSYDz-JTRg16jZxY.qjc9OGlMaaWKDWQSIwVpR4K556Pp6SF9",
"eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiUlNBMV81In0.c7_F1lMlRHQQE3WbKmtHBYTosdZrG9hPfs-F9gNQYet61zKG8NXVkSy0Zf2UFHt0vhcO8hP2qrqOFsy7vmRj20xnGHQ2EE29HH6hwX5bx1Jj3uE5WT9Gvh0OewpvF9VubbwWTIObBpdEG7XdJsMAQlIxtXUmQYAtLTWcy2ZJipyJtVlWQLaPuE8BKfZH-XAsp2CpQNiRPI8Ftza3EAspiyRfVQbjKt7nF8nuZ2sESjt7Y50q4CSiiCuGT28T3diMN0_rWrH-I-xx7OQvJlrQaNGglGtu3jKUcrJDcvxW2e1OxriaTeuQ848ayuRvGUNeSv6WoVYmkiK1x_gNwUAAbw.7XtSqHJA7kjt6JrfxJMwiA.Yvi4qukAbdT-k-Fd2s4G8xzL4VFxaFC0ZIzgFDAI6n0.JSWPJ-HjOE3SK9Lm0yHclmjS7Z1ahtQga9FHGCWVRcc",
"eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.SYVxJbCnJ_tcR13LJpaqHQj-nGNkMxre4A1FmnUdxnvzeJwuvyrLiUdRsZR1IkP4fqLtDON2mumx39QeJQf0WIObPBYlIxycRLkwxDHRVlyTmPvdZHAxN26jPrk09wa5SgK1UF1W1VSQIPm-Tek8jNAmarF1Yxzxl-t54wZFlQiHP4TuaczugO5f-J4nlWenfla2mU1snDgdUMlEZGOAQ_gTEtwSgd1MqXmK_7LZBkoDqqoCujMZhziafJPXPDaUUqBLW3hHkkDA7GpVec3XcTtNUWQJqOpMyQhqo1KQMc8jg3fuirILp-hjvvNVtBnCRBvbrKUCPzu2_yH3HM_agA.2VsdijtonAxShNIW.QzzB3P9CxYP3foNKN0Ma1Z9tMwijAlkWo08.ZdQkIPDY_M-hxqi5fD4NGw",
"eyJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.Z2oTJXXib1u-S38Vn3DRKE3JnhnwgUa92UhsefzY2Wpdn0dmxMfYt9iRoJGFfSAcA97MOfjyvXVRCKWXGrG5AZCMAXEqU8SNQwKPRjlcqojcVzQyMucXI0ikLC4mUgeRlfKTwsBicq6JZZylzRoLGGSNJQbni3_BLsf7H3Qor0BYg0FPCLG9Z2OVvrFzvjTLmZtV6gFlVrMHBxJub_aUet9gAkxiu1Wx_Kx46TlLX2tkumXIpTGlzX6pef6jLeZ5EIg_K-Uz4tkWgWQIEkLD7qmTyk5pAGmzukHa_08jIh5-U-Sd8XGZdx4J1pVPJ5CPg0qDJGZ_cfgkgpWbP_wB6A.4qgKfokK1EwYxz20._Md82bv_KH2Vru0Ue2Eb6oAqHP2xBBP5jF8.WFRojvQpD5VmZlOr_dN0rQ",
"eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.JzCUgJcBJmBgByp4PBAABUfhezPvndxBIVzaoZ96DAS0HPni0OjMbsOGsz6JwNsiTr1gSn_S6R1WpZM8GJc9R2z0EKKVP67TR62ZSG0MEWyLpHmG_4ug0fAp1HWWMa9bT4ApSaOLgwlpVAb_-BPZZgIu6c8cREuMon6UBHDqW1euTBbzk8zix3-FTZ6p5b_3soDL1wXfRiRBEsxxUGMnpryx1OFb8Od0JdyGF0GgfLt6OoaujDJpo-XtLRawu1Xlg6GqRs0NQwSHZ5jXgQ6-zgCufXonAmYTiIyBXY2no9XmECTexjwrS_05nA7H-UyIZEBOCp3Yhz2zxrt5j_0pvQ.SJR-ghhaUKP4zXtZ.muiuzLfZA0y0BDNsroGTw2r2-l73SLf9lK8.XFMH1oHr1G6ByP3dWSUUPA",
"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiUlNBLU9BRVAifQ.U946MVfIm4Dpk_86HrnIA-QXyiUu0LZ67PL93CMLmEtJemMNDqmRd9fXyenCIhAC7jPIV1aaqW7gS194xyrrnUpBoJBdbegiPqOfquy493Iq_GQ8OXnFxFibPNQ6rU0l8BwIfh28ei_VIF2jqN6bhxFURCVW7fG6n6zkCCuEyc7IcxWafSHjH2FNttREuVj-jS-4LYDZsFzSKbpqoYF6mHt8H3btNEZDTSmy_6v0fV1foNtUKNfWopCp-iE4hNh4EzJfDuU8eXLhDb03aoOockrUiUCh-E0tQx9su4rOv-mDEOHHAQK7swm5etxoa7__9PC3Hg97_p4GM9gC9ykNgw.pnXwvoSPi0kMQP54of-HGg.RPJt1CMWs1nyotx1fOIfZ8760mYQ69HlyDp3XmdVsZ8.Yxw2iPVWaBROFE_FGbvodA",
"eyJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiUlNBLU9BRVAifQ.eKEOIJUJpXmO_ghH_nGCJmoEspqKyiy3D5l0P8lKutlo8AuYHPQlgOsaFYnDkypyUVWd9zi-JaQuCeo7dzoBiS1L71nAZo-SUoN0anQBkVuyuRjr-deJMhPPfq1H86tTk-4rKzPr1Ivd2RGXMtWsrUpNGk81r1v8DdMntLE7UxZQqT34ONuZg1IXnD_U6di7k07unI29zuU1ySeUr6w1YPw5aUDErMlpZcEJWrgOEYWaS2nuC8sWGlPGYEjqkACMFGn-y40UoS_JatNZO6gHK3SKZnXD7vN5NAaMo_mFNbh50e1t_zO8DaUdLtXPOBLcx_ULoteNd9H8HyDGWqwAPw.0xmtzJfeVMoIT1Cp68QrXA.841l1aA4c3uvSYfw6l180gn5JZQjL53WQ5fr8ejtvoI.lojzeWql_3gDq-AoaIbl_aGQRH_54w_f",
"eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiUlNBLU9BRVAifQ.D0QkvIXR1TL7dIHWuPNMybmmD8UPyQd1bRKjRDNbA2HmKGpamCtcJmpNB_EetNFe-LDmhe44BYI_XN2wIBbYURKgDK_WG9BH0LQw_nCVqQ-sKqjtj3yQeytXhLHYTDmiF0TO-uW-RFR7GbPAdARBfuf4zj82r_wDD9sD5WSCGx89iPfozDOYQ_OLwdL2WD99VvDyfwS3ZhxA-9IMSYv5pwqPkxj4C0JdjCqrN0YNrZn_1ORgjtsVmcWXsmusObTozUGA7n5GeVepfZdU1vrMulAwdRYqOYtlqKaOpFowe9xFN3ncBG7wb4f9pmzbS_Dgt-1_Ii_4SEB9GQ4NiuBZ0w.N4AZeCxMGUv52A0UVJsaZw.5eHOGbZdtahnp3l_PDY-YojYib4ft4SRmdsQ2kggrTs.WsmGH8ZDv4ctBFs7qsQvw2obe4dVToRcAQaZ3PYL34E",
"eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.fDTxO_ZzZ3Jdrdw-bxvg7u-xWB2q1tp3kI5zH6JfhLUm4h6rt9qDA_wZlRym8-GzEtkUjkTtQGs6HgQx_qlyy8ylCakY5GHsNhCG4m0UNhRiNfcasAs03JSXfON9-tfTJimWD9n4k5OHHhvcrsCW1G3jYeLsK9WHCGRIhNz5ULbo8HBrCTbmZ6bOEQ9mqhdssLpdV24HDpebotf3bgPJqoaTfWU6Uy7tLmPiNuuNRLQ-iTpLyNMTVvGqqZhpcV3lAEN5l77QabI5xLJYucvYjrXQhAEZ7YXO8oRYhGkdG2XXIRcwr87rBeRH-47HAyhZgF_PBPBhhrJNS9UNMqdfBw.FvU4_s7Md6vxnXWd.fw29Q4_gHt4f026DPPV-CNebQ8plJ6IVLX8._apBZrw7WsT8HOmxgCrTwA",
"eyJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.bYuorK-rHMbO4c2CRWtvyOEaM1EN-o-wLRZ0wFWRX9mCXQ-iTNarZn7ksYM1XnGmZ4u3CSowX1Hpca9Rg72_VJCmKapqCT7r3YfasN4_oeLwuSKI_gT-uVOznod97tn3Gf_EDv0y1V4H0k9BEIFGbajAcG1znTD_ODY3j2KZJxisfrsBoslc6N-HI0kKZMC2hSGuHOcOf8HN1sTE-BLqZCtoj-zxQECJK8Wh14Ih4jzzdmmiu_qmSR780K6su-4PRt3j8uY7oCiLBfwpCsCmhJgp8rKd91zoedZmamfvX38mJIfE52j4fG6HmIYw9Ov814fk9OffV6tzixjcg54Q2g.yeVJz4aSh2s-GUr9.TBzzWP5llEiDdugpP2SmPf2U4MEGG9EoPWk.g25UoWpsBaOd45J__FX7mA",
"eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.h9tFtmh762JuffBxlSQbJujCyI4Zs9yc3IOb1yR8g65W4ZHosIvzVGHWbShj4EY9MNrz-RbKtHfqQGGzDeo3Xb4-HcQ2ZDHyWoUg7VfA8JafJ5zIKL1npz8eUExOVMLsAaRfHg8qNfczodg3egoSmX5Q-nrx4DeidDSXYZaZjV0C72stLTPcuQ7XPV7z1tvERAkqpvcsRmJn_PiRNxIbAgoyHMJ4Gijuzt1bWZwezlxYmw0TEuwCTVC2fl9NJTZyxOntS1Lcm-WQGlPkVYeVgYTOQXLlp7tF9t-aAvYpth2oWGT6Y-hbPrjx_19WaKD0XyWCR46V32DlXEVDP3Xl2A.NUgfnzQyEaJjzt9r.k2To43B2YVWMeR-w3n4Pr2b5wYq2o87giHk.X8_QYCg0IGnn1pJqe8p_KA",
"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.EDq6cNP6Yp1sds5HZ4CkXYp7bs9plIYVZScKvuyxUy0H1VyBC_YWg0HvndPNb-vwh1LA6KMxRazlOwJ9iPR9YzHnYmGgPM3Je_ZzBfiPlRfq6hQBpGnNaypBI1XZ2tyFBhulsVLqyJe2SmM2Ud00kasOdMYgcN8FNFzq7IOE7E0FUQkIwLdUL1nrzepiYDp-5bGkxWRcL02cYfdqdm00G4m0GkUxAmdxa3oPNxZlt2NeBI_UVWQSgJE-DJVJQkDcyA0id27TV2RCDnmujYauNT_wYlyb0bFDx3pYzzNXfAXd4wHZxt75QaLZ5APJ0EVfiXJ0qki6kT-GRVmOimUbQA.vTULZL7LvS0WD8kR8ZUtLg.mb2f0StEmmkuuvsyz8UplMvF58FtZzlu8eEwzvPUvN0.hbhveEN40V-pgG2hSVgyKg",
"eyJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.DuYk92p7u-YIN-JKn-XThmlVcnhU9x5TieQ2uhsLQVNlo0iWC9JJPP6bT6aI6u_1BIS3yE8_tSGGL7eM-zyEk6LuTqSWFRaZcZC06d0MnS9eYZcw1T2D17fL-ki-NtCaTahJD7jE2s0HevRVW49YtL-_V8whnO_EyVjvXIAQlPYqhH_o-0Nzcpng9ggdAnuF2rY1_6iRPYFJ3BLQvG1oWhyJ9s6SBttlOa0i6mmFCVLHx6sRpdGAB3lbCL3wfmHq4tpIv77gfoYUNP0SNff-zNmBXF_wp3dCntLZFTjbfMpGyHlruF_uoaLqwdjYpUGNUFVUoeSiMnSbMKm9NxiDgQ.6Mdgcqz7bMU1UeoAwFC8pg.W36QWOlBaJezakUX5FMZzbAgeAu_R14AYKZCQmuhguw.5OeyIJ03olxmJft8uBmjuOFQPWNZMYLI",
"eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.ECulJArWFsPL2FlpCN0W8E7IseSjJg1cZqE3wz5jk9gvwgNForAUEv5KYZqhNI-p5IxkGV0f8K6Y2X8pWzbLwiPIjZe8_dVqHYJoINxqCSgWLBhz0V36qL9Nc_xARTBk4-ZteIu75NoXVeos9gNvFnkOCj4tm-jGo8z8EFO9XfODgjhiR4xv8VqUtvrkjo9GQConaga5zpV-J4JQlXbdqbDjnuwacnJAxYpFyuemqcgqsl6BnFX3tovGkmSUPqcvF1A6tiHqr-TEmcgVqo5C3xswknRBKTQRM00iAmJ92WlVdkoOCx6E6O7cVHFawZ14BLzWzm66Crb4tv0ucYvk_Q.mxolwUaoj5S5kHCfph0w8g.nFpgYdnYg3blHCCEi2XXQGkkKQBXs2OkZaH11m3PRvk.k8BAVT4EcyrUFVIKr-KOSPbF89xyL0Vri2rFTu2iIWM",
}
for _, msg := range rsaSampleMessages {
obj, err := ParseEncrypted(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
plaintext, err := obj.Decrypt(rsaPrivateKey)
if err != nil {
t.Error("unable to decrypt message", msg, err)
continue
}
if string(plaintext) != "Lorem ipsum dolor sit amet" {
t.Error("plaintext is not what we expected for msg", msg)
}
}
}
// Test vectors generated with nimbus-jose-jwt
func TestSampleNimbusJWEMessagesAESKW(t *testing.T) {
aesTestKeys := [][]byte{
fromHexBytes("DF1FA4F36FFA7FC42C81D4B3C033928D"),
fromHexBytes("DF1FA4F36FFA7FC42C81D4B3C033928D95EC9CDC2D82233C"),
fromHexBytes("DF1FA4F36FFA7FC42C81D4B3C033928D95EC9CDC2D82233C333C35BA29044E90"),
}
aesSampleMessages := [][]string{
{
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwidGFnIjoib2ZMd2Q5NGloVWFRckJ0T1pQUDdjUSIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiV2Z3TnN5cjEwWUFjY2p2diJ9.9x3RxdqIS6P9xjh93Eu1bQ.6fs3_fSGt2jull_5.YDlzr6sWACkFg_GU5MEc-ZEWxNLwI_JMKe_jFA.f-pq-V7rlSSg_q2e1gDygw",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwidGFnIjoic2RneXB1ckFjTEFzTmZJU0lkZUNpUSIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoieVFMR0dCdDJFZ0c1THdyViJ9.arslKo4aKlh6f4s0z1_-U-8JbmhAoZHN.Xw2Q-GX98YXwuc4i.halTEWMWAYZbv-qOD52G6bte4x6sxlh1_VpGEA.Z1spn016v58cW6Q2o0Qxag",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwidGFnIjoicTNzejF5VUlhbVBDYXJfZ05kSVJqQSIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiM0ZRM0FsLWJWdWhmcEIyQyJ9.dhVipWbzIdsINttuZM4hnjpHvwEHf0VsVrOp4GAg01g.dk7dUyt1Qj13Pipw.5Tt70ONATF0BZAS8dBkYmCV7AQUrfb8qmKNLmw.A6ton9MQjZg0b3C0QcW-hg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwidGFnIjoiUHNpTGphZnJZNE16UlRmNlBPLTZfdyIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiSUFPbnd2ODR5YXFEaUxtbSJ9.swf92_LyCvjsvkynHTuMNXRl_MX2keU-fMDWIMezHG4.LOp9SVIXzs4yTnOtMyXZYQ.HUlXrzqJ1qXYl3vUA-ydezCg77WvJNtKdmZ3FPABoZw.8UYl1LOofQLAxHHvWqoTbg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwidGFnIjoiWGRndHQ5dUVEMVlVeU1rVHl6M3lqZyIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiWF90V2RhSmh6X3J1SHJvQSJ9.JQ3dS1JSgzIFi5M9ig63FoFU1nHBTmPwXY_ovNE2m1JOSUvHtalmihIuraPDloCf.e920JVryUIWt7zJJQM-www.8DUrl4LmsxIEhRr9RLTHG9tBTOcwXqEbQHAJd_qMHzE.wHinoqGUhL4O7lx125kponpwNtlp8VGJ",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidGFnIjoicGgyaTdoY0FWNlh3ZkQta1RHYlVXdyIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiaG41Smk4Wm1rUmRrSUxWVSJ9._bQlJXl22dhsBgYPhkxUyinBNi871teGWbviOueWj2PqG9OPxIc9SDS8a27YLSVDMircd5Q1Df28--vcXIABQA.DssmhrAg6w_f2VDaPpxTbQ.OGclEmqrxwvZqAfn7EgXlIfXgr0wiGvEbZz3zADnqJs.YZeP0uKVEiDl8VyC-s20YN-RbdyGNsbdtoGDP3eMof8",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiQTEyOEtXIn0.TEMcXEoY8WyqGjYs5GZgS-M_Niwu6wDY.i-26KtTt51Td6Iwd.wvhkagvPsLj3QxhPBbfH_th8OqxisUtme2UadQ.vlfvBPv3bw2Zk2H60JVNLQ",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiQTEyOEtXIn0.gPaR6mgQ9TUx05V6DRfgTQeZxl0ZSzBa5uQd-qw6yLs.MojplOD77FkMooS-.2yuD7dKR_C3sFbhgwiBccKKOF8DrSvNiwX7wPQ.qDKUbSvMnJv0qifjpWC14g",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiQTEyOEtXIn0.Fg-dgSkUW1KEaL5YDPoWHNL8fpX1WxWVLA9OOWsjIFhQVDKyUZI7BQ.mjRBpyJTZf7H-quf.YlNHezMadtaSKp23G-ozmYhHOeHwuJnvWGTtGg.YagnR7awBItUlMDo4uklvg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiQTEyOEtXIn0.x1vYzUE-E2XBWva9OPuwtqfQaf9rlJCIBAyAe6N2q2kWfJrkxGxFsQ.gAwe78dyODFaoP2IOityAA.Yh5YfovkWxGBNAs1sVhvXow_2izHHsBiYEc9JYD6kVg.mio1p3ncp2wLEaEaRa7P0w",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiQTEyOEtXIn0.szGrdnmF7D5put2aRBvSSFfp0vRgkRGYaafijJIqAF6PWd1IxsysZRV8aQkQOW1cB6d0fXsTfYM.Ru25LVOOk4xhaK-cIZ0ThA.pF9Ok5zot7elVqXFW5YYHV8MuF9gVGzpQnG1XDs_g_w.-7la0uwcNPpteev185pMHZjbVDXlrec8",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiQTEyOEtXIn0.cz-hRv0xR5CnOcnoRWNK8Q9poyVYzRCVTjfmEXQN6xPOZUkJ3zKNqb8Pir_FS0o2TVvxmIbuxeISeATTR2Ttx_YGCNgMkc93.SF5rEQT94lZR-UORcMKqGw.xphygoU7zE0ZggOczXCi_ytt-Evln8CL-7WLDlWcUHg.5h99r8xCCwP2PgDbZqzCJ13oFfB2vZWetD5qZjmmVho",
},
{
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwidGFnIjoiVWR5WUVKdEJ5ZTA5dzdjclY0cXI1QSIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiZlBBV0QwUmdSbHlFdktQcCJ9.P1uTfTuH-imL-NJJMpuTRA.22yqZ1NIfx3KNPgc.hORWZaTSgni1FS-JT90vJly-cU37qTn-tWSqTg.gMN0ufXF92rSXupTtBNkhA",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwidGFnIjoiOU9qX3B2LTJSNW5lZl9YbWVkUWltUSIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiY3BybGEwYUYzREVQNmFJTSJ9.6NVpAm_APiC7km2v-oNR8g23K9U_kf1-.jIg-p8tNwSvwxch0.1i-GPaxS4qR6Gy4tzeVtSdRFRSKQSMpmn-VhzA.qhFWPqtA6vVPl7OM3DThsA",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwidGFnIjoiOVc3THg3MVhGQVJCb3NaLVZ5dXc4ZyIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiZ1N4ZE5heFdBSVBRR0tHYiJ9.3YjPz6dVQwAtCekvtXiHZrooOUlmCsMSvyfwmGwdrOA.hA_C0IDJmGaRzsB0.W4l7OPqpFxiVOZTGfAlRktquyRTo4cEOk9KurQ.l4bGxOkO_ql_jlPo3Oz3TQ",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwidGFnIjoiOHJYbWl2WXFWZjNfbHhhd2NUbHJoUSIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiVXBWeXprVTNKcjEwYXRqYyJ9.8qft-Q_xqUbo5j_aVrVNHchooeLttR4Kb6j01O8k98M.hXO-5IKBYCL9UdwBFVm0tg.EBM4lCZX_K6tfqYmfoDxVPHcf6cT--AegXTTjfSqsIw.Of8xUvEQSh3xgFT3uENnAg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwidGFnIjoiVnItSnVaX0tqV2hSWWMzdzFwZ3cwdyIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiRGg2R3dISVBVS3ljZGNZeCJ9.YSEDjCnGWr_n9H94AvLoRnwm6bdU9w6-Q67k-QQRVcKRd6673pgH9zEF9A9Dt6o1.gcmVN4kxqBuMq6c7GrK3UQ.vWzJb0He6OY1lhYYjYS7CLh55REAAq1O7yNN-ND4R5Q.OD0B6nwyFaDr_92ysDOtlVnJaeoIqhGw",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidGFnIjoieEtad1BGYURpQ3NqUnBqZUprZHhmZyIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoieTVHRFdteXdkb2R1SDJlYyJ9.AW0gbhWqlptOQ1y9aoNVwrTIIkBfrp33C2OWJsbrDRk6lhxg_IgFhMDTE37moReySGUtttC4CXQD_7etHmd3Hw.OvKXK-aRKlXHOpJQ9ZY_YQ.Ngv7WarDDvR2uBj_DavPAR3DYuIaygvSSdcHrc8-ZqM.MJ6ElitzFCKf_0h5fIJw8uOLC6ps7dKZPozF8juQmUY",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiQTE5MktXIn0.8qu63pppcSvp1vv37WrZ44qcCTg7dQMA.cDp-f8dJTrDEpZW4.H6OBJYs4UvFR_IZHLYQZxB6u9a0wOdAif2LNfQ.1dB-id0UIwRSlmwHx5BJCg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiQTE5MktXIn0._FdoKQvC8qUs7K0upriEihUwztK8gOwonXpOxdIwrfs.UO38ok8gDdpLVa1T.x1GvHdVCy4fxoQRg-OQK4Ez3jDOvu9gllLPeEA.3dLeZGIprh_nHizOTVi1xw",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiQTE5MktXIn0.uzCJskgSIK6VkjJIu-dQi18biqaY0INc_A1Ehx0oESafgtR99_n4IA.W2eKK8Y14WwTowI_.J2cJC7R6Bz6maR0s1UBMPyRi5BebNUAmof4pvw.-7w6htAlc4iUsOJ6I04rFg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiQTE5MktXIn0.gImQeQETp_6dfJypFDPLlv7c5pCzuq86U16gzrLiCXth6X9XfxJpvQ.YlC4MxjtLWrsyEvlFhvsqw.Vlpvmg9F3gkz4e1xG01Yl2RXx-jG99rF5UvCxOBXSLc.RZUrU_FoR5bG3M-j3GY0Dw",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiQTE5MktXIn0.T2EfQ6Tu2wJyRMgZzfvBYmQNCCfdMudMrg86ibEMVAOUKJPtR3WMPEb_Syy9p2VjrLKRlv7nebo.GPc8VbarPPRtzIRATB8NsA.ugPCqLvVLwh55bWlwjsFkmWzJ31z5z-wuih2oJqmG_U.m7FY3EjvV6mKosEYJ5cY7ezFoVQoJS8X",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiQTE5MktXIn0.OgLMhZ-2ZhslQyHfzOfyC-qmT6bNg9AdpP59B4jtyxWkQu3eW475WCdiAjojjeyBtVRGQ5vOomwaOIFejY_IekzH6I_taii3.U9x44MF6Wyz5TIwIzwhoxQ.vK7yvSF2beKdNxNY_7n4XdF7JluCGZoxdFJyTJVkSmI.bXRlI8KL-g7gpprQxGmXjVYjYghhWJq7mlCfWI8q2uA",
},
{
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwidGFnIjoiR3BjX3pfbjduZjJVZlEtWGdsaTBaQSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiUk40eUdhOVlvYlFhUmZ1TCJ9.Q4ukD6_hZpmASAVcqWJ9Wg.Zfhny_1WNdlp4fH-.3sekDCjkExQCcv28ZW4yrcFnz0vma3vgoenSXA.g8_Ird2Y0itTCDP61du-Yg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwidGFnIjoiWC05UkNVWVh4U3NRelcwelVJS01VUSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiY3JNMnJfa3RrdWpyQ1h5OSJ9.c0q2jCxxV4y1h9u_Xvn7FqUDnbkmNEG4.S_noOTZKuUo9z1l6.ez0RdA25vXMUGH96iXmj3DEVox0J7TasJMnzgg.RbuSPTte_NzTtEEokbc5Ig",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwidGFnIjoiWmwyaDFpUW11QWZWd2lJeVp5RHloZyIsImFsZyI6IkEyNTZHQ01LVyIsIml2Ijoib19xZmljb0N0NzNzRWo1QyJ9.NpJxRJ0aqcpekD6HU2u9e6_pL_11JXjWvjfeQnAKkZU.4c5qBcBBrMWi27Lf.NKwNIb4b6cRDJ1TwMKsPrjs7ADn6aNoBdQClVw.yNWmSSRBqQfIQObzj8zDqw",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwidGFnIjoiMXdwVEI3LWhjdzZUVXhCbVh2UzdhUSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiOUdIVnZJaDZ0a09vX2pHUSJ9.MFgIhp9mzlq9hoPqqKVKHJ3HL79EBYtV4iNhD63yqiU.UzW5iq8ou21VpZYJgKEN8A.1gOEzA4uAPvHP76GMfs9uLloAV10mKaxiZVAeL7iQA0.i1X_2i0bCAz-soXF9bI_zw",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwidGFnIjoiNThocUtsSk15Y1BFUEFRUlNfSzlNUSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiUDh3aTBWMTluVnZqNXpkOSJ9.FXidOWHNFJODO74Thq3J2cC-Z2B8UZkn7SikeosU0bUK6Jx_lzzmUZ-Lafadpdpj.iLfcDbpuBKFiSfiBzUQc7Q.VZK-aD7BFspqfvbwa0wE2wwWxdomzk2IKMetFe8bI44.7wC6rJRGa4x48xbYMd6NH9VzK8uNn4Cb",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidGFnIjoicGcwOEpUcXdzMXdEaXBaRUlpVExoQSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiSlpodk9CdU1RUDFFZTZTNSJ9.wqVgTPm6TcYCTkpbwmn9sW4mgJROH2A3dIdSXo5oKIQUIVbQsmy7KXH8UYO2RS9slMGtb869C8o0My67GKg9dQ.ogrRiLlqjB1S5j-7a05OwA.2Y_LyqhU4S_RXMsB74bxcBacd23J2Sp5Lblw-sOkaUY.XGMiYoU-f3GaEzSvG41vpJP2DMGbeDFoWmkUGLUjc4M",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiQTI1NktXIn0.QiIZm9NYfahqYFIbiaoUhCCHjotHMkup.EsU0XLn4FjzzCILn.WuCoQkm9vzo95E7hxBtfYpt-Mooc_vmSTyzj6Q.NbeeYVy6gQPlmhoWDrZwaQ",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiQTI1NktXIn0.1ol3j_Lt0Os3UMe2Gypj0o8b77k0FSmqD7kNRNoMa9U.vZ2HMTgN2dgUd42h.JvNcy8-c8sYzOC089VtFSg2BOQx3YF8CqSTuJw.t03LRioWWKN3d7SjinU6SQ",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiQTI1NktXIn0.gbkk03l1gyrE9qGEMVtORiyyUqKsgzbqjLd8lw0RQ07WWn--TV4BgA.J8ThH4ac2UhSsMIP.g-W1piEGrdi3tNwQDJXpYm3fQjTf82mtVCrCOg.-vY05P4kiB9FgF2vwrSeXQ",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiQTI1NktXIn0.k86pQs7gmQIzuIWRFwesF32XY2xi1WbYxi7XUf_CYlOlehwGCTINHg.3NcC9VzfQgsECISKf4xy-g.v2amdo-rgeGsg-II_tvPukX9D-KAP27xxf2uQJ277Ws.E4LIE3fte3glAnPpnd8D9Q",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiQTI1NktXIn0.b8iN0Am3fCUvj7sBd7Z0lpfzBjh1MOgojV7J5rDfrcTU3b35RGYgEV1RdcrtUTBgUwITDjmU7jM.wsSDBFghDga_ERv36I2AOg.6uJsucCb2YReFOJGBdo4zidTIKLUmZBIXfm_M0AJpKk.YwdAfXI3HHcw2wLSnfCRtw4huZQtSKhz",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiQTI1NktXIn0.akY9pHCbkHPh5VpXIrX0At41XnJIKBR9iMMkf301vKeJNAZYJTxWzeJhFd-DhQ47tMctc3YYkwZkQ5I_9fGYb_f0oBcw4esh.JNwuuHud78h6S99NO1oBQQ.0RwckPYATBgvw67upkAQ1AezETHc-gh3rryz19i5ryc.3XClRTScgzfMgLCHxHHoRF8mm9VVGXv_Ahtx65PskKQ",
},
}
for i, msgs := range aesSampleMessages {
for _, msg := range msgs {
obj, err := ParseEncrypted(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
plaintext, err := obj.Decrypt(aesTestKeys[i])
if err != nil {
t.Error("unable to decrypt message", msg, err)
continue
}
if string(plaintext) != "Lorem ipsum dolor sit amet" {
t.Error("plaintext is not what we expected for msg", msg)
}
}
}
}
// Test vectors generated with jose4j
func TestSampleJose4jJWEMessagesECDH(t *testing.T) {
ecTestKey := &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: elliptic.P256(),
X: fromBase64Int("weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ"),
Y: fromBase64Int("e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck"),
},
D: fromBase64Int("VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw"),
}
ecSampleMessages := []string{
"eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOENCQy1IUzI1NiIsImVwayI6eyJrdHkiOiJFQyIsIngiOiJTQzAtRnJHUkVvVkpKSmg1TGhORmZqZnFXMC1XSUFyd3RZMzJzQmFQVVh3IiwieSI6ImFQMWlPRENveU9laTVyS1l2VENMNlRMZFN5UEdUN0djMnFsRnBwNXdiWFEiLCJjcnYiOiJQLTI1NiJ9fQ..3mifklTnTTGuA_etSUBBCw.dj8KFM8OlrQ3rT35nHcHZ7A5p84VB2OZb054ghSjS-M.KOIgnJjz87LGqMtikXGxXw",
"eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTE5MkNCQy1IUzM4NCIsImVwayI6eyJrdHkiOiJFQyIsIngiOiJUaHRGc0lRZ1E5MkZOYWFMbUFDQURLbE93dmNGVlRORHc4ampfWlJidUxjIiwieSI6IjJmRDZ3UXc3YmpYTm1nVThXMGpFbnl5ZUZkX3Y4ZmpDa3l1R29vTFhGM0EiLCJjcnYiOiJQLTI1NiJ9fQ..90zFayMkKc-fQC_19f6P3A.P1Y_7lMnfkUQOXW_en31lKZ3zAn1nEYn6fXLjmyVPrQ.hrgwy1cePVfhMWT0h-crKTXldglHZ-4g",
"eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTI1NkNCQy1IUzUxMiIsImVwayI6eyJrdHkiOiJFQyIsIngiOiI5R1Z6c3VKNWgySl96UURVUFR3WU5zUkFzVzZfY2RzN0pELVQ2RDREQ1ZVIiwieSI6InFZVGl1dVU4aTB1WFpoaS14VGlRNlZJQm5vanFoWENPVnpmWm1pR2lRTEUiLCJjcnYiOiJQLTI1NiJ9fQ..v2reRlDkIsw3eWEsTCc1NA.0qakrFdbhtBCTSl7EREf9sxgHBP9I-Xw29OTJYnrqP8.54ozViEBYYmRkcKp7d2Ztt4hzjQ9Vb5zCeijN_RQrcI",
"eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiOElUemg3VVFaaUthTWtfME9qX1hFaHZENXpUWjE2Ti13WVdjeTJYUC1tdyIsInkiOiJPNUJiVEk0bUFpU005ZmpCejBRU3pXaU5vbnl3cWlQLUN0RGgwdnNGYXNRIiwiY3J2IjoiUC0yNTYifX0.D3DP3wqPvJv4TYYfhnfrOG6nsM-MMH_CqGfnOGjgdXHNF7xRwEJBOA.WL9Kz3gNYA7S5Rs5mKcXmA.EmQkXhO_nFqAwxJWaM0DH4s3pmCscZovB8YWJ3Ru4N8.Bf88uzwfxiyTjpejU5B0Ng",
"eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImVuYyI6IkExOTJDQkMtSFMzODQiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiMjlJMk4zRkF0UlBlNGhzYjRLWlhTbmVyV0wyTVhtSUN1LXJJaXhNSHpJQSIsInkiOiJvMjY1bzFReEdmbDhzMHQ0U1JROS00RGNpc3otbXh4NlJ6WVF4SktyeWpJIiwiY3J2IjoiUC0yNTYifX0.DRmsmXz6fCnLc_njDIKdpM7Oc4jTqd_yd9J94TOUksAstEUkAl9Ie3Wg-Ji_LzbdX2xRLXIimcw.FwJOHPQhnqKJCfxt1_qRnQ.ssx3q1ZYILsMTln5q-K8HVn93BVPI5ViusstKMxZzRs.zzcfzWNYSdNDdQ4CiHfymj0bePaAbVaT",
"eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiRUp6bTViQnRzVXJNYTl2Y1Q2d1hZRXI3ZjNMcjB0N1V4SDZuZzdGcFF0VSIsInkiOiJRYTNDSDllVTFXYjItdFdVSDN3Sk9fTDVMZXRsRUlMQWNkNE9XR2tFd0hZIiwiY3J2IjoiUC0yNTYifX0.5WxwluZpVWAOJdVrsnDIlEc4_wfRE1gXOaQyx_rKkElNz157Ykf-JsAD7aEvXfx--NKF4js5zYyjeCtxWBhRWPOoNNZJlqV_.Iuo82-qsP2S1SgQQklAnrw.H4wB6XoLKOKWCu6Y3LPAEuHkvyvr-xAh4IBm53uRF8g._fOLKq0bqDZ8KNjni_MJ4olHNaYz376dV9eNmp9O9PU",
"eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiZktNSG5sRkoxajBTSnJ3WGtVWlpaX3BtWHdUQlJtcHhlaTkxdUpaczUycyIsInkiOiJLRkxKaXhEUTJQcjEybWp1aFdYb3pna2U1V3lhWnhmTWlxZkJ0OEJpbkRvIiwiY3J2IjoiUC0yNTYifX0.2LSD2Mw4tyYJyfsmpVmzBtJRd12jMEYGdlhFbaXIbKi5A33CGNQ1tg.s40aAjmZOvK8Us86FCBdHg.jpYSMAKp___oMCoWM495mTfbi_YC80ObeoCmGE3H_gs.A6V-jJJRY1yz24CaXGUbzg",
"eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkExOTJDQkMtSFMzODQiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiSDRxcFUzeWtuRktWRnV4SmxLa3NZSE5ieHF3aXM0WWtCVVFHVE1Td05JQSIsInkiOiJHb0lpRUZaUGRRSHJCbVR4ZTA3akJoZmxrdWNqUjVoX1QwNWVXc3Zib0prIiwiY3J2IjoiUC0yNTYifX0.KTrwwV2uzD--gf3PGG-kjEAGgi7u0eMqZPZfa4kpyFGm3x8t2m1NHdz3t9rfiqjuaqsxPKhF4gs.cu16fEOzYaSxhHu_Ht9w4g.BRJdxVBI9spVtY5KQ6gTR4CNcKvmLUMKZap0AO-RF2I.DZyUaa2p6YCIaYtjWOjC9GN_VIYgySlZ",
"eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoieDBYSGRkSGM2Q0ktSnlfbUVMOEZZRExhWnV0UkVFczR4c3BMQmcwZk1jbyIsInkiOiJEa0xzOUJGTlBkTTVTNkpLYVJ3cnV1TWMwcUFzWW9yNW9fZWp6NXBNVXFrIiwiY3J2IjoiUC0yNTYifX0.mfCxJ7JYIqTMqcAh5Vp2USF0eF7OhOeluqda7YagOUJNwxA9wC9o23DSoLUylfrZUfanZrJJJcG69awlv-LY7anOLHlp3Ht5.ec48A_JWb4qa_PVHWZaTfQ.kDAjIDb3LzJpfxNh-DiAmAuaKMYaOGSTb0rkiJLuVeY.oxGCpPlii4pr89XMk4b9s084LucTqPGU6TLbOW2MZoc",
"eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiQXB5TnlqU2d0bmRUcFg0eENYenNDRnZva1l3X18weXg2dGRUYzdPUUhIMCIsInkiOiJYUHdHMDVDaW1vOGlhWmxZbDNsMEp3ZllhY1FZWHFuM2RRZEJUWFpldDZBIiwiY3J2IjoiUC0yNTYifX0.yTA2PwK9IPqkaGPenZ9R-gOn9m9rvcSEfuX_Nm8AkuwHIYLzzYeAEA.ZW1F1iyHYKfo-YoanNaIVg.PouKQD94DlPA5lbpfGJXY-EJhidC7l4vSayVN2vVzvA.MexquqtGaXKUvX7WBmD4bA",
"eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExOTJDQkMtSFMzODQiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiaDRWeGNzNVUzWk1fTlp4WmJxQ3hMTVB5UmEtR2ktSVNZa0xDTzE1RHJkZyIsInkiOiJFeVotS3dWNVE5OXlnWk5zU0lpSldpR3hqbXNLUk1WVE5sTTNSd1VYTFRvIiwiY3J2IjoiUC0yNTYifX0.wo56VISyL1QAbi2HLuVut5NGF2FvxKt7B8zHzJ3FpmavPozfbVZV08-GSYQ6jLQWJ4xsO80I4Kg.3_9Bo5ozvD96WHGhqp_tfQ.48UkJ6jk6WK70QItb2QZr0edKH7O-aMuVahTEeqyfW4.ulMlY2tbC341ct20YSmNdtc84FRz1I4g",
"eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiN0xZRzZZWTJkel9ZaGNvNnRCcG1IX0tPREQ2X2hwX05tajdEc1c2RXgxcyIsInkiOiI5Y2lPeDcwUkdGT0tpVnBRX0NHQXB5NVlyeThDazBmUkpwNHVrQ2tjNmQ0IiwiY3J2IjoiUC0yNTYifX0.bWwW3J80k46HG1fQAZxUroko2OO8OKkeRavr_o3AnhJDMvp78OR229x-fZUaBm4uWv27_Yjm0X9T2H2lhlIli2Rl9v1PNC77.1NmsJBDGI1fDjRzyc4mtyA.9KfCFynQj7LmJq08qxAG4c-6ZPz1Lh3h3nUbgVwB0TI.cqech0d8XHzWfkWqgKZq1SlAfmO0PUwOsNVkuByVGWk",
}
for _, msg := range ecSampleMessages {
obj, err := ParseEncrypted(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
plaintext, err := obj.Decrypt(ecTestKey)
if err != nil {
t.Error("unable to decrypt message", msg, err)
continue
}
if string(plaintext) != "Lorem ipsum dolor sit amet." {
t.Error("plaintext is not what we expected for msg", msg)
}
}
}

View file

@ -1,715 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jose
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"encoding/hex"
"math/big"
"reflect"
"testing"
"golang.org/x/crypto/ed25519"
"gopkg.in/square/go-jose.v2/json"
)
// Test chain of two X.509 certificates
var testCertificates, _ = x509.ParseCertificates(fromBase64Bytes(`
MIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJ
BgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4G
A1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYx
MDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNV
BAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUw
EwYDVQQDEwxleGFtcGxlLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQC7stSvfQyGuHw3v34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKd
sR/J5sbWSl8K/5djpzj31eIzqU69w8v7SChM5x9bouDsABHz3kZucx5cSafE
gJojysBkcrq3VY+aJanzbL+qErYX+lhRpPcZK6JMWIwar8Y3B2la4yWwieec
w2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84czKPyt9r40gDk2XiH/lGts5a9
4rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF5O5iSV9rEI+m2+7j2S+j
HDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2Np6i464lAgMBAAGj
TzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNVHREEJTAj
hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJKoZIhvcN
AQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sMlM05
kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7
LstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloS
aa7dvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx
8MNGvUeLFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObi
qdsJLMVvb2XliJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIUwggNT
MIICO6ADAgECAgkAqD4tCWKt9/AwDQYJKoZIhvcNAQELBQAwVTELMAkGA1UE
BhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQL
EwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLXJvb3QwHhcNMTYwNjEwMjIx
NDExWhcNMjMwNDE1MjIxNDExWjBVMQswCQYDVQQGEwJVUzELMAkGA1UECBMC
Q0ExEDAOBgNVBAoTB2NlcnRpZ28xEDAOBgNVBAsTB2V4YW1wbGUxFTATBgNV
BAMTDGV4YW1wbGUtcm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAMo4ShKI2MxDz/NQVxBbz0tbD5R5NcobA0NKkaPKLyMEpnWVY9ucyauM
joNn1F568cfOoF0pm3700U8UTPt2MMxEHIi4mFG/OF8UF+Voh1J42Tb42lRo
W5RRR3ogh4+7QB1G94nxkYddHAJ4QMhUJlLigFg8c6Ff/MxYODy9I7ilLFOM
Zzsjx8fFpRKRXNQFt471P/V4WTSba7GzdTOJRyTZf/xipF36n8RoEQPvyde8
pEAsCC4oDOrEiCTdxw8rRJVAU0Wr55XX+qjxyi55C6oykIC/BWR+lUqGd7IL
Y2Uyt/OVxllt8b+KuVKNCfn4TFlfgizLWkJRs6JV9KuwJ20CAwEAAaMmMCQw
DgYDVR0PAQH/BAQDAgIEMBIGA1UdEwEB/wQIMAYBAf8CAQAwDQYJKoZIhvcN
AQELBQADggEBAIsQlTrm9NT6gts0cs4JHp8AutuMrvGyLpIUOlJcEybvgxaz
LebIMGZek5w3yEJiCyCK9RdNDP3Kdc/+nM6PhvzfPOVo58+0tMCYyEpZVXhD
zmasNDP4fMbiUpczvx5OwPw/KuhwD+1ITuZUQnQlqXgTYoj9n39+qlgUsHos
WXHmfzd6Fcz96ADSXg54IL2cEoJ41Q3ewhA7zmWWPLMAl21aex2haiAmzqqN
xXyfZTnGNnE3lkV1yVguOrqDZyMRdcxDFvxvtmEeMtYV2Mc/zlS9ccrcOkrc
mZSDxthLu3UMl98NA2NrCGWwzJwpk36vQ0PRSbibsCMarFspP8zbIoU=`))
func TestCurveSize(t *testing.T) {
size256 := curveSize(elliptic.P256())
size384 := curveSize(elliptic.P384())
size521 := curveSize(elliptic.P521())
if size256 != 32 {
t.Error("P-256 have 32 bytes")
}
if size384 != 48 {
t.Error("P-384 have 48 bytes")
}
if size521 != 66 {
t.Error("P-521 have 66 bytes")
}
}
func TestRoundtripRsaPrivate(t *testing.T) {
jwk, err := fromRsaPrivateKey(rsaTestKey)
if err != nil {
t.Error("problem constructing JWK from rsa key", err)
}
rsa2, err := jwk.rsaPrivateKey()
if err != nil {
t.Error("problem converting RSA private -> JWK", err)
}
if rsa2.N.Cmp(rsaTestKey.N) != 0 {
t.Error("RSA private N mismatch")
}
if rsa2.E != rsaTestKey.E {
t.Error("RSA private E mismatch")
}
if rsa2.D.Cmp(rsaTestKey.D) != 0 {
t.Error("RSA private D mismatch")
}
if len(rsa2.Primes) != 2 {
t.Error("RSA private roundtrip expected two primes")
}
if rsa2.Primes[0].Cmp(rsaTestKey.Primes[0]) != 0 {
t.Error("RSA private P mismatch")
}
if rsa2.Primes[1].Cmp(rsaTestKey.Primes[1]) != 0 {
t.Error("RSA private Q mismatch")
}
}
func TestRsaPrivateInsufficientPrimes(t *testing.T) {
brokenRsaPrivateKey := rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: rsaTestKey.N,
E: rsaTestKey.E,
},
D: rsaTestKey.D,
Primes: []*big.Int{rsaTestKey.Primes[0]},
}
_, err := fromRsaPrivateKey(&brokenRsaPrivateKey)
if err != ErrUnsupportedKeyType {
t.Error("expected unsupported key type error, got", err)
}
}
func TestRsaPrivateExcessPrimes(t *testing.T) {
brokenRsaPrivateKey := rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: rsaTestKey.N,
E: rsaTestKey.E,
},
D: rsaTestKey.D,
Primes: []*big.Int{
rsaTestKey.Primes[0],
rsaTestKey.Primes[1],
big.NewInt(3),
},
}
_, err := fromRsaPrivateKey(&brokenRsaPrivateKey)
if err != ErrUnsupportedKeyType {
t.Error("expected unsupported key type error, got", err)
}
}
func TestRoundtripEcPublic(t *testing.T) {
for i, ecTestKey := range []*ecdsa.PrivateKey{ecTestKey256, ecTestKey384, ecTestKey521} {
jwk, err := fromEcPublicKey(&ecTestKey.PublicKey)
ec2, err := jwk.ecPublicKey()
if err != nil {
t.Error("problem converting ECDSA private -> JWK", i, err)
}
if !reflect.DeepEqual(ec2.Curve, ecTestKey.Curve) {
t.Error("ECDSA private curve mismatch", i)
}
if ec2.X.Cmp(ecTestKey.X) != 0 {
t.Error("ECDSA X mismatch", i)
}
if ec2.Y.Cmp(ecTestKey.Y) != 0 {
t.Error("ECDSA Y mismatch", i)
}
}
}
func TestRoundtripEcPrivate(t *testing.T) {
for i, ecTestKey := range []*ecdsa.PrivateKey{ecTestKey256, ecTestKey384, ecTestKey521} {
jwk, err := fromEcPrivateKey(ecTestKey)
ec2, err := jwk.ecPrivateKey()
if err != nil {
t.Error("problem converting ECDSA private -> JWK", i, err)
}
if !reflect.DeepEqual(ec2.Curve, ecTestKey.Curve) {
t.Error("ECDSA private curve mismatch", i)
}
if ec2.X.Cmp(ecTestKey.X) != 0 {
t.Error("ECDSA X mismatch", i)
}
if ec2.Y.Cmp(ecTestKey.Y) != 0 {
t.Error("ECDSA Y mismatch", i)
}
if ec2.D.Cmp(ecTestKey.D) != 0 {
t.Error("ECDSA D mismatch", i)
}
}
}
func TestRoundtripX5C(t *testing.T) {
jwk := JSONWebKey{
Key: rsaTestKey,
KeyID: "bar",
Algorithm: "foo",
Certificates: testCertificates,
}
jsonbar, err := jwk.MarshalJSON()
if err != nil {
t.Error("problem marshaling", err)
}
var jwk2 JSONWebKey
err = jwk2.UnmarshalJSON(jsonbar)
if err != nil {
t.Error("problem unmarshalling", err)
}
if !reflect.DeepEqual(testCertificates, jwk2.Certificates) {
t.Error("Certificates not equal", jwk.Certificates, jwk2.Certificates)
}
jsonbar2, err := jwk2.MarshalJSON()
if err != nil {
t.Error("problem marshaling", err)
}
if !bytes.Equal(jsonbar, jsonbar2) {
t.Error("roundtrip should not lose information")
}
}
func TestMarshalUnmarshal(t *testing.T) {
kid := "DEADBEEF"
for i, key := range []interface{}{ecTestKey256, ecTestKey384, ecTestKey521, rsaTestKey, ed25519PrivateKey} {
for _, use := range []string{"", "sig", "enc"} {
jwk := JSONWebKey{Key: key, KeyID: kid, Algorithm: "foo"}
if use != "" {
jwk.Use = use
}
jsonbar, err := jwk.MarshalJSON()
if err != nil {
t.Error("problem marshaling", i, err)
}
var jwk2 JSONWebKey
err = jwk2.UnmarshalJSON(jsonbar)
if err != nil {
t.Error("problem unmarshalling", i, err)
}
jsonbar2, err := jwk2.MarshalJSON()
if err != nil {
t.Error("problem marshaling", i, err)
}
if !bytes.Equal(jsonbar, jsonbar2) {
t.Error("roundtrip should not lose information", i)
}
if jwk2.KeyID != kid {
t.Error("kid did not roundtrip JSON marshalling", i)
}
if jwk2.Algorithm != "foo" {
t.Error("alg did not roundtrip JSON marshalling", i)
}
if jwk2.Use != use {
t.Error("use did not roundtrip JSON marshalling", i)
}
}
}
}
func TestMarshalNonPointer(t *testing.T) {
type EmbedsKey struct {
Key JSONWebKey
}
keyJSON := []byte(`{
"e": "AQAB",
"kty": "RSA",
"n": "vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw"
}`)
var parsedKey JSONWebKey
err := json.Unmarshal(keyJSON, &parsedKey)
if err != nil {
t.Errorf("Error unmarshalling key: %v", err)
return
}
ek := EmbedsKey{
Key: parsedKey,
}
out, err := json.Marshal(ek)
if err != nil {
t.Errorf("Error marshalling JSON: %v", err)
return
}
expected := "{\"Key\":{\"kty\":\"RSA\",\"n\":\"vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw\",\"e\":\"AQAB\"}}"
if string(out) != expected {
t.Error("Failed to marshal embedded non-pointer JWK properly:", string(out))
}
}
func TestMarshalUnmarshalInvalid(t *testing.T) {
// Make an invalid curve coordinate by creating a byte array that is one
// byte too large, and setting the first byte to 1 (otherwise it's just zero).
invalidCoord := make([]byte, curveSize(ecTestKey256.Curve)+1)
invalidCoord[0] = 1
keys := []interface{}{
// Empty keys
&rsa.PrivateKey{},
&ecdsa.PrivateKey{},
// Invalid keys
&ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
// Missing values in pub key
Curve: elliptic.P256(),
},
},
&ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
// Invalid curve
Curve: nil,
X: ecTestKey256.X,
Y: ecTestKey256.Y,
},
},
&ecdsa.PrivateKey{
// Valid pub key, but missing priv key values
PublicKey: ecTestKey256.PublicKey,
},
&ecdsa.PrivateKey{
// Invalid pub key, values too large
PublicKey: ecdsa.PublicKey{
Curve: ecTestKey256.Curve,
X: big.NewInt(0).SetBytes(invalidCoord),
Y: big.NewInt(0).SetBytes(invalidCoord),
},
D: ecTestKey256.D,
},
nil,
}
for i, key := range keys {
jwk := JSONWebKey{Key: key}
_, err := jwk.MarshalJSON()
if err == nil {
t.Error("managed to serialize invalid key", i)
}
}
}
func TestWebKeyVectorsInvalid(t *testing.T) {
keys := []string{
// Invalid JSON
"{X",
// Empty key
"{}",
// Invalid RSA keys
`{"kty":"RSA"}`,
`{"kty":"RSA","e":""}`,
`{"kty":"RSA","e":"XXXX"}`,
`{"kty":"RSA","d":"XXXX"}`,
// Invalid EC keys
`{"kty":"EC","crv":"ABC"}`,
`{"kty":"EC","crv":"P-256"}`,
`{"kty":"EC","crv":"P-256","d":"XXX"}`,
`{"kty":"EC","crv":"ABC","d":"dGVzdA","x":"dGVzdA"}`,
`{"kty":"EC","crv":"P-256","d":"dGVzdA","x":"dGVzdA"}`,
}
for _, key := range keys {
var jwk2 JSONWebKey
err := jwk2.UnmarshalJSON([]byte(key))
if err == nil {
t.Error("managed to parse invalid key:", key)
}
}
}
// Test vectors from RFC 7520
var cookbookJWKs = []string{
// EC Public
stripWhitespace(`{
"kty": "EC",
"kid": "bilbo.baggins@hobbiton.example",
"use": "sig",
"crv": "P-521",
"x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9
A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
"y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVy
SsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1"
}`),
//ED Private
stripWhitespace(`{
"kty": "OKP",
"crv": "Ed25519",
"d": "nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A",
"x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
}`),
// EC Private
stripWhitespace(`{
"kty": "EC",
"kid": "bilbo.baggins@hobbiton.example",
"use": "sig",
"crv": "P-521",
"x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9
A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
"y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVy
SsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1",
"d": "AAhRON2r9cqXX1hg-RoI6R1tX5p2rUAYdmpHZoC1XNM56KtscrX6zb
KipQrCW9CGZH3T4ubpnoTKLDYJ_fF3_rJt"
}`),
// RSA Public
stripWhitespace(`{
"kty": "RSA",
"kid": "bilbo.baggins@hobbiton.example",
"use": "sig",
"n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT
-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqV
wGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-
oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde
3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuC
LqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5g
HdrNP5zw",
"e": "AQAB"
}`),
// RSA Private
stripWhitespace(`{"kty":"RSA",
"kid":"juliet@capulet.lit",
"use":"enc",
"n":"t6Q8PWSi1dkJj9hTP8hNYFlvadM7DflW9mWepOJhJ66w7nyoK1gPNqFMSQRy
O125Gp-TEkodhWr0iujjHVx7BcV0llS4w5ACGgPrcAd6ZcSR0-Iqom-QFcNP
8Sjg086MwoqQU_LYywlAGZ21WSdS_PERyGFiNnj3QQlO8Yns5jCtLCRwLHL0
Pb1fEv45AuRIuUfVcPySBWYnDyGxvjYGDSM-AqWS9zIQ2ZilgT-GqUmipg0X
OC0Cc20rgLe2ymLHjpHciCKVAbY5-L32-lSeZO-Os6U15_aXrk9Gw8cPUaX1
_I8sLGuSiVdt3C_Fn2PZ3Z8i744FPFGGcG1qs2Wz-Q",
"e":"AQAB",
"d":"GRtbIQmhOZtyszfgKdg4u_N-R_mZGU_9k7JQ_jn1DnfTuMdSNprTeaSTyWfS
NkuaAwnOEbIQVy1IQbWVV25NY3ybc_IhUJtfri7bAXYEReWaCl3hdlPKXy9U
vqPYGR0kIXTQRqns-dVJ7jahlI7LyckrpTmrM8dWBo4_PMaenNnPiQgO0xnu
ToxutRZJfJvG4Ox4ka3GORQd9CsCZ2vsUDmsXOfUENOyMqADC6p1M3h33tsu
rY15k9qMSpG9OX_IJAXmxzAh_tWiZOwk2K4yxH9tS3Lq1yX8C1EWmeRDkK2a
hecG85-oLKQt5VEpWHKmjOi_gJSdSgqcN96X52esAQ",
"p":"2rnSOV4hKSN8sS4CgcQHFbs08XboFDqKum3sc4h3GRxrTmQdl1ZK9uw-PIHf
QP0FkxXVrx-WE-ZEbrqivH_2iCLUS7wAl6XvARt1KkIaUxPPSYB9yk31s0Q8
UK96E3_OrADAYtAJs-M3JxCLfNgqh56HDnETTQhH3rCT5T3yJws",
"q":"1u_RiFDP7LBYh3N4GXLT9OpSKYP0uQZyiaZwBtOCBNJgQxaj10RWjsZu0c6I
edis4S7B_coSKB0Kj9PaPaBzg-IySRvvcQuPamQu66riMhjVtG6TlV8CLCYK
rYl52ziqK0E_ym2QnkwsUX7eYTB7LbAHRK9GqocDE5B0f808I4s",
"dp":"KkMTWqBUefVwZ2_Dbj1pPQqyHSHjj90L5x_MOzqYAJMcLMZtbUtwKqvVDq3
tbEo3ZIcohbDtt6SbfmWzggabpQxNxuBpoOOf_a_HgMXK_lhqigI4y_kqS1w
Y52IwjUn5rgRrJ-yYo1h41KR-vz2pYhEAeYrhttWtxVqLCRViD6c",
"dq":"AvfS0-gRxvn0bwJoMSnFxYcK1WnuEjQFluMGfwGitQBWtfZ1Er7t1xDkbN9
GQTB9yqpDoYaN06H7CFtrkxhJIBQaj6nkF5KKS3TQtQ5qCzkOkmxIe3KRbBy
mXxkb5qwUpX5ELD5xFc6FeiafWYY63TmmEAu_lRFCOJ3xDea-ots",
"qi":"lSQi-w9CpyUReMErP1RsBLk7wNtOvs5EQpPqmuMvqW57NBUczScEoPwmUqq
abu9V0-Py4dQ57_bapoKRu1R90bvuFnU63SHWEFglZQvJDMeAvmj4sm-Fp0o
Yu_neotgQ0hzbI5gry7ajdYy9-2lNx_76aBZoOUu9HCJ-UsfSOI8"}`),
// X.509 Certificate Chain
stripWhitespace(`{"kty":"RSA",
"use":"sig",
"kid":"1b94c",
"n":"vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08
PLbK_PdiVGKPrqzmDIsLI7sA25VEnHU1uCLNwBuUiCO11_-7dYbsr4iJmG0Q
u2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7iI7w0LK9orSMhBEwwZDCxTWq4a
YWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy1wgzjYQDwH
MTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMv
VfJb6jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ",
"e":"AQAB",
"x5c":
["MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJB
gNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYD
VQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1
wYmVsbDAeFw0xMzAyMjEyMzI5MTVaFw0xODA4MTQyMjI5MTVaMGIxCzAJBg
NVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDV
QQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1w
YmVsbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64zn8/QnH
YMeZ0LncoXaEde1fiLm1jHjmQsF/449IYALM9if6amFtPDy2yvz3YlRij66
s5gyLCyO7ANuVRJx1NbgizcAblIgjtdf/u3WG7K+IiZhtELto/A7Fck9Ws6
SQvzRvOE8uSirYbgmj6He4iO8NCyvaK0jIQRMMGQwsU1quGmFgHIXPLfnpn
fajr1rVTAwtgV5LEZ4Iel+W1GC8ugMhyr4/p1MtcIM42EA8BzE6ZQqC7VPq
PvEjZ2dbZkaBhPbiZAS3YeYBRDWm1p1OZtWamT3cEvqqPpnjL1XyW+oyVVk
aZdklLQp2Btgt9qr21m42f4wTw+Xrp6rCKNb0CAwEAATANBgkqhkiG9w0BA
QUFAAOCAQEAh8zGlfSlcI0o3rYDPBB07aXNswb4ECNIKG0CETTUxmXl9KUL
+9gGlqCz5iWLOgWsnrcKcY0vXPG9J1r9AqBNTqNgHq2G03X09266X5CpOe1
zFo+Owb1zxtp3PehFdfQJ610CDLEaS9V9Rqp17hCyybEpOGVwe8fnk+fbEL
2Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo
4tpzd5rFXhjRbg4zW9C+2qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTq
gawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA=="]}`),
}
// SHA-256 thumbprints of the above keys, hex-encoded
var cookbookJWKThumbprints = []string{
"747ae2dd2003664aeeb21e4753fe7402846170a16bc8df8f23a8cf06d3cbe793",
"f6934029a341ddf81dceb753e91d17efe16664f40d9f4ed84bc5ea87e111f29d",
"747ae2dd2003664aeeb21e4753fe7402846170a16bc8df8f23a8cf06d3cbe793",
"f63838e96077ad1fc01c3f8405774dedc0641f558ebb4b40dccf5f9b6d66a932",
"0fc478f8579325fcee0d4cbc6d9d1ce21730a6e97e435d6008fb379b0ebe47d4",
"0ddb05bfedbec2070fa037324ba397396561d3425d6d69245570c261dc49dee3",
}
func TestWebKeyVectorsValid(t *testing.T) {
for _, key := range cookbookJWKs {
var jwk2 JSONWebKey
err := jwk2.UnmarshalJSON([]byte(key))
if err != nil {
t.Error("unable to parse valid key:", key, err)
}
}
}
func TestThumbprint(t *testing.T) {
for i, key := range cookbookJWKs {
var jwk2 JSONWebKey
err := jwk2.UnmarshalJSON([]byte(key))
if err != nil {
t.Error("unable to parse valid key:", key, err)
}
tp, err := jwk2.Thumbprint(crypto.SHA256)
if err != nil {
t.Error("unable to compute thumbprint:", key, err)
}
tpHex := hex.EncodeToString(tp)
if cookbookJWKThumbprints[i] != tpHex {
t.Error("incorrect thumbprint:", i, cookbookJWKThumbprints[i], tpHex)
}
}
}
func TestMarshalUnmarshalJWKSet(t *testing.T) {
jwk1 := JSONWebKey{Key: rsaTestKey, KeyID: "ABCDEFG", Algorithm: "foo"}
jwk2 := JSONWebKey{Key: rsaTestKey, KeyID: "GFEDCBA", Algorithm: "foo"}
var set JSONWebKeySet
set.Keys = append(set.Keys, jwk1)
set.Keys = append(set.Keys, jwk2)
jsonbar, err := json.Marshal(&set)
if err != nil {
t.Error("problem marshalling set", err)
}
var set2 JSONWebKeySet
err = json.Unmarshal(jsonbar, &set2)
if err != nil {
t.Error("problem unmarshalling set", err)
}
jsonbar2, err := json.Marshal(&set2)
if err != nil {
t.Error("problem marshalling set", err)
}
if !bytes.Equal(jsonbar, jsonbar2) {
t.Error("roundtrip should not lose information")
}
}
func TestJWKSetKey(t *testing.T) {
jwk1 := JSONWebKey{Key: rsaTestKey, KeyID: "ABCDEFG", Algorithm: "foo"}
jwk2 := JSONWebKey{Key: rsaTestKey, KeyID: "GFEDCBA", Algorithm: "foo"}
var set JSONWebKeySet
set.Keys = append(set.Keys, jwk1)
set.Keys = append(set.Keys, jwk2)
k := set.Key("ABCDEFG")
if len(k) != 1 {
t.Errorf("method should return slice with one key not %d", len(k))
}
if k[0].KeyID != "ABCDEFG" {
t.Error("method should return key with ID ABCDEFG")
}
}
func TestJWKSymmetricKey(t *testing.T) {
sample1 := `{"kty":"oct","alg":"A128KW","k":"GawgguFyGrWKav7AX4VKUg"}`
sample2 := `{"kty":"oct","k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow","kid":"HMAC key used in JWS spec Appendix A.1 example"}`
var jwk1 JSONWebKey
json.Unmarshal([]byte(sample1), &jwk1)
if jwk1.Algorithm != "A128KW" {
t.Errorf("expected Algorithm to be A128KW, but was '%s'", jwk1.Algorithm)
}
expected1 := fromHexBytes("19ac2082e1721ab58a6afec05f854a52")
if !bytes.Equal(jwk1.Key.([]byte), expected1) {
t.Errorf("expected Key to be '%s', but was '%s'", hex.EncodeToString(expected1), hex.EncodeToString(jwk1.Key.([]byte)))
}
var jwk2 JSONWebKey
json.Unmarshal([]byte(sample2), &jwk2)
if jwk2.KeyID != "HMAC key used in JWS spec Appendix A.1 example" {
t.Errorf("expected KeyID to be 'HMAC key used in JWS spec Appendix A.1 example', but was '%s'", jwk2.KeyID)
}
expected2 := fromHexBytes(`
0323354b2b0fa5bc837e0665777ba68f5ab328e6f054c928a90f84b2d2502ebf
d3fb5a92d20647ef968ab4c377623d223d2e2172052e4f08c0cd9af567d080a3`)
if !bytes.Equal(jwk2.Key.([]byte), expected2) {
t.Errorf("expected Key to be '%s', but was '%s'", hex.EncodeToString(expected2), hex.EncodeToString(jwk2.Key.([]byte)))
}
}
func TestJWKSymmetricRoundtrip(t *testing.T) {
jwk1 := JSONWebKey{Key: []byte{1, 2, 3, 4}}
marshaled, err := jwk1.MarshalJSON()
if err != nil {
t.Error("failed to marshal valid JWK object", err)
}
var jwk2 JSONWebKey
err = jwk2.UnmarshalJSON(marshaled)
if err != nil {
t.Error("failed to unmarshal valid JWK object", err)
}
if !bytes.Equal(jwk1.Key.([]byte), jwk2.Key.([]byte)) {
t.Error("round-trip of symmetric JWK gave different raw keys")
}
}
func TestJWKSymmetricInvalid(t *testing.T) {
invalid := JSONWebKey{}
_, err := invalid.MarshalJSON()
if err == nil {
t.Error("excepted error on marshaling invalid symmetric JWK object")
}
var jwk JSONWebKey
err = jwk.UnmarshalJSON([]byte(`{"kty":"oct"}`))
if err == nil {
t.Error("excepted error on unmarshaling invalid symmetric JWK object")
}
}
func TestJWKIsPublic(t *testing.T) {
bigInt := big.NewInt(0)
eccPub := ecdsa.PublicKey{elliptic.P256(), bigInt, bigInt}
rsaPub := rsa.PublicKey{bigInt, 1}
cases := []struct {
key interface{}
expectedIsPublic bool
}{
{&eccPub, true},
{&ecdsa.PrivateKey{eccPub, bigInt}, false},
{&rsaPub, true},
{&rsa.PrivateKey{rsaPub, bigInt, []*big.Int{bigInt, bigInt}, rsa.PrecomputedValues{}}, false},
{ed25519PublicKey, true},
{ed25519PrivateKey, false},
}
for _, tc := range cases {
k := &JSONWebKey{Key: tc.key}
if public := k.IsPublic(); public != tc.expectedIsPublic {
t.Errorf("expected IsPublic to return %t, got %t", tc.expectedIsPublic, public)
}
}
}
func TestJWKValid(t *testing.T) {
bigInt := big.NewInt(0)
eccPub := ecdsa.PublicKey{elliptic.P256(), bigInt, bigInt}
rsaPub := rsa.PublicKey{bigInt, 1}
edPubEmpty := ed25519.PublicKey([]byte{})
edPrivEmpty := ed25519.PublicKey([]byte{})
cases := []struct {
key interface{}
expectedValidity bool
}{
{nil, false},
{&ecdsa.PublicKey{}, false},
{&eccPub, true},
{&ecdsa.PrivateKey{}, false},
{&ecdsa.PrivateKey{eccPub, bigInt}, true},
{&rsa.PublicKey{}, false},
{&rsaPub, true},
{&rsa.PrivateKey{}, false},
{&rsa.PrivateKey{rsaPub, bigInt, []*big.Int{bigInt, bigInt}, rsa.PrecomputedValues{}}, true},
{ed25519PublicKey, true},
{ed25519PrivateKey, true},
{edPubEmpty, false},
{edPrivEmpty, false},
}
for _, tc := range cases {
k := &JSONWebKey{Key: tc.key}
valid := k.Valid()
if valid != tc.expectedValidity {
t.Errorf("expected Valid to return %t, got %t", tc.expectedValidity, valid)
}
if valid {
wasPublic := k.IsPublic()
p := k.Public() // all aforemention keys are asymmetric
if !p.Valid() {
t.Errorf("unable to derive public key from valid asymmetric key")
}
if wasPublic != k.IsPublic() {
t.Errorf("original key was touched during public key derivation")
}
}
}
}

View file

@ -1,616 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jose
import (
"crypto/x509"
"strings"
"testing"
)
const trustedCA = `
-----BEGIN CERTIFICATE-----
MIIE6DCCAtCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlUcnVz
dGVkQ0EwHhcNMTgwMzI4MTg0MzA0WhcNMzgwMzI4MTg0MzA0WjAUMRIwEAYDVQQD
EwlUcnVzdGVkQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsHcd3
uaKBilWQUe2epNf86xvq2HZV+JDULjJlKfUQAkpG+huHDEMiPEFPSlQK17bFj7gc
qOx/INeeCU2nBVtZDtlm3U0jfQWO2F2kZgH1JWnEArrAWWy3BP/NYv7apBLcl7nD
hkL4USVUnXF8mtuegiSMI2YT7TVchGzYMjrj/j+oRuDm1GF1OxoIMeUuVmqyJ6jK
Kxv9YVmCB+e/QaUltkPGwxl2dKWdBwECXDgSr7hcZhT8ANmgFR1dJjLCy0Us12yw
5eKUANDlfNP+z9urykoAwHXpBlmga1ze45aL+p+7K+8sl/PgMqKO7VdT5GBsOCzf
xaBDG5Qy92Di34Sc27ZZz0mfaIy5kySnceBclMyWb8vdhEGkyHVsGpWc63JBmtg+
bKeh876m7KVLfiykfpMqHUhq/ImQwiQTwX2RonFK5gP+XU0I9V+4rE0iqucbcvCS
HuHzhf6B+TybhalRsvOZ6GB/SokF5YCmf8ylAq4be/HSxnJQcBhpSSQp0zz4ZKOD
ikXuwf29yhWZ0lgIyaZpT9H4QecWNcyx4UcqO3wQAGjxadTG3gzjLu/OJwPkw+bK
RvXWSBZjlQ9+JPmrHH+oKMgHshR4TQmtmXqXLaarrAe+HXCZEiBKFOqPgeo2RMxr
LAO+MYIsVtEz39gISRhEvqcAls01sV1l7oGicQIDAQABo0UwQzAOBgNVHQ8BAf8E
BAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUy9Nqk0mDRwC5tcmN
xQ1YWO5MAhgwDQYJKoZIhvcNAQELBQADggIBAHbpsqY+tPSj8BSky+acZoZjF7fZ
Ae3MKVogwm5tecmwTKf5xDj9J99ZpGvcWCKtoxxWw0LZ+JI/aeqANSRDXZIelcIw
yZefw06z/coQJwAIy1RSoKJPV72mkG0Es9w2HxSEoLaZ9tql0TyV8D/QseUM8Yt/
nNtShRoj6iMnZjhmut5pLfrLWHwQkt4fguBpL7rtydS/wAsOmnJ7lmOrU6zrBJzD
vEER3AJtgdIt4GvKf4MupKLgKvYDB4sUQVmMyAS78B9+WZDDRTClsx+/Oc1ggkWz
8X7EmIw+3U9V2hd67qZ81EwcSB8ixV06E7ZcbhnJs7ds7swqUjwMArFWuzqO4cjW
2BnyVzCO9pymFLI7qol32xCEgaQlOVS/kFHP3meygfeaeYe902sJw6NevOA4e0AO
AKR8FDfGRXJ9cOmYzeHeWKex8yt1Ul6+N8SXzjOhf39JM0QqTfHN7pPfFthTAFOs
9rI/buJteJqR1WxgVk/jY4wLGEOcEyO6Y/Uj5iWWTvm5G/C1yZfSg+NvWoytxZ7P
3S0qtEfmT4UwuHBsd5ZfEZoxb+GbqL/nhrKz/0B9LyKS0SJP9+mz7nSORz7t35Uc
BhiG6T9W7P/NRW4Tqb2tEN1VwU6eP5SEf7c7C1VVaepk0fvc1p5dl67IERqPucPD
dT2rDsCMBV7SXMUM
-----END CERTIFICATE-----`
const intermediateCA = `
-----BEGIN CERTIFICATE-----
MIIEHTCCAgWgAwIBAgIQXzZsEQv0cvSRLJAkS9FmWTANBgkqhkiG9w0BAQsFADAU
MRIwEAYDVQQDEwlUcnVzdGVkQ0EwHhcNMTgwMzI4MTg0MzMzWhcNMzgwMzI4MTg0
MzAzWjAZMRcwFQYDVQQDEw5JbnRlcm1lZGlhdGVDQTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAN3aYpH/1yEYf/kHuHWyO3AO4tgwlYYLhCDT2GvaPdaE
cqhe/VuYiqx3xY7IRDqsW2rau/OXgW6KzLHdRZHogK07hUj1Lfr7X+Oqbp22IV4y
dyiL7jwK9AtVXvDuuv5ET+oRfV82j0uhyk0ueGD9r6C/h+6NTzHBD+3xo6Yuc0Vk
BfY5zIyhaFqlm1aRYvupDRjC/63uBgAlrGxy2LyiTMVnYMuxoJM5ahDepz3sqjuN
WVyPhfGwIezjXuXRdEvlmWX05XLnsTdP4zu4fHq9Z7c3TKWWONM3z64ECAZmGQVf
MAcEDX7qP0gZX5PCT+0WcvTgTWE4Q+WIh5AmYyxQ04cCAwEAAaNmMGQwDgYDVR0P
AQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFMAYlq86RZzT
WxLpYE7KTTM7DHOuMB8GA1UdIwQYMBaAFMvTapNJg0cAubXJjcUNWFjuTAIYMA0G
CSqGSIb3DQEBCwUAA4ICAQBmYRpQoWEm5g16kwUrpwWrH7OIqqMtUhM1dcskECfk
i3/hcsV+MQRkGHLIItucYIWqs7oOQIglsyGcohAbnvE1PVtKKojUHC0lfbjgIenD
Pbvz15QB6A3KLDR82QbQGeGniACy924p66zlfPwHJbkMo5ZaqtNqI//EIa2YCpyy
okhFXaSFmPWXXrTOCsEEsFJKsoSCH1KUpTcwACGkkilNseg1edZB6/lBDwybxVuY
+dbUlHip3r5tFcP66Co3tKAaEcVY0AsZ/8GKwH+IM2AR6q7jdn9Gp2OX4E1ul9Wy
+hW5GHMmfixkgTVwRowuKgkCPEKV2/Xy3k9rlSpnKr2NpYYq0mu6An9HYt8THQ+e
wGZHwWufuDFDWuzlu7CxFOjpXLKv8qqVnwSFC91S3HsPAzPKLC9ZMEC+iQs2Vkes
Os0nFLZeMaMGAO5W6xiyQ5p94oo0bqa1XbmSV1bNp1HWuNEGIiZKrEUDxfYuDc6f
C6hJZKsjJkMkBeadlQAlLcjIx1rDV171CKLLTxy/dT5kv4p9UrJlnleyMVG6S/3d
6nX/WLSgZIMYbOwiZVVPlSrobuG38ULJMCSuxndxD0l+HahJaH8vYXuR67A0XT+b
TEe305AI6A/9MEaRrActBnq6/OviQgBsKAvtTv1FmDbnpZsKeoFuwc3OPdTveQdC
RA==
-----END CERTIFICATE-----`
func TestEmbeddedHMAC(t *testing.T) {
// protected: {"alg":"HS256", "jwk":{"kty":"oct", "k":"MTEx"}}, aka HMAC key.
msg := `{"payload":"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ","protected":"eyJhbGciOiJIUzI1NiIsICJqd2siOnsia3R5Ijoib2N0IiwgImsiOiJNVEV4In19","signature":"lvo41ZZsuHwQvSh0uJtEXRR3vmuBJ7in6qMoD7p9jyo"}`
_, err := ParseSigned(msg)
if err == nil {
t.Error("should not allow parsing JWS with embedded JWK with HMAC key")
}
}
func TestCompactParseJWS(t *testing.T) {
// Should parse
msg := "eyJhbGciOiJYWVoifQ.cGF5bG9hZA.c2lnbmF0dXJl"
_, err := ParseSigned(msg)
if err != nil {
t.Error("Unable to parse valid message:", err)
}
// Should parse (detached signature missing payload)
msg = "eyJhbGciOiJYWVoifQ..c2lnbmF0dXJl"
_, err = ParseSigned(msg)
if err != nil {
t.Error("Unable to parse valid message:", err)
}
// Messages that should fail to parse
failures := []string{
// Not enough parts
"eyJhbGciOiJYWVoifQ.cGF5bG9hZA",
// Invalid signature
"eyJhbGciOiJYWVoifQ.cGF5bG9hZA.////",
// Invalid payload
"eyJhbGciOiJYWVoifQ.////.c2lnbmF0dXJl",
// Invalid header
"////.eyJhbGciOiJYWVoifQ.c2lnbmF0dXJl",
// Invalid header
"cGF5bG9hZA.cGF5bG9hZA.c2lnbmF0dXJl",
}
for i := range failures {
_, err = ParseSigned(failures[i])
if err == nil {
t.Error("Able to parse invalid message")
}
}
}
func TestFullParseJWS(t *testing.T) {
// Messages that should succeed to parse
successes := []string{
"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"e30\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"},{\"protected\":\"e30\",\"signature\":\"CUJD\"}]}",
}
for i := range successes {
_, err := ParseSigned(successes[i])
if err != nil {
t.Error("Unble to parse valid message", err, successes[i])
}
}
// Messages that should fail to parse
failures := []string{
// Empty
"{}",
// Invalid JSON
"{XX",
// Invalid protected header
"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"CUJD\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}]}",
// Invalid protected header
"{\"payload\":\"CUJD\",\"protected\":\"CUJD\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}",
// Invalid protected header
"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"###\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}]}",
// Invalid payload
"{\"payload\":\"###\",\"signatures\":[{\"protected\":\"CUJD\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}]}",
// Invalid payload
"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"e30\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"###\"}]}",
}
for i := range failures {
_, err := ParseSigned(failures[i])
if err == nil {
t.Error("Able to parse invalid message", err, failures[i])
}
}
}
func TestRejectUnprotectedJWSNonce(t *testing.T) {
// No need to test compact, since that's always protected
// Flattened JSON
input := `{
"header": { "nonce": "should-cause-an-error" },
"payload": "does-not-matter",
"signature": "does-not-matter"
}`
_, err := ParseSigned(input)
if err == nil {
t.Error("JWS with an unprotected nonce parsed as valid.")
} else if err != ErrUnprotectedNonce {
t.Errorf("Improper error for unprotected nonce: %v", err)
}
// Full JSON
input = `{
"payload": "does-not-matter",
"signatures": [{
"header": { "nonce": "should-cause-an-error" },
"signature": "does-not-matter"
}]
}`
_, err = ParseSigned(input)
if err == nil {
t.Error("JWS with an unprotected nonce parsed as valid.")
} else if err != ErrUnprotectedNonce {
t.Errorf("Improper error for unprotected nonce: %v", err)
}
}
func TestVerifyFlattenedWithIncludedUnprotectedKey(t *testing.T) {
input := `{
"header": {
"alg": "RS256",
"jwk": {
"e": "AQAB",
"kty": "RSA",
"n": "tSwgy3ORGvc7YJI9B2qqkelZRUC6F1S5NwXFvM4w5-M0TsxbFsH5UH6adigV0jzsDJ5imAechcSoOhAh9POceCbPN1sTNwLpNbOLiQQ7RD5mY_pSUHWXNmS9R4NZ3t2fQAzPeW7jOfF0LKuJRGkekx6tXP1uSnNibgpJULNc4208dgBaCHo3mvaE2HV2GmVl1yxwWX5QZZkGQGjNDZYnjFfa2DKVvFs0QbAk21ROm594kAxlRlMMrvqlf24Eq4ERO0ptzpZgm_3j_e4hGRD39gJS7kAzK-j2cacFQ5Qi2Y6wZI2p-FCq_wiYsfEAIkATPBiLKl_6d_Jfcvs_impcXQ"
}
},
"payload": "Zm9vCg",
"signature": "hRt2eYqBd_MyMRNIh8PEIACoFtmBi7BHTLBaAhpSU6zyDAFdEBaX7us4VB9Vo1afOL03Q8iuoRA0AT4akdV_mQTAQ_jhTcVOAeXPr0tB8b8Q11UPQ0tXJYmU4spAW2SapJIvO50ntUaqU05kZd0qw8-noH1Lja-aNnU-tQII4iYVvlTiRJ5g8_CADsvJqOk6FcHuo2mG643TRnhkAxUtazvHyIHeXMxydMMSrpwUwzMtln4ZJYBNx4QGEq6OhpAD_VSp-w8Lq5HOwGQoNs0bPxH1SGrArt67LFQBfjlVr94E1sn26p4vigXm83nJdNhWAMHHE9iV67xN-r29LT-FjA"
}`
jws, err := ParseSigned(input)
if err != nil {
t.Error("Unable to parse valid message.")
}
if len(jws.Signatures) != 1 {
t.Error("Too many or too few signatures.")
}
sig := jws.Signatures[0]
if sig.Header.JSONWebKey == nil {
t.Error("No JWK in signature header.")
}
payload, err := jws.Verify(sig.Header.JSONWebKey)
if err != nil {
t.Errorf("Signature did not validate: %v", err)
}
if string(payload) != "foo\n" {
t.Errorf("Payload was incorrect: '%s' should have been 'foo\\n'", string(payload))
}
}
// Test verification of a detached signature
func TestDetachedVerifyJWS(t *testing.T) {
rsaPublicKey, err := x509.ParsePKIXPublicKey(fromBase64Bytes(`
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3aLSGwbeX0ZA2Ha+EvELaIFGzO
91+Q15JQc/tdGdCgGW3XAbrh7ZUhDh1XKzbs+UOQxqn3Eq4YOx18IG0WsJSuCaHQIxnDlZ
t/GP8WLwjMC0izlJLm2SyfM/EEoNpmTC3w6MQ2dHK7SZ9Zoq+sKijQd+V7CYdr8zHMpDrd
NKoEcR0HjmvzzdMoUChhkGH5TaNbZyollULTggepaYUKS8QphqdSDMWiSetKG+g6V87lv6
CVYyK1FF6g7Esp5OOj5pNn3/bmF+7V+b7TvK91NCIlURCjE9toRgNoIP4TDnWRn/vvfZ3G
zNrtWmlizqz3r5KdvIs71ahWgMUSD4wfazrwIDAQAB`))
if err != nil {
t.Fatal(err)
}
sampleMessages := []string{
"eyJhbGciOiJSUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.YHX849fvekz6wJGeyqnQhFqyHFcUXNJKj3o2w3ddR46YLlsCopUJrlifRU_ZuTWzpYxt5oC--T2eoqMhlCvltSWrE5_1_EumqiMfAYsZULx9E6Jns7q3w7mttonYFSIh7aR3-yg2HMMfTCgoAY1y_AZ4VjXwHDcZ5gu1oZDYgvZF4uXtCmwT6e5YtR1m8abiWPF8BgoTG_BD3KV6ClLj_QQiNFdfdxAMDw7vKVOKG1T7BFtz6cDs2Q3ILS4To5E2IjcVSSYS8mi77EitCrWmrqbK_G3WCdKeUFGnMnyuKXaCDy_7FLpAZ6Z5RomRr5iskXeJZdZqIKcJV8zl4fpsPA",
"eyJhbGciOiJSUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.meyfoOTjAAjXHFYiNlU7EEnsYtbeUYeEglK6BL_cxISEr2YAGLr1Gwnn2HnucTnH6YilyRio7ZC1ohy_ZojzmaljPHqpr8kn1iqNFu9nFE2M16ZPgJi38-PGzppcDNliyzOQO-c7L-eA-v8Gfww5uyRaOJdiWg-hUJmeGBIngPIeLtSVmhJtz8oTeqeNdUOqQv7f7VRCuvagLhW1PcEM91VUS-gS0WEUXoXWZ2lp91No0v1O24izgX3__FKiX_16XhrOfAgJ82F61vjbTIQYwhexHPZyYTlXYt_scNRzFGhSKeGFin4zVdFLOXWJqKWdUd5IrDP5Nya3FSoWbWDXAg",
}
for _, msg := range sampleMessages {
obj, err := ParseSigned(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
payload := obj.payload
obj.payload = nil
err = obj.DetachedVerify(payload, rsaPublicKey)
if err != nil {
t.Error("unable to verify message", msg, err)
continue
}
idx, _, err := obj.DetachedVerifyMulti(payload, rsaPublicKey)
if idx != 0 || err != nil {
t.Error("unable to verify message", msg, err)
continue
}
}
}
func TestVerifyFlattenedWithPrivateProtected(t *testing.T) {
// The protected field contains a Private Header Parameter name, per
// https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-4
// Base64-decoded, it's '{"nonce":"8HIepUNFZUa-exKTrXVf4g"}'
input := `{"header":{"alg":"RS256","jwk":{"kty":"RSA","n":"7ixeydcbxxppzxrBphrW1atUiEZqTpiHDpI-79olav5XxAgWolHmVsJyxzoZXRxmtED8PF9-EICZWBGdSAL9ZTD0hLUCIsPcpdgT_LqNW3Sh2b2caPL2hbMF7vsXvnCGg9varpnHWuYTyRrCLUF9vM7ES-V3VCYTa7LcCSRm56Gg9r19qar43Z9kIKBBxpgt723v2cC4bmLmoAX2s217ou3uCpCXGLOeV_BesG4--Nl3pso1VhCfO85wEWjmW6lbv7Kg4d7Jdkv5DjDZfJ086fkEAYZVYGRpIgAvJBH3d3yKDCrSByUEud1bWuFjQBmMaeYOrVDXO_mbYg5PwUDMhw","e":"AQAB"}},"protected":"eyJub25jZSI6IjhISWVwVU5GWlVhLWV4S1RyWFZmNGcifQ","payload":"eyJjb250YWN0IjpbIm1haWx0bzpmb29AYmFyLmNvbSJdfQ","signature":"AyvVGMgXsQ1zTdXrZxE_gyO63pQgotL1KbI7gv6Wi8I7NRy0iAOkDAkWcTQT9pcCYApJ04lXfEDZfP5i0XgcFUm_6spxi5mFBZU-NemKcvK9dUiAbXvb4hB3GnaZtZiuVnMQUb_ku4DOaFFKbteA6gOYCnED_x7v0kAPHIYrQnvIa-KZ6pTajbV9348zgh9TL7NgGIIsTcMHd-Jatr4z1LQ0ubGa8tS300hoDhVzfoDQaEetYjCo1drR1RmdEN1SIzXdHOHfubjA3ZZRbrF_AJnNKpRRoIwzu1VayOhRmdy1qVSQZq_tENF4VrQFycEL7DhG7JLoXC4T2p1urwMlsw"}`
jws, err := ParseSigned(input)
if err != nil {
t.Error("Unable to parse valid message.")
}
if len(jws.Signatures) != 1 {
t.Error("Too many or too few signatures.")
}
sig := jws.Signatures[0]
if sig.Header.JSONWebKey == nil {
t.Error("No JWK in signature header.")
}
payload, err := jws.Verify(sig.Header.JSONWebKey)
if err != nil {
t.Errorf("Signature did not validate: %v", err)
}
expected := "{\"contact\":[\"mailto:foo@bar.com\"]}"
if string(payload) != expected {
t.Errorf("Payload was incorrect: '%s' should have been '%s'", string(payload), expected)
}
}
// Test vectors generated with nimbus-jose-jwt
func TestSampleNimbusJWSMessagesRSA(t *testing.T) {
rsaPublicKey, err := x509.ParsePKIXPublicKey(fromBase64Bytes(`
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3aLSGwbeX0ZA2Ha+EvELaIFGzO
91+Q15JQc/tdGdCgGW3XAbrh7ZUhDh1XKzbs+UOQxqn3Eq4YOx18IG0WsJSuCaHQIxnDlZ
t/GP8WLwjMC0izlJLm2SyfM/EEoNpmTC3w6MQ2dHK7SZ9Zoq+sKijQd+V7CYdr8zHMpDrd
NKoEcR0HjmvzzdMoUChhkGH5TaNbZyollULTggepaYUKS8QphqdSDMWiSetKG+g6V87lv6
CVYyK1FF6g7Esp5OOj5pNn3/bmF+7V+b7TvK91NCIlURCjE9toRgNoIP4TDnWRn/vvfZ3G
zNrtWmlizqz3r5KdvIs71ahWgMUSD4wfazrwIDAQAB`))
if err != nil {
panic(err)
}
rsaSampleMessages := []string{
"eyJhbGciOiJSUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.YHX849fvekz6wJGeyqnQhFqyHFcUXNJKj3o2w3ddR46YLlsCopUJrlifRU_ZuTWzpYxt5oC--T2eoqMhlCvltSWrE5_1_EumqiMfAYsZULx9E6Jns7q3w7mttonYFSIh7aR3-yg2HMMfTCgoAY1y_AZ4VjXwHDcZ5gu1oZDYgvZF4uXtCmwT6e5YtR1m8abiWPF8BgoTG_BD3KV6ClLj_QQiNFdfdxAMDw7vKVOKG1T7BFtz6cDs2Q3ILS4To5E2IjcVSSYS8mi77EitCrWmrqbK_G3WCdKeUFGnMnyuKXaCDy_7FLpAZ6Z5RomRr5iskXeJZdZqIKcJV8zl4fpsPA",
"eyJhbGciOiJSUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.meyfoOTjAAjXHFYiNlU7EEnsYtbeUYeEglK6BL_cxISEr2YAGLr1Gwnn2HnucTnH6YilyRio7ZC1ohy_ZojzmaljPHqpr8kn1iqNFu9nFE2M16ZPgJi38-PGzppcDNliyzOQO-c7L-eA-v8Gfww5uyRaOJdiWg-hUJmeGBIngPIeLtSVmhJtz8oTeqeNdUOqQv7f7VRCuvagLhW1PcEM91VUS-gS0WEUXoXWZ2lp91No0v1O24izgX3__FKiX_16XhrOfAgJ82F61vjbTIQYwhexHPZyYTlXYt_scNRzFGhSKeGFin4zVdFLOXWJqKWdUd5IrDP5Nya3FSoWbWDXAg",
"eyJhbGciOiJSUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.rQPz0PDh8KyE2AX6JorgI0MLwv-qi1tcWlz6tuZuWQG1hdrlzq5tR1tQg1evYNc_SDDX87DWTSKXT7JEqhKoFixLfZa13IJrOc7FB8r5ZLx7OwOBC4F--OWrvxMA9Y3MTJjPN3FemQePUo-na2vNUZv-YgkcbuOgbO3hTxwQ7j1JGuqy-YutXOFnccdXvntp3t8zYZ4Mg1It_IyL9pzgGqHIEmMV1pCFGHsDa-wStB4ffmdhrADdYZc0q_SvxUdobyC_XzZCz9ENzGIhgwYxyyrqg7kjqUGoKmCLmoSlUFW7goTk9IC5SXdUyLPuESxOWNfHoRClGav230GYjPFQFA",
"eyJhbGciOiJQUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.UTtxjsv_6x4CdlAmZfAW6Lun3byMjJbcwRp_OlPH2W4MZaZar7aql052mIB_ddK45O9VUz2aphYVRvKPZY8WHmvlTUU30bk0z_cDJRYB9eIJVMOiRCYj0oNkz1iEZqsP0YgngxwuUDv4Q4A6aJ0Bo5E_rZo3AnrVHMHUjPp_ZRRSBFs30tQma1qQ0ApK4Gxk0XYCYAcxIv99e78vldVRaGzjEZmQeAVZx4tGcqZP20vG1L84nlhSGnOuZ0FhR8UjRFLXuob6M7EqtMRoqPgRYw47EI3fYBdeSivAg98E5S8R7R1NJc7ef-l03RvfUSY0S3_zBq_4PlHK6A-2kHb__w",
"eyJhbGciOiJSUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.meyfoOTjAAjXHFYiNlU7EEnsYtbeUYeEglK6BL_cxISEr2YAGLr1Gwnn2HnucTnH6YilyRio7ZC1ohy_ZojzmaljPHqpr8kn1iqNFu9nFE2M16ZPgJi38-PGzppcDNliyzOQO-c7L-eA-v8Gfww5uyRaOJdiWg-hUJmeGBIngPIeLtSVmhJtz8oTeqeNdUOqQv7f7VRCuvagLhW1PcEM91VUS-gS0WEUXoXWZ2lp91No0v1O24izgX3__FKiX_16XhrOfAgJ82F61vjbTIQYwhexHPZyYTlXYt_scNRzFGhSKeGFin4zVdFLOXWJqKWdUd5IrDP5Nya3FSoWbWDXAg",
"eyJhbGciOiJSUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.rQPz0PDh8KyE2AX6JorgI0MLwv-qi1tcWlz6tuZuWQG1hdrlzq5tR1tQg1evYNc_SDDX87DWTSKXT7JEqhKoFixLfZa13IJrOc7FB8r5ZLx7OwOBC4F--OWrvxMA9Y3MTJjPN3FemQePUo-na2vNUZv-YgkcbuOgbO3hTxwQ7j1JGuqy-YutXOFnccdXvntp3t8zYZ4Mg1It_IyL9pzgGqHIEmMV1pCFGHsDa-wStB4ffmdhrADdYZc0q_SvxUdobyC_XzZCz9ENzGIhgwYxyyrqg7kjqUGoKmCLmoSlUFW7goTk9IC5SXdUyLPuESxOWNfHoRClGav230GYjPFQFA",
}
for _, msg := range rsaSampleMessages {
obj, err := ParseSigned(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
payload, err := obj.Verify(rsaPublicKey)
if err != nil {
t.Error("unable to verify message", msg, err)
continue
}
if string(payload) != "Lorem ipsum dolor sit amet" {
t.Error("payload is not what we expected for msg", msg)
}
}
}
// Test vectors generated with nimbus-jose-jwt
func TestSampleNimbusJWSMessagesEC(t *testing.T) {
ecPublicKeyP256, err := x509.ParsePKIXPublicKey(fromBase64Bytes("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIg62jq6FyL1otEj9Up7S35BUrwGF9TVrAzrrY1rHUKZqYIGEg67u/imjgadVcr7y9Q32I0gB8W8FHqbqt696rA=="))
if err != nil {
panic(err)
}
ecPublicKeyP384, err := x509.ParsePKIXPublicKey(fromBase64Bytes("MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEPXsVlqCtN2oTY+F+hFZm3M0ldYpb7IeeJM5wYmT0k1RaqzBFDhDMNnYK5Q5x+OyssZrAtHgYDFw02AVJhhng/eHRp7mqmL/vI3wbxJtrLKYldIbBA+9fYBQcKeibjlu5"))
if err != nil {
panic(err)
}
ecPublicKeyP521, err := x509.ParsePKIXPublicKey(fromBase64Bytes("MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAa2w3MMJ5FWD6tSf68G+Wy5jIhWXOD3IA7pE5IC/myQzo1lWcD8KS57SM6nm4POtPcxyLmDhL7FLuh8DKoIZyvtAAdK8+tOQP7XXRlT2bkvzIuazp05It3TAPu00YzTIpKfDlc19Y1lvf7etrbFqhShD92B+hHmhT4ddrdbPCBDW8hvU="))
if err != nil {
panic(err)
}
ecPublicKeys := []interface{}{ecPublicKeyP256, ecPublicKeyP384, ecPublicKeyP521}
ecSampleMessages := []string{
"eyJhbGciOiJFUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.MEWJVlvGRQyzMEGOYm4rwuiwxrX-6LjnlbaRDAuhwmnBm2Gtn7pRpGXRTMFZUXsSGDz2L1p-Hz1qn8j9bFIBtQ",
"eyJhbGciOiJFUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.nbdjPnJPYQtVNNdBIx8-KbFKplTxrz-hnW5UNhYUY7SBkwHK4NZnqc2Lv4DXoA0aWHq9eiypgOh1kmyPWGEmqKAHUx0xdIEkBoHk3ZsbmhOQuq2jL_wcMUG6nTWNhLrB",
"eyJhbGciOiJFUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.AeYNFC1rwIgQv-5fwd8iRyYzvTaSCYTEICepgu9gRId-IW99kbSVY7yH0MvrQnqI-a0L8zwKWDR35fW5dukPAYRkADp3Y1lzqdShFcEFziUVGo46vqbiSajmKFrjBktJcCsfjKSaLHwxErF-T10YYPCQFHWb2nXJOOI3CZfACYqgO84g",
}
for i, msg := range ecSampleMessages {
obj, err := ParseSigned(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
payload, err := obj.Verify(ecPublicKeys[i])
if err != nil {
t.Error("unable to verify message", msg, err)
continue
}
if string(payload) != "Lorem ipsum dolor sit amet" {
t.Error("payload is not what we expected for msg", msg)
}
}
}
// Test vectors generated with nimbus-jose-jwt
func TestSampleNimbusJWSMessagesHMAC(t *testing.T) {
hmacTestKey := fromHexBytes("DF1FA4F36FFA7FC42C81D4B3C033928D")
hmacSampleMessages := []string{
"eyJhbGciOiJIUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.W5tc_EUhxexcvLYEEOckyyvdb__M5DQIVpg6Nmk1XGM",
"eyJhbGciOiJIUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.sBu44lXOJa4Nd10oqOdYH2uz3lxlZ6o32QSGHaoGdPtYTDG5zvSja6N48CXKqdAh",
"eyJhbGciOiJIUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.M0yR4tmipsORIix-BitIbxEPGaxPchDfj8UNOpKuhDEfnb7URjGvCKn4nOlyQ1z9mG1FKbwnqR1hOVAWSzAU_w",
}
for _, msg := range hmacSampleMessages {
obj, err := ParseSigned(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
payload, err := obj.Verify(hmacTestKey)
if err != nil {
t.Error("unable to verify message", msg, err)
continue
}
if string(payload) != "Lorem ipsum dolor sit amet" {
t.Error("payload is not what we expected for msg", msg)
}
}
}
func TestHeaderFieldsCompact(t *testing.T) {
msg := "eyJhbGciOiJFUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.AeYNFC1rwIgQv-5fwd8iRyYzvTaSCYTEICepgu9gRId-IW99kbSVY7yH0MvrQnqI-a0L8zwKWDR35fW5dukPAYRkADp3Y1lzqdShFcEFziUVGo46vqbiSajmKFrjBktJcCsfjKSaLHwxErF-T10YYPCQFHWb2nXJOOI3CZfACYqgO84g"
obj, err := ParseSigned(msg)
if err != nil {
t.Fatal("unable to parse message", msg, err)
}
if obj.Signatures[0].Header.Algorithm != "ES512" {
t.Error("merged header did not contain expected alg value")
}
if obj.Signatures[0].Protected.Algorithm != "ES512" {
t.Error("protected header did not contain expected alg value")
}
if obj.Signatures[0].Unprotected.Algorithm != "" {
t.Error("unprotected header contained an alg value")
}
}
func TestHeaderFieldsFull(t *testing.T) {
msg := `{"payload":"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ","protected":"eyJhbGciOiJFUzUxMiJ9","header":{"custom":"test"},"signature":"AeYNFC1rwIgQv-5fwd8iRyYzvTaSCYTEICepgu9gRId-IW99kbSVY7yH0MvrQnqI-a0L8zwKWDR35fW5dukPAYRkADp3Y1lzqdShFcEFziUVGo46vqbiSajmKFrjBktJcCsfjKSaLHwxErF-T10YYPCQFHWb2nXJOOI3CZfACYqgO84g"}`
obj, err := ParseSigned(msg)
if err != nil {
t.Fatal("unable to parse message", msg, err)
}
if obj.Signatures[0].Header.Algorithm != "ES512" {
t.Error("merged header did not contain expected alg value")
}
if obj.Signatures[0].Protected.Algorithm != "ES512" {
t.Error("protected header did not contain expected alg value")
}
if obj.Signatures[0].Unprotected.Algorithm != "" {
t.Error("unprotected header contained an alg value")
}
if obj.Signatures[0].Unprotected.ExtraHeaders["custom"] != "test" {
t.Error("unprotected header did not contain custom header value")
}
}
// Test vectors generated with nimbus-jose-jwt
func TestErrorMissingPayloadJWS(t *testing.T) {
_, err := (&rawJSONWebSignature{}).sanitized()
if err == nil {
t.Error("was able to parse message with missing payload")
}
if !strings.Contains(err.Error(), "missing payload") {
t.Errorf("unexpected error message, should contain 'missing payload': %s", err)
}
}
// Test that a null value in the header doesn't panic
func TestNullHeaderValue(t *testing.T) {
msg := `{
"payload":
"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF
tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
"protected":"eyJhbGciOiJFUzI1NiIsIm5vbmNlIjpudWxsfQ",
"header":
{"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
"signature":
"DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS
lSApmWQxfKTUJqPP3-Kg6NU1Q"
}`
defer func() {
if r := recover(); r != nil {
t.Errorf("ParseSigned panic'd when parsing a message with a null protected header value")
}
}()
ParseSigned(msg)
}
// Test for bug:
// https://github.com/square/go-jose/issues/157
func TestEmbedJWKBug(t *testing.T) {
signerKey := SigningKey{
Key: &JSONWebKey{
Key: rsaTestKey,
KeyID: "rsa-test-key",
},
Algorithm: RS256,
}
signer, err := NewSigner(signerKey, &SignerOptions{EmbedJWK: true})
if err != nil {
t.Fatal(err)
}
signerNoEmbed, err := NewSigner(signerKey, &SignerOptions{EmbedJWK: false})
if err != nil {
t.Fatal(err)
}
jws, err := signer.Sign([]byte("Lorem ipsum dolor sit amet"))
if err != nil {
t.Fatal(err)
}
jwsNoEmbed, err := signerNoEmbed.Sign([]byte("Lorem ipsum dolor sit amet"))
if err != nil {
t.Fatal(err)
}
// This used to panic with:
// json: error calling MarshalJSON for type *jose.JSONWebKey: square/go-jose: unknown key type '%!s(<nil>)'
output := jws.FullSerialize()
outputNoEmbed := jwsNoEmbed.FullSerialize()
// Expected output with embed set to true is a JWS with the public JWK embedded, with kid header empty.
// Expected output with embed set to false is that we set the kid header for key identification instead.
parsed, err := ParseSigned(output)
if err != nil {
t.Fatal(err)
}
parsedNoEmbed, err := ParseSigned(outputNoEmbed)
if err != nil {
t.Fatal(err)
}
if parsed.Signatures[0].Header.KeyID != "" {
t.Error("expected kid field in protected header to be empty")
}
if parsed.Signatures[0].Header.JSONWebKey.KeyID != "rsa-test-key" {
t.Error("expected rsa-test-key to be kid in embedded JWK in protected header")
}
if parsedNoEmbed.Signatures[0].Header.KeyID != "rsa-test-key" {
t.Error("expected kid field in protected header to be rsa-test-key")
}
if parsedNoEmbed.Signatures[0].Header.JSONWebKey != nil {
t.Error("expected no embedded JWK to be present")
}
}
func TestJWSWithCertificateChain(t *testing.T) {
signerKey := SigningKey{
Key: rsaTestKey,
Algorithm: RS256,
}
certs := []string{
// CN=TrustedSigner, signed by IntermediateCA
"MIIDLDCCAhSgAwIBAgIQNsV1i7m3kXGugqOQuuC7FzANBgkqhkiG9w0BAQsFADAZMRcwFQYDVQQDEw5JbnRlcm1lZGlhdGVDQTAeFw0xODAzMjgxODQzNDlaFw0zODAzMjgxODQzMDJaMBgxFjAUBgNVBAMTDVRydXN0ZWRTaWduZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLpvmOEDRxzQJUKHLkLQSsFDo9eGnolSERa6fz1E1F4wmk6nieHqssPd28C6Vb1sHJFne/j93DXNrx7W9Gy9fQvWa+VNHfGuYAodaS2pyV4VUPWMXI2a+qjxW85orq34XtcHzU+qm+ekR5W06ypW+xewbXJW//P9ulrsv3bDoDFaiggHY/u3p5CRSB9mg+Pbpf6E/k/N85sFJUsRE9hzgwg27Kqhh6p3hP3QnA+0WZRcWhwG0gykoD6layRLCPVcxlTSUdpyStDiK8w2whLJQfixCBGLS3/tB/GKb726bxTQK72OLzIMtOo4ZMtTva7bcA2PRgwfRz7bJg4DXz7oHTAgMBAAGjcTBvMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFCpZEyJGAyK//NsYSSC4xkOqNnh3MB8GA1UdIwQYMBaAFMAYlq86RZzTWxLpYE7KTTM7DHOuMA0GCSqGSIb3DQEBCwUAA4IBAQBSIln6jPFkctPC17le0O+wkCStFOuqUM9cjwPuj4xBQ47RxmC0Pjv52N3TuVH7slmMykITQO/vVqQZguf+N5u4BCh223qWiu1muYBTfBPXCPgJjJ79bUL/dy9QEocOfPiIqTFC6xHKeSUCu6qi5jCPFynOaoVvlNPZEb2MR+QrkKVzg09aDEfk6J+wE6eH9+kNOtwvd/z2a2t2hterURtJEnYt7AQGviEpUf1gbHxCE9f3FW5iJGdgcshrk5ZwUfxvND2x4qFq2fYQRxNBnkO+TSYzwYoAItcGAUvlZFH+rdsq3N+UpRptXRkj5iMq59VlcXFOT675EkkNREgromWn",
// CN=IntermediateCA, signed by TrustedCA
"MIIEHTCCAgWgAwIBAgIQXzZsEQv0cvSRLJAkS9FmWTANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlUcnVzdGVkQ0EwHhcNMTgwMzI4MTg0MzMzWhcNMzgwMzI4MTg0MzAzWjAZMRcwFQYDVQQDEw5JbnRlcm1lZGlhdGVDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN3aYpH/1yEYf/kHuHWyO3AO4tgwlYYLhCDT2GvaPdaEcqhe/VuYiqx3xY7IRDqsW2rau/OXgW6KzLHdRZHogK07hUj1Lfr7X+Oqbp22IV4ydyiL7jwK9AtVXvDuuv5ET+oRfV82j0uhyk0ueGD9r6C/h+6NTzHBD+3xo6Yuc0VkBfY5zIyhaFqlm1aRYvupDRjC/63uBgAlrGxy2LyiTMVnYMuxoJM5ahDepz3sqjuNWVyPhfGwIezjXuXRdEvlmWX05XLnsTdP4zu4fHq9Z7c3TKWWONM3z64ECAZmGQVfMAcEDX7qP0gZX5PCT+0WcvTgTWE4Q+WIh5AmYyxQ04cCAwEAAaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFMAYlq86RZzTWxLpYE7KTTM7DHOuMB8GA1UdIwQYMBaAFMvTapNJg0cAubXJjcUNWFjuTAIYMA0GCSqGSIb3DQEBCwUAA4ICAQBmYRpQoWEm5g16kwUrpwWrH7OIqqMtUhM1dcskECfki3/hcsV+MQRkGHLIItucYIWqs7oOQIglsyGcohAbnvE1PVtKKojUHC0lfbjgIenDPbvz15QB6A3KLDR82QbQGeGniACy924p66zlfPwHJbkMo5ZaqtNqI//EIa2YCpyyokhFXaSFmPWXXrTOCsEEsFJKsoSCH1KUpTcwACGkkilNseg1edZB6/lBDwybxVuY+dbUlHip3r5tFcP66Co3tKAaEcVY0AsZ/8GKwH+IM2AR6q7jdn9Gp2OX4E1ul9Wy+hW5GHMmfixkgTVwRowuKgkCPEKV2/Xy3k9rlSpnKr2NpYYq0mu6An9HYt8THQ+ewGZHwWufuDFDWuzlu7CxFOjpXLKv8qqVnwSFC91S3HsPAzPKLC9ZMEC+iQs2VkesOs0nFLZeMaMGAO5W6xiyQ5p94oo0bqa1XbmSV1bNp1HWuNEGIiZKrEUDxfYuDc6fC6hJZKsjJkMkBeadlQAlLcjIx1rDV171CKLLTxy/dT5kv4p9UrJlnleyMVG6S/3d6nX/WLSgZIMYbOwiZVVPlSrobuG38ULJMCSuxndxD0l+HahJaH8vYXuR67A0XT+bTEe305AI6A/9MEaRrActBnq6/OviQgBsKAvtTv1FmDbnpZsKeoFuwc3OPdTveQdCRA==",
}
testCases := []struct {
// Cert chain to embed in message
chain []string
// Intermediates & root certificate to verify against
intermediates []string
root string
// Should this test case verify?
success bool
}{
{certs, nil, trustedCA, true},
{certs, []string{intermediateCA}, trustedCA, true},
{certs[0:1], nil, intermediateCA, true},
{certs[0:1], nil, trustedCA, false},
{[]string{}, nil, trustedCA, false},
}
for i, testCase := range testCases {
signer, err := NewSigner(signerKey, &SignerOptions{
ExtraHeaders: map[HeaderKey]interface{}{HeaderKey("x5c"): testCase.chain},
})
if err != nil {
t.Fatal(err)
}
signed, err := signer.Sign([]byte("Lorem ipsum dolor sit amet"))
if err != nil {
t.Fatal(err)
}
parsed, err := ParseSigned(signed.FullSerialize())
if err != nil {
t.Fatal(err)
}
opts := x509.VerifyOptions{
DNSName: "TrustedSigner",
Roots: x509.NewCertPool(),
}
ok := opts.Roots.AppendCertsFromPEM([]byte(testCase.root))
if !ok {
t.Fatal("failed to parse trusted root certificate")
}
if len(testCase.intermediates) > 0 {
opts.Intermediates = x509.NewCertPool()
for _, intermediate := range testCase.intermediates {
ok := opts.Intermediates.AppendCertsFromPEM([]byte(intermediate))
if !ok {
t.Fatal("failed to parse trusted root certificate")
}
}
}
chains, err := parsed.Signatures[0].Protected.Certificates(opts)
if testCase.success && (len(chains) == 0 || err != nil) {
t.Fatalf("failed to verify certificate chain for test case %d: %s", i, err)
}
if !testCase.success && (len(chains) != 0 && err == nil) {
t.Fatalf("incorrectly verified certificate chain for test case %d (should fail)", i)
}
}
}

View file

@ -1,507 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jwt
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"io"
"reflect"
"sort"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/json"
)
type testClaims struct {
Subject string `json:"sub"`
}
type invalidMarshalClaims struct {
}
var errInvalidMarshalClaims = errors.New("Failed marshaling invalid claims.")
func (c invalidMarshalClaims) MarshalJSON() ([]byte, error) {
return nil, errInvalidMarshalClaims
}
var sampleClaims = Claims{
Subject: "42",
IssuedAt: NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
Issuer: "issuer",
Audience: Audience{"a1", "a2"},
}
type numberClaims struct {
Int int64 `json:"int"`
Float float64 `json:"float"`
}
func TestIntegerAndFloatsNormalize(t *testing.T) {
c := numberClaims{1 << 60, 12345.6789}
normalized, err := normalize(c)
if err != nil {
t.Fatal(err)
}
ni, err := (normalized["int"].(json.Number)).Int64()
nf, err := (normalized["float"].(json.Number)).Float64()
if ni != c.Int {
t.Error(fmt.Sprintf("normalize failed to preserve int64 (got %v, wanted %v, type %s)", normalized["int"], c.Int, reflect.TypeOf(normalized["int"])))
}
if nf != c.Float {
t.Error(fmt.Sprintf("normalize failed to preserve float64 (got %v, wanted %v, type %s)", normalized["float"], c.Float, reflect.TypeOf(normalized["float"])))
}
}
func TestBuilderCustomClaimsNonPointer(t *testing.T) {
jwt, err := Signed(rsaSigner).Claims(testClaims{"foo"}).CompactSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseSigned(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := &testClaims{}
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, out), "Error unmarshaling claims.") {
assert.Equal(t, "foo", out.Subject)
}
}
func TestBuilderCustomClaimsPointer(t *testing.T) {
jwt, err := Signed(rsaSigner).Claims(&testClaims{"foo"}).CompactSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseSigned(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := &testClaims{}
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, out), "Error unmarshaling claims.") {
assert.Equal(t, "foo", out.Subject)
}
}
func TestBuilderMergeClaims(t *testing.T) {
jwt, err := Signed(rsaSigner).
Claims(&Claims{
Subject: "42",
}).
Claims(map[string]interface{}{
"Scopes": []string{"read:users"},
}).
CompactSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseSigned(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := make(map[string]interface{})
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, &out), "Error unmarshaling claims.") {
assert.Equal(t, map[string]interface{}{
"sub": "42",
"Scopes": []interface{}{"read:users"},
}, out)
}
_, err = Signed(rsaSigner).Claims("invalid-claims").Claims(&testClaims{"foo"}).CompactSerialize()
assert.Equal(t, err, ErrInvalidClaims)
_, err = Signed(rsaSigner).Claims(&invalidMarshalClaims{}).CompactSerialize()
assert.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
}
func TestSignedFullSerializeAndToken(t *testing.T) {
b := Signed(rsaSigner).Claims(&testClaims{"foo"})
jwt, err := b.FullSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseSigned(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := &testClaims{}
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, &out), "Error unmarshaling claims.") {
assert.Equal(t, &testClaims{
Subject: "foo",
}, out)
}
jwt2, err := b.Token()
require.NoError(t, err, "Error creating JWT.")
out2 := &testClaims{}
if assert.NoError(t, jwt2.Claims(&testPrivRSAKey1.PublicKey, &out2), "Error unmarshaling claims.") {
assert.Equal(t, &testClaims{
Subject: "foo",
}, out2)
}
b2 := Signed(rsaSigner).Claims(&invalidMarshalClaims{})
_, err = b2.FullSerialize()
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
_, err = b2.Token()
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
}
func TestEncryptedFullSerializeAndToken(t *testing.T) {
recipient := jose.Recipient{
Algorithm: jose.RSA1_5,
Key: testPrivRSAKey1.Public(),
}
encrypter, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, nil)
require.NoError(t, err, "Error creating encrypter.")
b := Encrypted(encrypter).Claims(&testClaims{"foo"})
jwt, err := b.FullSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseEncrypted(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := &testClaims{}
if assert.NoError(t, parsed.Claims(testPrivRSAKey1, &out)) {
assert.Equal(t, &testClaims{
Subject: "foo",
}, out)
}
jwt2, err := b.Token()
require.NoError(t, err, "Error creating JWT.")
out2 := &testClaims{}
if assert.NoError(t, jwt2.Claims(testPrivRSAKey1, &out2)) {
assert.Equal(t, &testClaims{
Subject: "foo",
}, out2)
}
b2 := Encrypted(encrypter).Claims(&invalidMarshalClaims{})
_, err = b2.FullSerialize()
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
_, err = b2.Token()
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
}
func TestBuilderSignedAndEncrypted(t *testing.T) {
recipient := jose.Recipient{
Algorithm: jose.RSA1_5,
Key: testPrivRSAKey1.Public(),
}
encrypter, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, (&jose.EncrypterOptions{}).WithContentType("JWT").WithType("JWT"))
require.NoError(t, err, "Error creating encrypter.")
jwt1, err := SignedAndEncrypted(rsaSigner, encrypter).Claims(&testClaims{"foo"}).Token()
require.NoError(t, err, "Error marshaling signed-then-encrypted token.")
if nested, err := jwt1.Decrypt(testPrivRSAKey1); assert.NoError(t, err, "Error decrypting signed-then-encrypted token.") {
out := &testClaims{}
assert.NoError(t, nested.Claims(&testPrivRSAKey1.PublicKey, out))
assert.Equal(t, &testClaims{"foo"}, out)
}
b := SignedAndEncrypted(rsaSigner, encrypter).Claims(&testClaims{"foo"})
tok1, err := b.CompactSerialize()
if assert.NoError(t, err) {
jwt, err := ParseSignedAndEncrypted(tok1)
if assert.NoError(t, err, "Error parsing signed-then-encrypted compact token.") {
if nested, err := jwt.Decrypt(testPrivRSAKey1); assert.NoError(t, err) {
out := &testClaims{}
assert.NoError(t, nested.Claims(&testPrivRSAKey1.PublicKey, out))
assert.Equal(t, &testClaims{"foo"}, out)
}
}
}
tok2, err := b.FullSerialize()
if assert.NoError(t, err) {
jwe, err := ParseSignedAndEncrypted(tok2)
if assert.NoError(t, err, "Error parsing signed-then-encrypted full token.") {
assert.Equal(t, []jose.Header{{
Algorithm: string(jose.RSA1_5),
ExtraHeaders: map[jose.HeaderKey]interface{}{
jose.HeaderType: "JWT",
jose.HeaderContentType: "JWT",
"enc": "A128CBC-HS256",
},
}}, jwe.Headers)
if jws, err := jwe.Decrypt(testPrivRSAKey1); assert.NoError(t, err) {
assert.Equal(t, []jose.Header{{
Algorithm: string(jose.RS256),
ExtraHeaders: map[jose.HeaderKey]interface{}{
jose.HeaderType: "JWT",
},
}}, jws.Headers)
out := &testClaims{}
assert.NoError(t, jws.Claims(&testPrivRSAKey1.PublicKey, out))
assert.Equal(t, &testClaims{"foo"}, out)
}
}
}
b2 := SignedAndEncrypted(rsaSigner, encrypter).Claims(&invalidMarshalClaims{})
_, err = b2.CompactSerialize()
assert.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
_, err = b2.FullSerialize()
assert.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
encrypter2, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, nil)
require.NoError(t, err, "Error creating encrypter.")
_, err = SignedAndEncrypted(rsaSigner, encrypter2).CompactSerialize()
assert.EqualError(t, err, "square/go-jose/jwt: expected content type to be JWT (cty header)")
}
func TestBuilderHeadersSigner(t *testing.T) {
tests := []struct {
Keys []*rsa.PrivateKey
Claims interface{}
}{
{
Keys: []*rsa.PrivateKey{testPrivRSAKey1},
Claims: &Claims{Issuer: "foo"},
},
{
Keys: []*rsa.PrivateKey{testPrivRSAKey1, testPrivRSAKey2},
Claims: &Claims{Issuer: "foo"},
},
}
for i, tc := range tests {
wantKeyIDs := make([]string, len(tc.Keys))
signingKeys := make([]jose.SigningKey, len(tc.Keys))
for j, key := range tc.Keys {
keyIDBytes := make([]byte, 20)
if _, err := io.ReadFull(rand.Reader, keyIDBytes); err != nil {
t.Fatalf("failed to read random bytes: %v", err)
}
keyID := hex.EncodeToString(keyIDBytes)
wantKeyIDs[j] = keyID
signingKeys[j] = jose.SigningKey{
Algorithm: jose.RS256,
Key: &jose.JSONWebKey{
KeyID: keyID,
Algorithm: "RSA",
Key: key,
},
}
}
signer, err := jose.NewMultiSigner(signingKeys, nil)
if err != nil {
t.Errorf("case %d: NewMultiSigner(): %v", i, err)
continue
}
var token string
if len(tc.Keys) == 1 {
token, err = Signed(signer).Claims(tc.Claims).CompactSerialize()
} else {
token, err = Signed(signer).Claims(tc.Claims).FullSerialize()
}
if err != nil {
t.Errorf("case %d: failed to create token: %v", i, err)
continue
}
jws, err := jose.ParseSigned(token)
if err != nil {
t.Errorf("case %d: parse signed: %v", i, err)
continue
}
gotKeyIDs := make([]string, len(jws.Signatures))
for i, sig := range jws.Signatures {
gotKeyIDs[i] = sig.Header.KeyID
}
sort.Strings(wantKeyIDs)
sort.Strings(gotKeyIDs)
if !reflect.DeepEqual(wantKeyIDs, gotKeyIDs) {
t.Errorf("case %d: wanted=%q got=%q", i, wantKeyIDs, gotKeyIDs)
}
}
}
func TestBuilderHeadersEncrypter(t *testing.T) {
key := testPrivRSAKey1
claims := &Claims{Issuer: "foo"}
keyIDBytes := make([]byte, 20)
if _, err := io.ReadFull(rand.Reader, keyIDBytes); err != nil {
t.Fatalf("failed to read random bytes: %v", err)
}
keyID := hex.EncodeToString(keyIDBytes)
wantKeyID := keyID
recipient := jose.Recipient{
Algorithm: jose.RSA1_5,
Key: key.Public(),
KeyID: keyID,
}
wantType := jose.ContentType("JWT")
encrypter, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, (&jose.EncrypterOptions{}).WithType(wantType))
require.NoError(t, err, "failed to create encrypter")
token, err := Encrypted(encrypter).Claims(claims).CompactSerialize()
require.NoError(t, err, "failed to create token")
jwe, err := jose.ParseEncrypted(token)
if assert.NoError(t, err, "error parsing encrypted token") {
assert.Equal(t, jose.Header{
ExtraHeaders: map[jose.HeaderKey]interface{}{
jose.HeaderType: string(wantType),
"enc": "A128CBC-HS256",
},
Algorithm: string(jose.RSA1_5),
KeyID: wantKeyID,
}, jwe.Header)
}
}
func BenchmarkMapClaims(b *testing.B) {
m := map[string]interface{}{
"sub": "42",
"iat": 1451606400,
"iss": "issuer",
"aud": []string{"a1", "a2"},
}
for i := 0; i < b.N; i++ {
Signed(rsaSigner).Claims(m)
}
}
func BenchmarkStructClaims(b *testing.B) {
for i := 0; i < b.N; i++ {
Signed(rsaSigner).Claims(sampleClaims)
}
}
func BenchmarkSignedCompactSerializeRSA(b *testing.B) {
tb := Signed(rsaSigner).Claims(sampleClaims)
b.ResetTimer()
for i := 0; i < b.N; i++ {
tb.CompactSerialize()
}
}
func BenchmarkSignedCompactSerializeSHA(b *testing.B) {
tb := Signed(hmacSigner).Claims(sampleClaims)
b.ResetTimer()
for i := 0; i < b.N; i++ {
tb.CompactSerialize()
}
}
func mustUnmarshalRSA(data string) *rsa.PrivateKey {
block, _ := pem.Decode([]byte(data))
if block == nil {
panic("failed to decode PEM data")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
panic("failed to parse RSA key: " + err.Error())
}
if key, ok := key.(*rsa.PrivateKey); ok {
return key
}
panic("key is not of type *rsa.PrivateKey")
}
func mustMakeSigner(alg jose.SignatureAlgorithm, k interface{}) jose.Signer {
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: alg, Key: k}, (&jose.SignerOptions{}).WithType("JWT"))
if err != nil {
panic("failed to create signer:" + err.Error())
}
return sig
}
var (
sharedKey = []byte("secret")
sharedEncryptionKey = []byte("itsa16bytesecret")
testPrivRSAKey1 = mustUnmarshalRSA(`-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIHBvDHAr7jh8h
xaqBCl11fjI9YZtdC5b3HtXTXZW3c2dIOImNUjffT8POP6p5OpzivmC1om7iOyuZ
3nJjC9LT3zqqs3f2i5d4mImxEuqG6uWdryFfkp0uIv5VkjVO+iQWd6pDAPGP7r1Z
foXCleyCtmyNH4JSkJneNPOk/4BxO8vcvRnCMT/Gv81IT6H+OQ6OovWOuJr8RX9t
1wuCjC9ezZxeI9ONffhiO5FMrVh5H9LJTl3dPOVa4aEcOvgd45hBmvxAyXqf8daE
6Kl2O7vQ4uwgnSTVXYIIjCjbepuersApIMGx/XPSgiU1K3Xtah/TBvep+S3VlwPc
q/QH25S9AgMBAAECggEAe+y8XKYfPw4SxY1uPB+5JSwT3ON3nbWxtjSIYy9Pqp5z
Vcx9kuFZ7JevQSk4X38m7VzM8282kC/ono+d8yy9Uayq3k/qeOqV0X9Vti1qxEbw
ECkG1/MqGApfy4qSLOjINInDDV+mOWa2KJgsKgdCwuhKbVMYGB2ozG2qfYIlfvlY
vLcBEpGWmswJHNmkcjTtGFIyJgPbsI6ndkkOeQbqQKAaadXtG1xUzH+vIvqaUl/l
AkNf+p4qhPkHsoAWXf1qu9cYa2T8T+mEo79AwlgVC6awXQWNRTiyClDJC7cu6NBy
ZHXCLFMbalzWF9qeI2OPaFX2x3IBWrbyDxcJ4TSdQQKBgQD/Fp/uQonMBh1h4Vi4
HlxZdqSOArTitXValdLFGVJ23MngTGV/St4WH6eRp4ICfPyldsfcv6MZpNwNm1Rn
lB5Gtpqpby1dsrOSfvVbY7U3vpLnd8+hJ/lT5zCYt5Eor46N6iWRkYWzNe4PixiF
z1puGUvFCbZdeeACVrPLmW3JKQKBgQDI0y9WTf8ezKPbtap4UEE6yBf49ftohVGz
p4iD6Ng1uqePwKahwoVXKOc179CjGGtW/UUBORAoKRmxdHajHq6LJgsBxpaARz21
COPy99BUyp9ER5P8vYn63lC7Cpd/K7uyMjaz1DAzYBZIeVZHIw8O9wuGNJKjRFy9
SZyD3V0ddQKBgFMdohrWH2QVEfnUnT3Q1rJn0BJdm2bLTWOosbZ7G72TD0xAWEnz
sQ1wXv88n0YER6X6YADziEdQykq8s/HT91F/KkHO8e83zP8M0xFmGaQCOoelKEgQ
aFMIX3NDTM7+9OoUwwz9Z50PE3SJFAJ1n7eEEoYvNfabQXxBl+/dHEKRAoGAPEvU
EaiXacrtg8EWrssB2sFLGU/ZrTciIbuybFCT4gXp22pvXXAHEvVP/kzDqsRhLhwb
BNP6OuSkNziNikpjA5pngZ/7fgZly54gusmW/m5bxWdsUl0iOXVYbeAvPlqGH2me
LP4Pfs1hw17S/cbT9Z1NE31jbavP4HFikeD73SUCgYEArQfuudml6ei7XZ1Emjq8
jZiD+fX6e6BD/ISatVnuyZmGj9wPFsEhY2BpLiAMQHMDIvH9nlKzsFvjkTPB86qG
jCh3D67Os8eSBk5uRC6iW3Fc4DXvB5EFS0W9/15Sl+V5vXAcrNMpYS82OTSMG2Gt
b9Ym/nxaqyTu0PxajXkKm5Q=
-----END PRIVATE KEY-----`)
testPrivRSAKey2 = mustUnmarshalRSA(`-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxJ09jkXZ5Okyq
FrEKrs+GTzZRvoLziyzDTIZLJC6BVryau4gaFjuBG+pnm4z53oDP0XVnjFsx1mBw
R6RHeXlXbxLXsMfJpMzU9I2SRen9DokpD187CAnjLOoN9QRl1h8CA+sqR5Jw9mdl
mdaBKC99M9QYAPK3vGNfPC4soo8LDSBiemmt5raL4WSfoYh/6qg5rHUTymY28uxV
ew3I9Yp+3ltIw+WlRDtW5l+MM5CSUofjj2zcgcG3LEuPtvyZ+CSObxxcZZugm9zc
JdiazNyUxtX8yAj3Xg8Hde0jt0QDXv7A+U0KMVi9lX6PJEaNj4tOhOmQhJVMzAyr
1W/bifZVAgMBAAECggEAduKnn21GMZLTUi4KP94SvNK55F/Sp7hVoPbhBNpSL1BT
IBAMBV24LyvZwhAcqq8MiOrLPGNv6+EvNQqPD7xQl0GeRouHeCYVpDA+NdSfc8jm
eVysjwQVBpTkudsdSW5JvuN8VRJVD2P8/a0gy+p4/C/k/Prd6DoQAiBz6FZrYoEd
iYgIegHOMXWd4vzO3ENOWSIUI6ci7Aro+Y0Z75kfiVokAGhUcFgrZ58E82fBYh8I
cxO20oMnucGrLicQzj536jx4wX3Cdd4jr9UVEJ9ZII1ldlp03nZlFLXqJH1547Aq
ZM+3vVcBGoJ8T9ZQ4VDAL++0K2DLC9JkTARAYCEi/QKBgQDebIc1+2zblhQtVQ/e
IbEErZcB7v+TkUoRoBfR0lj7bKBFJgRe37fgu1xf95/s63okdnOw/OuQqtGmgx/J
TL3yULBdNcwTCRm41t+cqoGymjK0VRbqk6CWBId0E3r5TaCVWedk2JI2XwTvIJ1A
eDiqfJeDHUD44yaonwbysj9ZDwKBgQDL5VQfTppVaJk2PXNwhAkRQklZ8RFmt/7p
yA3dddQNdwMk4Fl8F7QuO1gBxDiHdnwIrlEOz6fTsM3LwIS+Q12P1vYFIhpo7HDB
wvjfMwCPxBIS4jI28RgcAf0VbZ/+CHAm6bb9iDwsjXhh1J5oOm5VKnju6/rPH/QY
+md40pnSWwKBgBnKPbdNquafNUG4XjmkcHEZa6wGuU20CAGZLYnfuP+WLdM2wET7
7cc6ElDyVnHTL/twXKPF/85rcBm9lH7zzgZ9wqVcKoh+gqQDDjSNNLKv3Hc6cojK
i1E5vzb/Vz/290q5/PGdhv6U7+6GOpWSGwfxoGPMjY8OT5o3rkeP0XaTAoGBALLR
GQmr4eZtqZDMK+XNpjYgsDvVE7HGRCW7cY17vNFiQruglloiX778BJ7n+7uxye3D
EwuuSj15ncLHwKMsaW2w1GqEEi1azzjfSWxWSnPLPR6aifdtUfueMtsMHXio5dL6
vaV0SXG5UI5b7eDy/bhrW0wOYRQtreIKGZz49jZpAoGBAIvxYngkLwmq6g6MmnAc
YK4oT6YAm2wfSy2mzpEQP5r1igp1rN7T46o7FMUPDLS9wK3ESAaIYe01qT6Yftcc
5qF+yiOGDTr9XQiHwe4BcyrNEMfUjDhDU5ao2gH8+t1VGr1KspLsUNbedrJwZsY4
UCZVKEEDHzKfLO/iBgKjJQF7
-----END PRIVATE KEY-----`)
rsaSigner = mustMakeSigner(jose.RS256, testPrivRSAKey1)
hmacSigner = mustMakeSigner(jose.HS256, sharedKey)
)

View file

@ -1,80 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jwt
import (
"testing"
"time"
"gopkg.in/square/go-jose.v2/json"
"github.com/stretchr/testify/assert"
)
func TestEncodeClaims(t *testing.T) {
now := time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)
c := Claims{
Issuer: "issuer",
Subject: "subject",
Audience: Audience{"a1", "a2"},
NotBefore: NewNumericDate(time.Time{}),
IssuedAt: NewNumericDate(now),
Expiry: NewNumericDate(now.Add(1 * time.Hour)),
}
b, err := json.Marshal(c)
assert.NoError(t, err)
expected := `{"iss":"issuer","sub":"subject","aud":["a1","a2"],"exp":1451610000,"iat":1451606400}`
assert.Equal(t, expected, string(b))
}
func TestDecodeClaims(t *testing.T) {
s := []byte(`{"iss":"issuer","sub":"subject","aud":["a1","a2"],"exp":1451610000,"iat":1451606400}`)
now := time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)
c := Claims{}
if err := json.Unmarshal(s, &c); assert.NoError(t, err) {
assert.Equal(t, "issuer", c.Issuer)
assert.Equal(t, "subject", c.Subject)
assert.Equal(t, Audience{"a1", "a2"}, c.Audience)
assert.True(t, now.Equal(c.IssuedAt.Time()))
assert.True(t, now.Add(1*time.Hour).Equal(c.Expiry.Time()))
}
s2 := []byte(`{"aud": "a1"}`)
c2 := Claims{}
if err := json.Unmarshal(s2, &c2); assert.NoError(t, err) {
assert.Equal(t, Audience{"a1"}, c2.Audience)
}
invalid := []struct {
Raw string
Err error
}{
{`{"aud": 5}`, ErrUnmarshalAudience},
{`{"aud": ["foo", 5, "bar"]}`, ErrUnmarshalAudience},
{`{"exp": "invalid"}`, ErrUnmarshalNumericDate},
}
for _, v := range invalid {
c := Claims{}
assert.Equal(t, v.Err, json.Unmarshal([]byte(v.Raw), &c))
}
}

View file

@ -1,340 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jwt_test
import (
"fmt"
"strings"
"time"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
)
var sharedKey = []byte("secret")
var sharedEncryptionKey = []byte("itsa16bytesecret")
var signer, _ = jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: sharedKey}, &jose.SignerOptions{})
func ExampleParseSigned() {
raw := `eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzdWIiOiJzdWJqZWN0In0.gpHyA1B1H6X4a4Edm9wo7D3X2v3aLSDBDG2_5BzXYe0`
tok, err := jwt.ParseSigned(raw)
if err != nil {
panic(err)
}
out := jwt.Claims{}
if err := tok.Claims(sharedKey, &out); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)
// Output: iss: issuer, sub: subject
}
func ExampleParseEncrypted() {
key := []byte("itsa16bytesecret")
raw := `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..jg45D9nmr6-8awml.z-zglLlEw9MVkYHi-Znd9bSwc-oRGbqKzf9WjXqZxno.kqji2DiZHZmh-1bLF6ARPw`
tok, err := jwt.ParseEncrypted(raw)
if err != nil {
panic(err)
}
out := jwt.Claims{}
if err := tok.Claims(key, &out); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)
// Output: iss: issuer, sub: subject
}
func ExampleParseSignedAndEncrypted() {
raw := `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIiwiY3R5IjoiSldUIn0..-keV-9YpsxotBEHw.yC9SHWgnkjykgJqXZGlzYC5Wg_EdWKO5TgfqeqsWWJYw7fX9zXQE3NtXmA3nAiUrYOr3H2s0AgTeAhTNbELLEHQu0blfRaPa_uKOAgFgmhJwbGe2iFLn9J0U72wk56318nI-pTLCV8FijoGpXvAxQlaKrPLKkl9yDQimPhb7UiDwLWYkJeoayciAXhR5f40E8ORGjCz8oawXRvjDaSjgRElUwy4kMGzvJy_difemEh4lfMSIwUNVEqJkEYaalRttSymMYuV6NvBVU0N0Jb6omdM4tW961OySB4KPWCWH9UJUX0XSEcqbW9WLxpg3ftx5R7xNiCnaVaCx_gJZfXJ9yFLqztIrKh2N05zHM0tddSOwCOnq7_1rJtaVz0nTXjSjf1RrVaxJya59p3K-e41QutiGFiJGzXG-L2OyLETIaVSU3ptvaCz4IxCF3GzeCvOgaICvXkpBY1-bv-fk1ilyjmcTDnLp2KivWIxcnoQmpN9xj06ZjagdG09AHUhS5WixADAg8mIdGcanNblALecnCWG-otjM9Kw.RZoaHtSgnzOin2od3D9tnA`
tok, err := jwt.ParseSignedAndEncrypted(raw)
if err != nil {
panic(err)
}
nested, err := tok.Decrypt(sharedEncryptionKey)
if err != nil {
panic(err)
}
out := jwt.Claims{}
if err := nested.Claims(&rsaPrivKey.PublicKey, &out); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)
// Output: iss: issuer, sub: subject
}
func ExampleClaims_Validate() {
cl := jwt.Claims{
Subject: "subject",
Issuer: "issuer",
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
Expiry: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 15, 0, 0, time.UTC)),
Audience: jwt.Audience{"leela", "fry"},
}
err := cl.Validate(jwt.Expected{
Issuer: "issuer",
Time: time.Date(2016, 1, 1, 0, 10, 0, 0, time.UTC),
})
if err != nil {
panic(err)
}
fmt.Printf("valid!")
// Output: valid!
}
func ExampleClaims_Validate_withParse() {
raw := `eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzdWIiOiJzdWJqZWN0In0.gpHyA1B1H6X4a4Edm9wo7D3X2v3aLSDBDG2_5BzXYe0`
tok, err := jwt.ParseSigned(raw)
if err != nil {
panic(err)
}
cl := jwt.Claims{}
if err := tok.Claims(sharedKey, &cl); err != nil {
panic(err)
}
err = cl.Validate(jwt.Expected{
Issuer: "issuer",
Subject: "subject",
})
if err != nil {
panic(err)
}
fmt.Printf("valid!")
// Output: valid!
}
func ExampleSigned() {
key := []byte("secret")
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: key}, (&jose.SignerOptions{}).WithType("JWT"))
if err != nil {
panic(err)
}
cl := jwt.Claims{
Subject: "subject",
Issuer: "issuer",
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
Audience: jwt.Audience{"leela", "fry"},
}
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
if err != nil {
panic(err)
}
fmt.Println(raw)
// Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibGVlbGEiLCJmcnkiXSwiaXNzIjoiaXNzdWVyIiwibmJmIjoxNDUxNjA2NDAwLCJzdWIiOiJzdWJqZWN0In0.4PgCj0VO-uG_cb1mNA38NjJyp0N-NdGIDLoYelEkciw
}
func ExampleSigned_privateClaims() {
key := []byte("secret")
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: key}, (&jose.SignerOptions{}).WithType("JWT"))
if err != nil {
panic(err)
}
cl := jwt.Claims{
Subject: "subject",
Issuer: "issuer",
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
Audience: jwt.Audience{"leela", "fry"},
}
// When setting private claims, make sure to add struct tags
// to specify how to serialize the field. The naming behavior
// should match the encoding/json package otherwise.
privateCl := struct {
CustomClaim string `json:"custom"`
}{
"custom claim value",
}
raw, err := jwt.Signed(sig).Claims(cl).Claims(privateCl).CompactSerialize()
if err != nil {
panic(err)
}
fmt.Println(raw)
// Ouput: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibGVlbGEiLCJmcnkiXSwiY3VzdG9tIjoiY3VzdG9tIGNsYWltIHZhbHVlIiwiaXNzIjoiaXNzdWVyIiwibmJmIjoxNDUxNjA2NDAwLCJzdWIiOiJzdWJqZWN0In0.knXH3ReNJToS5XI7BMCkk80ugpCup3tOy53xq-ga47o
}
func ExampleEncrypted() {
enc, err := jose.NewEncrypter(
jose.A128GCM,
jose.Recipient{Algorithm: jose.DIRECT, Key: sharedEncryptionKey},
(&jose.EncrypterOptions{}).WithType("JWT"),
)
if err != nil {
panic(err)
}
cl := jwt.Claims{
Subject: "subject",
Issuer: "issuer",
}
raw, err := jwt.Encrypted(enc).Claims(cl).CompactSerialize()
if err != nil {
panic(err)
}
fmt.Println(raw)
}
func ExampleSignedAndEncrypted() {
enc, err := jose.NewEncrypter(
jose.A128GCM,
jose.Recipient{
Algorithm: jose.DIRECT,
Key: sharedEncryptionKey,
},
(&jose.EncrypterOptions{}).WithType("JWT").WithContentType("JWT"))
if err != nil {
panic(err)
}
cl := jwt.Claims{
Subject: "subject",
Issuer: "issuer",
}
raw, err := jwt.SignedAndEncrypted(rsaSigner, enc).Claims(cl).CompactSerialize()
if err != nil {
panic(err)
}
fmt.Println(raw)
}
func ExampleSigned_multipleClaims() {
c := &jwt.Claims{
Subject: "subject",
Issuer: "issuer",
}
c2 := struct {
Scopes []string
}{
[]string{"foo", "bar"},
}
raw, err := jwt.Signed(signer).Claims(c).Claims(c2).CompactSerialize()
if err != nil {
panic(err)
}
fmt.Println(raw)
// Output: eyJhbGciOiJIUzI1NiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sImlzcyI6Imlzc3VlciIsInN1YiI6InN1YmplY3QifQ.esKOIsmwkudr_gnfnB4SngxIr-7pspd5XzG3PImfQ6Y
}
func ExampleJSONWebToken_Claims_map() {
raw := `eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzdWIiOiJzdWJqZWN0In0.gpHyA1B1H6X4a4Edm9wo7D3X2v3aLSDBDG2_5BzXYe0`
tok, err := jwt.ParseSigned(raw)
if err != nil {
panic(err)
}
out := make(map[string]interface{})
if err := tok.Claims(sharedKey, &out); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out["iss"], out["sub"])
// Output: iss: issuer, sub: subject
}
func ExampleJSONWebToken_Claims_multiple() {
raw := `eyJhbGciOiJIUzI1NiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sImlzcyI6Imlzc3VlciIsInN1YiI6InN1YmplY3QifQ.esKOIsmwkudr_gnfnB4SngxIr-7pspd5XzG3PImfQ6Y`
tok, err := jwt.ParseSigned(raw)
if err != nil {
panic(err)
}
out := jwt.Claims{}
out2 := struct {
Scopes []string
}{}
if err := tok.Claims(sharedKey, &out, &out2); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s, scopes: %s\n", out.Issuer, out.Subject, strings.Join(out2.Scopes, ","))
// Output: iss: issuer, sub: subject, scopes: foo,bar
}
func mustUnmarshalRSA(data string) *rsa.PrivateKey {
block, _ := pem.Decode([]byte(data))
if block == nil {
panic("failed to decode PEM data")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
panic("failed to parse RSA key: " + err.Error())
}
if key, ok := key.(*rsa.PrivateKey); ok {
return key
}
panic("key is not of type *rsa.PrivateKey")
}
func mustMakeSigner(alg jose.SignatureAlgorithm, k interface{}) jose.Signer {
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: alg, Key: k}, nil)
if err != nil {
panic("failed to create signer:" + err.Error())
}
return sig
}
var rsaPrivKey = mustUnmarshalRSA(`-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIHBvDHAr7jh8h
xaqBCl11fjI9YZtdC5b3HtXTXZW3c2dIOImNUjffT8POP6p5OpzivmC1om7iOyuZ
3nJjC9LT3zqqs3f2i5d4mImxEuqG6uWdryFfkp0uIv5VkjVO+iQWd6pDAPGP7r1Z
foXCleyCtmyNH4JSkJneNPOk/4BxO8vcvRnCMT/Gv81IT6H+OQ6OovWOuJr8RX9t
1wuCjC9ezZxeI9ONffhiO5FMrVh5H9LJTl3dPOVa4aEcOvgd45hBmvxAyXqf8daE
6Kl2O7vQ4uwgnSTVXYIIjCjbepuersApIMGx/XPSgiU1K3Xtah/TBvep+S3VlwPc
q/QH25S9AgMBAAECggEAe+y8XKYfPw4SxY1uPB+5JSwT3ON3nbWxtjSIYy9Pqp5z
Vcx9kuFZ7JevQSk4X38m7VzM8282kC/ono+d8yy9Uayq3k/qeOqV0X9Vti1qxEbw
ECkG1/MqGApfy4qSLOjINInDDV+mOWa2KJgsKgdCwuhKbVMYGB2ozG2qfYIlfvlY
vLcBEpGWmswJHNmkcjTtGFIyJgPbsI6ndkkOeQbqQKAaadXtG1xUzH+vIvqaUl/l
AkNf+p4qhPkHsoAWXf1qu9cYa2T8T+mEo79AwlgVC6awXQWNRTiyClDJC7cu6NBy
ZHXCLFMbalzWF9qeI2OPaFX2x3IBWrbyDxcJ4TSdQQKBgQD/Fp/uQonMBh1h4Vi4
HlxZdqSOArTitXValdLFGVJ23MngTGV/St4WH6eRp4ICfPyldsfcv6MZpNwNm1Rn
lB5Gtpqpby1dsrOSfvVbY7U3vpLnd8+hJ/lT5zCYt5Eor46N6iWRkYWzNe4PixiF
z1puGUvFCbZdeeACVrPLmW3JKQKBgQDI0y9WTf8ezKPbtap4UEE6yBf49ftohVGz
p4iD6Ng1uqePwKahwoVXKOc179CjGGtW/UUBORAoKRmxdHajHq6LJgsBxpaARz21
COPy99BUyp9ER5P8vYn63lC7Cpd/K7uyMjaz1DAzYBZIeVZHIw8O9wuGNJKjRFy9
SZyD3V0ddQKBgFMdohrWH2QVEfnUnT3Q1rJn0BJdm2bLTWOosbZ7G72TD0xAWEnz
sQ1wXv88n0YER6X6YADziEdQykq8s/HT91F/KkHO8e83zP8M0xFmGaQCOoelKEgQ
aFMIX3NDTM7+9OoUwwz9Z50PE3SJFAJ1n7eEEoYvNfabQXxBl+/dHEKRAoGAPEvU
EaiXacrtg8EWrssB2sFLGU/ZrTciIbuybFCT4gXp22pvXXAHEvVP/kzDqsRhLhwb
BNP6OuSkNziNikpjA5pngZ/7fgZly54gusmW/m5bxWdsUl0iOXVYbeAvPlqGH2me
LP4Pfs1hw17S/cbT9Z1NE31jbavP4HFikeD73SUCgYEArQfuudml6ei7XZ1Emjq8
jZiD+fX6e6BD/ISatVnuyZmGj9wPFsEhY2BpLiAMQHMDIvH9nlKzsFvjkTPB86qG
jCh3D67Os8eSBk5uRC6iW3Fc4DXvB5EFS0W9/15Sl+V5vXAcrNMpYS82OTSMG2Gt
b9Ym/nxaqyTu0PxajXkKm5Q=
-----END PRIVATE KEY-----`)
var rsaSigner = mustMakeSigner(jose.RS256, rsaPrivKey)

View file

@ -1,137 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jwt
import (
"testing"
"github.com/stretchr/testify/assert"
)
var (
hmacSignedToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwic2NvcGVzIjpbInMxIiwiczIiXX0.Y6_PfQHrzRJ_Vlxij5VI07-pgDIuJNN3Z_g5sSaGQ0c`
rsaSignedToken = `eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzY29wZXMiOlsiczEiLCJzMiJdLCJzdWIiOiJzdWJqZWN0In0.UDDtyK9gC9kyHltcP7E_XODsnqcJWZIiXeGmSAH7SE9YKy3N0KSfFIN85dCNjTfs6zvy4rkrCHzLB7uKAtzMearh3q7jL4nxbhUMhlUcs_9QDVoN4q_j58XmRqBqRnBk-RmDu9TgcV8RbErP4awpIhwWb5UU-hR__4_iNbHdKqwSUPDKYGlf5eicuiYrPxH8mxivk4LRD-vyRdBZZKBt0XIDnEU4TdcNCzAXojkftqcFWYsczwS8R4JHd1qYsMyiaWl4trdHZkO4QkeLe34z4ZAaPMt3wE-gcU-VoqYTGxz-K3Le2VaZ0r3j_z6bOInsv0yngC_cD1dCXMyQJWnWjQ`
invalidPayloadSignedToken = `eyJhbGciOiJIUzI1NiJ9.aW52YWxpZC1wYXlsb2Fk.ScBKKm18jcaMLGYDNRUqB5gVMRZl4DM6dh3ShcxeNgY`
invalidPartsSignedToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwic2NvcGVzIjpbInMxIiwiczIiXX0`
hmacEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..NZrU98U4QNO0y-u6.HSq5CvlmkUT1BPqLGZ4.1-zuiZ4RbHrTTUoA8Dvfhg`
rsaEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.IvkVHHiI8JwwavvTR80xGjYvkzubMrZ-TDDx8k8SNJMEylfFfNUc7F2rC3WAABF_xmJ3SW2A6on-S6EAG97k0RsjqHHNqZuaFpDvjeuLqZFfYKzI45aCtkGG4C2ij2GbeySqJ784CcvFJPUWJ-6VPN2Ho2nhefUSqig0jE2IvOKy1ywTj_VBVBxF_dyXFnXwxPKGUQr3apxrWeRJfDh2Cf8YPBlLiRznjfBfwgePB1jP7WCZNwItj10L7hsT_YWEx01XJcbxHaXFLwKyVzwWaDhreFyaWMRbGqEfqVuOT34zfmhLDhQlgLLwkXrvYqX90NsQ9Ftg0LLIfRMbsfdgug.BFy2Tj1RZN8yq2Lk-kMiZQ.9Z0eOyPiv5cEzmXh64RlAQ36Uvz0WpZgqRcc2_69zHTmUOv0Vnl1I6ks8sTraUEvukAilolNBjBj47s0b4b-Og.VM8-eJg5ZsqnTqs0LtGX_Q`
invalidPayloadEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..T4jCS4Yyw1GCH0aW.y4gFaMITdBs_QZM8RKrL.6MPyk1cMVaOJFoNGlEuaRQ`
invalidPartsEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..NZrU98U4QNO0y-u6.HSq5CvlmkUT1BPqLGZ4`
signedAndEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiY3R5IjoiSldUIn0.icnR7M1HSgMDaUnJhfzT5nLmT0eRPeNsKPkioNcyq9TZsm-LgbE7wZkNFGfQqYwvbmrZ3UpOhNkrq4n2KN3N1dtjH9TVxzfMxz2OMh0dRWUNMi58EMadhmIpH3PLyyaeDyd0dyHpOIRPFTAoOdn2GoO_flV5CvPMhgdVKYB3h3vQW-ZZDu4cOZwXAjTuThdoUZCNWFhJhXyj-PrKLyVpX6rE1o4X05IS8008SLZyx-PZlsUPyLs6CJi7Z4PzZRzOJTV00a-7UOi-fBKBZV5V8eRpWuzJ673pMALlRCBzrRin-JeEA_QnAejtMAHG7RSGP60easQN4I-0jLTQNNNynw.oFrO-5ZgRrnWmbkPsbyMiQ.BVaWUzlrdfhe0otPJpb3DGoDCT6-BOmN_Pgq5NOqVFYIAwG5pM4pf7TaiPUJeQLf0phbLgpT4RfJ20Zhwfc2MH5unCqc8TZEP2dOrYRhb8o-X57x6IQppIDbjK2i_CAWf3yF5JUB7qRqOizpKZTh3HFTVEglY3WF8tAJ8KpnatTUmwcnqlyjdBFvYu4usiyvc_u9wNbXx5-lFt0slQYleHQMUirBprKyswIBjMoFJEe7kDvU_MCKI4NI9_fSfWJpaUdNxQEvRYR1PV4ZQdwBY0X9u2n2QH5iVQMrmgmQ5hPbWxwRv1-7jXBMPBpGeFQZHeEtSwif1_Umwyt8cDyRChb3OM7XQ3eY0UJRrbmvhcLWIcMp8FpblDaBinbjD6qIVXZVmaAdIbi2a_HblfoeL3-UABb82AAxOqQcAFjDEDTR2TFalDXSwgPZrAaQ_Mql3eFe9r2y0UVkgG7XYF4ik8sSK48CkZPUvkZFr-K9QMq-RZLzT3Zw0edxNaKgje27S26H9qClh6CCr9nk38AZZ76_Xz7f-Fil5xI0Dq95UzvwW__U3JJWE6OVUVx_RVJgdOJn8_B7hluckwBLUblscA.83pPXNnH0sKgHvFboiJVDA`
invalidSignedAndEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.QKYu3DkFEXBUa2U0Sgtm-e44BMuaFVbMu2T-GB3qEGONrmOuaB5BtNCvBUnuj6HR0v6u-tvawToRSzExQQLFTvPcLiQR8iclWirqAFUqLrg8kRU3qIRLkmErYeGIfCML1jq9ofKg0DI5-YrU5RSyUg9cwfXKEx8KNwFcjeVeDZwWEACdU8xBnQp57rNfr0Tj-dPnGKID7LU5ZV0vhK90FpEG7UqOeSHFmvONQyz6Ca-ZkE8X2swqGad-q5xl8f9pApdFqHzADox5OlgtxPkr-Khkm6WGfvf1K_e-iW5LYtvWIAjNByft2TexsNcYpdAO2oNAgh2nkhoohl-zCWU-og.UAU65JWKqvHZ_Z0V-xLyjQ.M6sQ4lAzKFelSmL6C6uoK00rB8IFCAK-eJ0iByGhtg8eYtmSBFsP_oUySfKPtxcPRkQ7YxnEX5D-DOo20wCV7il2Be9No__0R6_5heISOMXcKmKP3D6pFusaPisNGOgLw8SKXBuVpe20PvOJ9RgOXRKucSR2UMINXtqIn9RdxbKOlBBmMJhnX4TeQ00fRILng2sMbUHsWExSthQODHGx6VcwLFp-Aqmsnv2q2KkLpA8sEm48AHHFQXSGtlVGVgWKi3dOQYUnDJW4P64Xxr1Uq3yT7w_dRwK4BA7l3Biecj5dwkKrFMJ_RaCt-ED_R15zpxg6PmnXeeJnif58Fai40ZWOsGvLZNYwL1jbi-TrsargpdUQedfzuTk8Na2NkCzFNg2BYXVDHJ_WAX1daVyhvunaURwAlBatAcmnOGxWebwV1xQoQ7iHg6ZGohCannn_pqGwJlMHMgnCcnCIhwfj9uL9Ejz_TVceZNMlT1KvLRafVfxGhkp48bdnd8OcXmjT9pQzZUB3OqrstWKhbItZ1xMpy6dZ54ldWvtTTyQ4tQJaVWgXERUM1erDT6Ypyl15-fumOB9MRcgMG3NDblKowA.P9WTBITvVUgrLjX6bS0opQ`
)
type customClaims struct {
Scopes []string `json:"scopes,omitempty"`
}
func TestDecodeToken(t *testing.T) {
tok, err := ParseSigned(hmacSignedToken)
if assert.NoError(t, err, "Error parsing signed token.") {
c := &Claims{}
c2 := &customClaims{}
if assert.NoError(t, tok.Claims(sharedKey, c, c2)) {
assert.Equal(t, "subject", c.Subject)
assert.Equal(t, "issuer", c.Issuer)
assert.Equal(t, []string{"s1", "s2"}, c2.Scopes)
}
}
assert.EqualError(t, tok.Claims([]byte("invalid-secret")), "square/go-jose: error in cryptographic primitive")
tok2, err := ParseSigned(rsaSignedToken)
if assert.NoError(t, err, "Error parsing encrypted token.") {
c := make(map[string]interface{})
if assert.NoError(t, tok2.Claims(&testPrivRSAKey1.PublicKey, &c)) {
assert.Equal(t, map[string]interface{}{
"sub": "subject",
"iss": "issuer",
"scopes": []interface{}{"s1", "s2"},
}, c)
}
}
assert.EqualError(t, tok.Claims(&testPrivRSAKey2.PublicKey), "square/go-jose: error in cryptographic primitive")
tok3, err := ParseSigned(invalidPayloadSignedToken)
if assert.NoError(t, err, "Error parsing signed token.") {
assert.Error(t, tok3.Claims(sharedKey, &Claims{}), "Expected unmarshaling claims to fail.")
}
_, err = ParseSigned(invalidPartsSignedToken)
assert.EqualError(t, err, "square/go-jose: compact JWS format must have three parts")
tok4, err := ParseEncrypted(hmacEncryptedToken)
if assert.NoError(t, err, "Error parsing encrypted token.") {
c := Claims{}
if assert.NoError(t, tok4.Claims(sharedEncryptionKey, &c)) {
assert.Equal(t, "foo", c.Subject)
}
}
assert.EqualError(t, tok4.Claims([]byte("invalid-secret-key")), "square/go-jose: error in cryptographic primitive")
tok5, err := ParseEncrypted(rsaEncryptedToken)
if assert.NoError(t, err, "Error parsing encrypted token.") {
c := make(map[string]interface{})
if assert.NoError(t, tok5.Claims(testPrivRSAKey1, &c)) {
assert.Equal(t, map[string]interface{}{
"sub": "subject",
"iss": "issuer",
"scopes": []interface{}{"s1", "s2"},
}, c)
}
}
assert.EqualError(t, tok5.Claims(testPrivRSAKey2), "square/go-jose: error in cryptographic primitive")
tok6, err := ParseEncrypted(invalidPayloadEncryptedToken)
if assert.NoError(t, err, "Error parsing encrypted token.") {
assert.Error(t, tok6.Claims(sharedEncryptionKey, &Claims{}))
}
_, err = ParseEncrypted(invalidPartsEncryptedToken)
assert.EqualError(t, err, "square/go-jose: compact JWE format must have five parts")
tok7, err := ParseSignedAndEncrypted(signedAndEncryptedToken)
if assert.NoError(t, err, "Error parsing signed-then-encrypted token.") {
c := make(map[string]interface{})
if nested, err := tok7.Decrypt(testPrivRSAKey1); assert.NoError(t, err) {
assert.NoError(t, nested.Claims(testPrivRSAKey1.Public(), &c))
assert.Equal(t, map[string]interface{}{
"sub": "subject",
"iss": "issuer",
"scopes": []interface{}{"s1", "s2"},
}, c)
assert.EqualError(t, nested.Claims(testPrivRSAKey2.Public()), "square/go-jose: error in cryptographic primitive")
}
}
_, err = tok7.Decrypt(testPrivRSAKey2)
assert.EqualError(t, err, "square/go-jose: error in cryptographic primitive")
_, err = ParseSignedAndEncrypted(invalidSignedAndEncryptedToken)
assert.EqualError(t, err, "square/go-jose/jwt: expected content type to be JWT (cty header)")
}
func BenchmarkDecodeSignedToken(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseSigned(hmacSignedToken)
}
}
func BenchmarkDecodeEncryptedHMACToken(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseEncrypted(hmacEncryptedToken)
}
}

View file

@ -1,92 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jwt
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestFieldsMatch(t *testing.T) {
c := Claims{
Issuer: "issuer",
Subject: "subject",
Audience: []string{"a1", "a2"},
ID: "42",
}
valid := []Expected{
{Issuer: "issuer"},
{Subject: "subject"},
{Audience: Audience{"a1", "a2"}},
{Audience: Audience{"a2", "a1"}},
{ID: "42"},
}
for _, v := range valid {
assert.NoError(t, c.Validate(v))
}
invalid := []struct {
Expected Expected
Error error
}{
{Expected{Issuer: "invalid-issuer"}, ErrInvalidIssuer},
{Expected{Subject: "invalid-subject"}, ErrInvalidSubject},
{Expected{Audience: Audience{"invalid-audience"}}, ErrInvalidAudience},
{Expected{ID: "invalid-id"}, ErrInvalidID},
}
for _, v := range invalid {
assert.Equal(t, v.Error, c.Validate(v.Expected))
}
}
func TestExpiryAndNotBefore(t *testing.T) {
now := time.Date(2016, 1, 1, 12, 0, 0, 0, time.UTC)
twelveHoursAgo := now.Add(-12 * time.Hour)
c := Claims{
IssuedAt: NewNumericDate(twelveHoursAgo),
NotBefore: NewNumericDate(twelveHoursAgo),
Expiry: NewNumericDate(now),
}
// expired - default leeway (1 minute)
assert.NoError(t, c.Validate(Expected{Time: now}))
err := c.Validate(Expected{Time: now.Add(2 * DefaultLeeway)})
if assert.Error(t, err) {
assert.Equal(t, err, ErrExpired)
}
// expired - no leeway
assert.NoError(t, c.ValidateWithLeeway(Expected{Time: now}, 0))
err = c.ValidateWithLeeway(Expected{Time: now.Add(1 * time.Second)}, 0)
if assert.Error(t, err) {
assert.Equal(t, err, ErrExpired)
}
// not before - default leeway (1 minute)
assert.NoError(t, c.Validate(Expected{Time: twelveHoursAgo}))
err = c.Validate(Expected{Time: twelveHoursAgo.Add(-2 * DefaultLeeway)})
if assert.Error(t, err) {
assert.Equal(t, err, ErrNotValidYet)
}
}

View file

@ -1,523 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jose
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"fmt"
"io"
"reflect"
"testing"
"gopkg.in/square/go-jose.v2/json"
)
type staticNonceSource string
func (sns staticNonceSource) Nonce() (string, error) {
return string(sns), nil
}
func RoundtripJWS(sigAlg SignatureAlgorithm, serializer func(*JSONWebSignature) (string, error), corrupter func(*JSONWebSignature), signingKey interface{}, verificationKey interface{}, nonce string) error {
opts := &SignerOptions{}
if nonce != "" {
opts.NonceSource = staticNonceSource(nonce)
}
signer, err := NewSigner(SigningKey{Algorithm: sigAlg, Key: signingKey}, opts)
if err != nil {
return fmt.Errorf("error on new signer: %s", err)
}
input := []byte("Lorem ipsum dolor sit amet")
obj, err := signer.Sign(input)
if err != nil {
return fmt.Errorf("error on sign: %s", err)
}
msg, err := serializer(obj)
if err != nil {
return fmt.Errorf("error on serialize: %s", err)
}
obj, err = ParseSigned(msg)
if err != nil {
return fmt.Errorf("error on parse: %s", err)
}
// (Maybe) mangle the object
corrupter(obj)
output, err := obj.Verify(verificationKey)
if err != nil {
return fmt.Errorf("error on verify: %s", err)
}
// Check that verify works with embedded keys (if present)
for i, sig := range obj.Signatures {
if sig.Header.JSONWebKey != nil {
_, err = obj.Verify(sig.Header.JSONWebKey)
if err != nil {
return fmt.Errorf("error on verify with embedded key %d: %s", i, err)
}
}
// Check that the nonce correctly round-tripped (if present)
if sig.Header.Nonce != nonce {
return fmt.Errorf("Incorrect nonce returned: [%s]", sig.Header.Nonce)
}
}
if bytes.Compare(output, input) != 0 {
return fmt.Errorf("input/output do not match, got '%s', expected '%s'", output, input)
}
return nil
}
func TestRoundtripsJWS(t *testing.T) {
// Test matrix
sigAlgs := []SignatureAlgorithm{RS256, RS384, RS512, PS256, PS384, PS512, HS256, HS384, HS512, ES256, ES384, ES512, EdDSA}
serializers := []func(*JSONWebSignature) (string, error){
func(obj *JSONWebSignature) (string, error) { return obj.CompactSerialize() },
func(obj *JSONWebSignature) (string, error) { return obj.FullSerialize(), nil },
}
corrupter := func(obj *JSONWebSignature) {}
for _, alg := range sigAlgs {
signingKey, verificationKey := GenerateSigningTestKey(alg)
for i, serializer := range serializers {
err := RoundtripJWS(alg, serializer, corrupter, signingKey, verificationKey, "test_nonce")
if err != nil {
t.Error(err, alg, i)
}
}
}
}
func TestRoundtripsJWSCorruptSignature(t *testing.T) {
// Test matrix
sigAlgs := []SignatureAlgorithm{RS256, RS384, RS512, PS256, PS384, PS512, HS256, HS384, HS512, ES256, ES384, ES512, EdDSA}
serializers := []func(*JSONWebSignature) (string, error){
func(obj *JSONWebSignature) (string, error) { return obj.CompactSerialize() },
func(obj *JSONWebSignature) (string, error) { return obj.FullSerialize(), nil },
}
corrupters := []func(*JSONWebSignature){
func(obj *JSONWebSignature) {
// Changes bytes in signature
obj.Signatures[0].Signature[10]++
},
func(obj *JSONWebSignature) {
// Set totally invalid signature
obj.Signatures[0].Signature = []byte("###")
},
}
// Test all different configurations
for _, alg := range sigAlgs {
signingKey, verificationKey := GenerateSigningTestKey(alg)
for i, serializer := range serializers {
for j, corrupter := range corrupters {
err := RoundtripJWS(alg, serializer, corrupter, signingKey, verificationKey, "test_nonce")
if err == nil {
t.Error("failed to detect corrupt signature", err, alg, i, j)
}
}
}
}
}
func TestSignerWithBrokenRand(t *testing.T) {
sigAlgs := []SignatureAlgorithm{RS256, RS384, RS512, PS256, PS384, PS512}
serializer := func(obj *JSONWebSignature) (string, error) { return obj.CompactSerialize() }
corrupter := func(obj *JSONWebSignature) {}
// Break rand reader
readers := []func() io.Reader{
// Totally broken
func() io.Reader { return bytes.NewReader([]byte{}) },
// Not enough bytes
func() io.Reader { return io.LimitReader(rand.Reader, 20) },
}
defer resetRandReader()
for _, alg := range sigAlgs {
signingKey, verificationKey := GenerateSigningTestKey(alg)
for i, getReader := range readers {
randReader = getReader()
err := RoundtripJWS(alg, serializer, corrupter, signingKey, verificationKey, "test_nonce")
if err == nil {
t.Error("signer should fail if rand is broken", alg, i)
}
}
}
}
func TestJWSInvalidKey(t *testing.T) {
signingKey0, verificationKey0 := GenerateSigningTestKey(RS256)
_, verificationKey1 := GenerateSigningTestKey(ES256)
_, verificationKey2 := GenerateSigningTestKey(EdDSA)
signer, err := NewSigner(SigningKey{Algorithm: RS256, Key: signingKey0}, nil)
if err != nil {
panic(err)
}
input := []byte("Lorem ipsum dolor sit amet")
obj, err := signer.Sign(input)
if err != nil {
panic(err)
}
// Must work with correct key
_, err = obj.Verify(verificationKey0)
if err != nil {
t.Error("error on verify", err)
}
// Must not work with incorrect key
_, err = obj.Verify(verificationKey1)
if err == nil {
t.Error("verification should fail with incorrect key")
}
// Must not work with incorrect key
_, err = obj.Verify(verificationKey2)
if err == nil {
t.Error("verification should fail with incorrect key")
}
// Must not work with invalid key
_, err = obj.Verify("")
if err == nil {
t.Error("verification should fail with incorrect key")
}
}
func TestMultiRecipientJWS(t *testing.T) {
sharedKey := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}
jwkSharedKey := JSONWebKey{
KeyID: "123",
Key: sharedKey,
}
signer, err := NewMultiSigner([]SigningKey{
{RS256, rsaTestKey},
{HS384, sharedKey},
{HS512, jwkSharedKey},
}, nil)
if err != nil {
t.Fatal("error creating signer: ", err)
}
input := []byte("Lorem ipsum dolor sit amet")
obj, err := signer.Sign(input)
if err != nil {
t.Fatal("error on sign: ", err)
}
_, err = obj.CompactSerialize()
if err == nil {
t.Fatal("message with multiple recipient was compact serialized")
}
msg := obj.FullSerialize()
obj, err = ParseSigned(msg)
if err != nil {
t.Fatal("error on parse: ", err)
}
i, _, output, err := obj.VerifyMulti(&rsaTestKey.PublicKey)
if err != nil {
t.Fatal("error on verify: ", err)
}
if i != 0 {
t.Fatal("signature index should be 0 for RSA key")
}
if bytes.Compare(output, input) != 0 {
t.Fatal("input/output do not match", output, input)
}
i, _, output, err = obj.VerifyMulti(sharedKey)
if err != nil {
t.Fatal("error on verify: ", err)
}
if i != 1 {
t.Fatal("signature index should be 1 for EC key")
}
if bytes.Compare(output, input) != 0 {
t.Fatal("input/output do not match", output, input)
}
}
func GenerateSigningTestKey(sigAlg SignatureAlgorithm) (sig, ver interface{}) {
switch sigAlg {
case EdDSA:
sig = ed25519PrivateKey
ver = ed25519PublicKey
case RS256, RS384, RS512, PS256, PS384, PS512:
sig = rsaTestKey
ver = &rsaTestKey.PublicKey
case HS256, HS384, HS512:
sig, _, _ = randomKeyGenerator{size: 16}.genKey()
ver = sig
case ES256:
key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
sig = key
ver = &key.PublicKey
case ES384:
key, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
sig = key
ver = &key.PublicKey
case ES512:
key, _ := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
sig = key
ver = &key.PublicKey
default:
panic("Must update test case")
}
return
}
func TestInvalidSignerAlg(t *testing.T) {
_, err := NewSigner(SigningKey{"XYZ", nil}, nil)
if err == nil {
t.Error("should not accept invalid algorithm")
}
_, err = NewSigner(SigningKey{"XYZ", []byte{}}, nil)
if err == nil {
t.Error("should not accept invalid algorithm")
}
}
func TestInvalidJWS(t *testing.T) {
signer, err := NewSigner(SigningKey{PS256, rsaTestKey}, nil)
if err != nil {
panic(err)
}
obj, err := signer.Sign([]byte("Lorem ipsum dolor sit amet"))
obj.Signatures[0].header = &rawHeader{}
obj.Signatures[0].header.set(headerCritical, []string{"TEST"})
_, err = obj.Verify(&rsaTestKey.PublicKey)
if err == nil {
t.Error("should not verify message with unknown crit header")
}
// Try without alg header
obj.Signatures[0].protected = &rawHeader{}
obj.Signatures[0].header = &rawHeader{}
_, err = obj.Verify(&rsaTestKey.PublicKey)
if err == nil {
t.Error("should not verify message with missing headers")
}
}
func TestSignerKid(t *testing.T) {
kid := "DEADBEEF"
payload := []byte("Lorem ipsum dolor sit amet")
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Error("problem generating test signing key", err)
}
basejwk := JSONWebKey{Key: key}
jsonbar, err := basejwk.MarshalJSON()
if err != nil {
t.Error("problem marshalling base JWK", err)
}
var jsonmsi map[string]interface{}
err = json.Unmarshal(jsonbar, &jsonmsi)
if err != nil {
t.Error("problem unmarshalling base JWK", err)
}
jsonmsi["kid"] = kid
jsonbar2, err := json.Marshal(jsonmsi)
if err != nil {
t.Error("problem marshalling kided JWK", err)
}
var jwk JSONWebKey
err = jwk.UnmarshalJSON(jsonbar2)
if err != nil {
t.Error("problem unmarshalling kided JWK", err)
}
signer, err := NewSigner(SigningKey{ES256, &jwk}, nil)
if err != nil {
t.Error("problem creating signer with *JSONWebKey", err)
}
signed, err := signer.Sign(payload)
serialized := signed.FullSerialize()
parsed, err := ParseSigned(serialized)
if err != nil {
t.Error("problem parsing signed object", err)
}
if parsed.Signatures[0].Header.KeyID != kid {
t.Error("KeyID did not survive trip")
}
signer, err = NewSigner(SigningKey{ES256, jwk}, nil)
if err != nil {
t.Error("problem creating signer with JSONWebKey", err)
}
}
func TestEmbedJwk(t *testing.T) {
var payload = []byte("Lorem ipsum dolor sit amet")
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Error("Failed to generate key")
}
signer, err := NewSigner(SigningKey{ES256, key}, &SignerOptions{EmbedJWK: true})
if err != nil {
t.Error("Failed to create signer")
}
object, err := signer.Sign(payload)
if err != nil {
t.Error("Failed to sign payload")
}
object, err = ParseSigned(object.FullSerialize())
if err != nil {
t.Error("Failed to parse jws")
}
jwk, err := object.Signatures[0].protected.getJWK()
if jwk == nil || err != nil {
t.Error("JWK isn't set in protected header")
}
// This time, sign and do not embed JWK in message
signer, err = NewSigner(SigningKey{ES256, key}, &SignerOptions{EmbedJWK: false})
object, err = signer.Sign(payload)
if err != nil {
t.Error("Failed to sign payload")
}
object, err = ParseSigned(object.FullSerialize())
if err != nil {
t.Error("Failed to parse jws")
}
jwk2, err := object.Signatures[0].protected.getJWK()
if err != nil {
t.Error("JWK is invalid in protected header")
}
if jwk2 != nil {
t.Error("JWK is set in protected header")
}
}
func TestSignerOptionsEd(t *testing.T) {
key, _ := GenerateSigningTestKey(EdDSA)
opts := &SignerOptions{
EmbedJWK: true,
}
opts.WithContentType("JWT")
opts.WithType("JWT")
sig, err := NewSigner(SigningKey{EdDSA, key}, opts)
if err != nil {
t.Error("Failed to create signer")
}
if !reflect.DeepEqual(*opts, sig.Options()) {
t.Error("Signer options do not match")
}
}
func TestSignerOptions(t *testing.T) {
key, _ := GenerateSigningTestKey(HS256)
opts := &SignerOptions{
EmbedJWK: true,
}
opts.WithContentType("JWT")
opts.WithType("JWT")
sig, err := NewSigner(SigningKey{HS256, key}, opts)
if err != nil {
t.Error("Failed to create signer")
}
if !reflect.DeepEqual(*opts, sig.Options()) {
t.Error("Signer options do not match")
}
}
// Test that extra headers are generated and parsed in a round trip.
func TestSignerExtraHeaderInclusion(t *testing.T) {
var payload = []byte("Lorem ipsum dolor sit amet")
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Error("Failed to generate key")
}
signer, err := NewSigner(SigningKey{ES256, key}, (&SignerOptions{}).WithContentType("foo/bar").WithHeader(HeaderKey("myCustomHeader"), "xyz"))
if err != nil {
t.Error("Failed to create signer", err)
}
object, err := signer.Sign(payload)
if err != nil {
t.Error("Failed to sign payload")
}
object, err = ParseSigned(object.FullSerialize())
if err != nil {
t.Error("Failed to parse jws")
}
correct := map[HeaderKey]interface{}{
HeaderContentType: "foo/bar",
HeaderKey("myCustomHeader"): "xyz",
}
if !reflect.DeepEqual(object.Signatures[0].Header.ExtraHeaders, correct) {
t.Errorf("Mismatch in extra headers: %#v", object.Signatures[0].Header.ExtraHeaders)
}
}

View file

@ -1,131 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jose
import (
"bytes"
"crypto/cipher"
"crypto/rand"
"io"
"testing"
)
func TestInvalidSymmetricAlgorithms(t *testing.T) {
_, err := newSymmetricRecipient("XYZ", []byte{})
if err != ErrUnsupportedAlgorithm {
t.Error("should not accept invalid algorithm")
}
enc := &symmetricKeyCipher{}
_, err = enc.encryptKey([]byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should not accept invalid algorithm")
}
}
func TestAeadErrors(t *testing.T) {
aead := &aeadContentCipher{
keyBytes: 16,
authtagBytes: 16,
getAead: func(key []byte) (cipher.AEAD, error) {
return nil, ErrCryptoFailure
},
}
parts, err := aead.encrypt([]byte{}, []byte{}, []byte{})
if err != ErrCryptoFailure {
t.Error("should handle aead failure")
}
_, err = aead.decrypt([]byte{}, []byte{}, parts)
if err != ErrCryptoFailure {
t.Error("should handle aead failure")
}
}
func TestInvalidKey(t *testing.T) {
gcm := newAESGCM(16).(*aeadContentCipher)
_, err := gcm.getAead([]byte{})
if err == nil {
t.Error("should not accept invalid key")
}
}
func TestStaticKeyGen(t *testing.T) {
key := make([]byte, 32)
io.ReadFull(rand.Reader, key)
gen := &staticKeyGenerator{key: key}
if gen.keySize() != len(key) {
t.Error("static key generator reports incorrect size")
}
generated, _, err := gen.genKey()
if err != nil {
t.Error("static key generator should always succeed", err)
}
if !bytes.Equal(generated, key) {
t.Error("static key generator returns different data")
}
}
func TestVectorsAESGCM(t *testing.T) {
// Source: http://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-29#appendix-A.1
plaintext := []byte{
84, 104, 101, 32, 116, 114, 117, 101, 32, 115, 105, 103, 110, 32,
111, 102, 32, 105, 110, 116, 101, 108, 108, 105, 103, 101, 110, 99,
101, 32, 105, 115, 32, 110, 111, 116, 32, 107, 110, 111, 119, 108,
101, 100, 103, 101, 32, 98, 117, 116, 32, 105, 109, 97, 103, 105,
110, 97, 116, 105, 111, 110, 46}
aad := []byte{
101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 48, 69,
116, 84, 48, 70, 70, 85, 67, 73, 115, 73, 109, 86, 117, 89, 121, 73,
54, 73, 107, 69, 121, 78, 84, 90, 72, 81, 48, 48, 105, 102, 81}
expectedCiphertext := []byte{
229, 236, 166, 241, 53, 191, 115, 196, 174, 43, 73, 109, 39, 122,
233, 96, 140, 206, 120, 52, 51, 237, 48, 11, 190, 219, 186, 80, 111,
104, 50, 142, 47, 167, 59, 61, 181, 127, 196, 21, 40, 82, 242, 32,
123, 143, 168, 226, 73, 216, 176, 144, 138, 247, 106, 60, 16, 205,
160, 109, 64, 63, 192}
expectedAuthtag := []byte{
92, 80, 104, 49, 133, 25, 161, 215, 173, 101, 219, 211, 136, 91, 210, 145}
// Mock random reader
randReader = bytes.NewReader([]byte{
177, 161, 244, 128, 84, 143, 225, 115, 63, 180, 3, 255, 107, 154,
212, 246, 138, 7, 110, 91, 112, 46, 34, 105, 47, 130, 203, 46, 122,
234, 64, 252, 227, 197, 117, 252, 2, 219, 233, 68, 180, 225, 77, 219})
defer resetRandReader()
enc := newAESGCM(32)
key, _, _ := randomKeyGenerator{size: 32}.genKey()
out, err := enc.encrypt(key, aad, plaintext)
if err != nil {
t.Error("Unable to encrypt:", err)
return
}
if bytes.Compare(out.ciphertext, expectedCiphertext) != 0 {
t.Error("Ciphertext did not match")
}
if bytes.Compare(out.tag, expectedAuthtag) != 0 {
t.Error("Auth tag did not match")
}
}

View file

@ -1,70 +0,0 @@
/*-
* Copyright 2014 Square Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jose
import (
"crypto/rand"
"encoding/base64"
"encoding/hex"
"math/big"
"regexp"
)
// Reset random reader to original value
func resetRandReader() {
randReader = rand.Reader
}
// Build big int from hex-encoded string. Strips whitespace (for testing).
func fromHexInt(base16 string) *big.Int {
re := regexp.MustCompile(`\s+`)
val, ok := new(big.Int).SetString(re.ReplaceAllString(base16, ""), 16)
if !ok {
panic("Invalid test data")
}
return val
}
// Build big int from base64-encoded string. Strips whitespace (for testing).
func fromBase64Int(encoded string) *big.Int {
re := regexp.MustCompile(`\s+`)
val, err := base64.RawURLEncoding.DecodeString(re.ReplaceAllString(encoded, ""))
if err != nil {
panic("Invalid test data: " + err.Error())
}
return new(big.Int).SetBytes(val)
}
// Decode hex-encoded string into byte array. Strips whitespace (for testing).
func fromHexBytes(base16 string) []byte {
re := regexp.MustCompile(`\s+`)
val, err := hex.DecodeString(re.ReplaceAllString(base16, ""))
if err != nil {
panic("Invalid test data")
}
return val
}
// Decode base64-encoded string into byte array. Strips whitespace (for testing).
func fromBase64Bytes(b64 string) []byte {
re := regexp.MustCompile(`\s+`)
val, err := base64.StdEncoding.DecodeString(re.ReplaceAllString(b64, ""))
if err != nil {
panic("Invalid test data")
}
return val
}

View file

@ -4,6 +4,9 @@ go:
- 1.4
- 1.5
- 1.6
- 1.7
- 1.8
- 1.9
- tip
go_import_path: gopkg.in/yaml.v2

13
vendor/gopkg.in/yaml.v2/NOTICE generated vendored Normal file
View file

@ -0,0 +1,13 @@
Copyright 2011-2016 Canonical Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

4
vendor/gopkg.in/yaml.v2/README.md generated vendored
View file

@ -48,8 +48,6 @@ The yaml package is licensed under the Apache License 2.0. Please see the LICENS
Example
-------
Some more examples can be found in the "examples" folder.
```Go
package main
@ -67,6 +65,8 @@ b:
d: [3, 4]
`
// Note: struct fields must be public in order for unmarshal to
// correctly populate the data.
type T struct {
A string
B struct {

55
vendor/gopkg.in/yaml.v2/apic.go generated vendored
View file

@ -2,7 +2,6 @@ package yaml
import (
"io"
"os"
)
func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) {
@ -48,9 +47,9 @@ func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err
return n, nil
}
// File read handler.
func yaml_file_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
return parser.input_file.Read(buffer)
// Reader read handler.
func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
return parser.input_reader.Read(buffer)
}
// Set a string input.
@ -64,12 +63,12 @@ func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) {
}
// Set a file input.
func yaml_parser_set_input_file(parser *yaml_parser_t, file *os.File) {
func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) {
if parser.read_handler != nil {
panic("must set the input source only once")
}
parser.read_handler = yaml_file_read_handler
parser.input_file = file
parser.read_handler = yaml_reader_read_handler
parser.input_reader = r
}
// Set the source encoding.
@ -81,14 +80,13 @@ func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
}
// Create a new emitter object.
func yaml_emitter_initialize(emitter *yaml_emitter_t) bool {
func yaml_emitter_initialize(emitter *yaml_emitter_t) {
*emitter = yaml_emitter_t{
buffer: make([]byte, output_buffer_size),
raw_buffer: make([]byte, 0, output_raw_buffer_size),
states: make([]yaml_emitter_state_t, 0, initial_stack_size),
events: make([]yaml_event_t, 0, initial_queue_size),
}
return true
}
// Destroy an emitter object.
@ -102,9 +100,10 @@ func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
return nil
}
// File write handler.
func yaml_file_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
_, err := emitter.output_file.Write(buffer)
// yaml_writer_write_handler uses emitter.output_writer to write the
// emitted text.
func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
_, err := emitter.output_writer.Write(buffer)
return err
}
@ -118,12 +117,12 @@ func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]by
}
// Set a file output.
func yaml_emitter_set_output_file(emitter *yaml_emitter_t, file io.Writer) {
func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) {
if emitter.write_handler != nil {
panic("must set the output target only once")
}
emitter.write_handler = yaml_file_write_handler
emitter.output_file = file
emitter.write_handler = yaml_writer_write_handler
emitter.output_writer = w
}
// Set the output encoding.
@ -252,41 +251,41 @@ func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) {
//
// Create STREAM-START.
func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) bool {
func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) {
*event = yaml_event_t{
typ: yaml_STREAM_START_EVENT,
encoding: encoding,
}
return true
}
// Create STREAM-END.
func yaml_stream_end_event_initialize(event *yaml_event_t) bool {
func yaml_stream_end_event_initialize(event *yaml_event_t) {
*event = yaml_event_t{
typ: yaml_STREAM_END_EVENT,
}
return true
}
// Create DOCUMENT-START.
func yaml_document_start_event_initialize(event *yaml_event_t, version_directive *yaml_version_directive_t,
tag_directives []yaml_tag_directive_t, implicit bool) bool {
func yaml_document_start_event_initialize(
event *yaml_event_t,
version_directive *yaml_version_directive_t,
tag_directives []yaml_tag_directive_t,
implicit bool,
) {
*event = yaml_event_t{
typ: yaml_DOCUMENT_START_EVENT,
version_directive: version_directive,
tag_directives: tag_directives,
implicit: implicit,
}
return true
}
// Create DOCUMENT-END.
func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) bool {
func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) {
*event = yaml_event_t{
typ: yaml_DOCUMENT_END_EVENT,
implicit: implicit,
}
return true
}
///*
@ -348,7 +347,7 @@ func yaml_sequence_end_event_initialize(event *yaml_event_t) bool {
}
// Create MAPPING-START.
func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) bool {
func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) {
*event = yaml_event_t{
typ: yaml_MAPPING_START_EVENT,
anchor: anchor,
@ -356,15 +355,13 @@ func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte
implicit: implicit,
style: yaml_style_t(style),
}
return true
}
// Create MAPPING-END.
func yaml_mapping_end_event_initialize(event *yaml_event_t) bool {
func yaml_mapping_end_event_initialize(event *yaml_event_t) {
*event = yaml_event_t{
typ: yaml_MAPPING_END_EVENT,
}
return true
}
// Destroy an event object.
@ -471,7 +468,7 @@ func yaml_event_delete(event *yaml_event_t) {
// } context
// tag_directive *yaml_tag_directive_t
//
// context.error = YAML_NO_ERROR // Eliminate a compliler warning.
// context.error = YAML_NO_ERROR // Eliminate a compiler warning.
//
// assert(document) // Non-NULL document object is expected.
//

244
vendor/gopkg.in/yaml.v2/decode.go generated vendored
View file

@ -4,6 +4,7 @@ import (
"encoding"
"encoding/base64"
"fmt"
"io"
"math"
"reflect"
"strconv"
@ -22,19 +23,22 @@ type node struct {
kind int
line, column int
tag string
value string
implicit bool
children []*node
anchors map[string]*node
// For an alias node, alias holds the resolved alias.
alias *node
value string
implicit bool
children []*node
anchors map[string]*node
}
// ----------------------------------------------------------------------------
// Parser, produces a node tree out of a libyaml event stream.
type parser struct {
parser yaml_parser_t
event yaml_event_t
doc *node
parser yaml_parser_t
event yaml_event_t
doc *node
doneInit bool
}
func newParser(b []byte) *parser {
@ -42,21 +46,30 @@ func newParser(b []byte) *parser {
if !yaml_parser_initialize(&p.parser) {
panic("failed to initialize YAML emitter")
}
if len(b) == 0 {
b = []byte{'\n'}
}
yaml_parser_set_input_string(&p.parser, b)
p.skip()
if p.event.typ != yaml_STREAM_START_EVENT {
panic("expected stream start event, got " + strconv.Itoa(int(p.event.typ)))
}
p.skip()
return &p
}
func newParserFromReader(r io.Reader) *parser {
p := parser{}
if !yaml_parser_initialize(&p.parser) {
panic("failed to initialize YAML emitter")
}
yaml_parser_set_input_reader(&p.parser, r)
return &p
}
func (p *parser) init() {
if p.doneInit {
return
}
p.expect(yaml_STREAM_START_EVENT)
p.doneInit = true
}
func (p *parser) destroy() {
if p.event.typ != yaml_NO_EVENT {
yaml_event_delete(&p.event)
@ -64,16 +77,35 @@ func (p *parser) destroy() {
yaml_parser_delete(&p.parser)
}
func (p *parser) skip() {
if p.event.typ != yaml_NO_EVENT {
if p.event.typ == yaml_STREAM_END_EVENT {
failf("attempted to go past the end of stream; corrupted value?")
// expect consumes an event from the event stream and
// checks that it's of the expected type.
func (p *parser) expect(e yaml_event_type_t) {
if p.event.typ == yaml_NO_EVENT {
if !yaml_parser_parse(&p.parser, &p.event) {
p.fail()
}
yaml_event_delete(&p.event)
}
if p.event.typ == yaml_STREAM_END_EVENT {
failf("attempted to go past the end of stream; corrupted value?")
}
if p.event.typ != e {
p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
p.fail()
}
yaml_event_delete(&p.event)
p.event.typ = yaml_NO_EVENT
}
// peek peeks at the next event in the event stream,
// puts the results into p.event and returns the event type.
func (p *parser) peek() yaml_event_type_t {
if p.event.typ != yaml_NO_EVENT {
return p.event.typ
}
if !yaml_parser_parse(&p.parser, &p.event) {
p.fail()
}
return p.event.typ
}
func (p *parser) fail() {
@ -81,6 +113,10 @@ func (p *parser) fail() {
var line int
if p.parser.problem_mark.line != 0 {
line = p.parser.problem_mark.line
// Scanner errors don't iterate line before returning error
if p.parser.error == yaml_SCANNER_ERROR {
line++
}
} else if p.parser.context_mark.line != 0 {
line = p.parser.context_mark.line
}
@ -103,7 +139,8 @@ func (p *parser) anchor(n *node, anchor []byte) {
}
func (p *parser) parse() *node {
switch p.event.typ {
p.init()
switch p.peek() {
case yaml_SCALAR_EVENT:
return p.scalar()
case yaml_ALIAS_EVENT:
@ -118,7 +155,7 @@ func (p *parser) parse() *node {
// Happens when attempting to decode an empty buffer.
return nil
default:
panic("attempted to parse unknown event: " + strconv.Itoa(int(p.event.typ)))
panic("attempted to parse unknown event: " + p.event.typ.String())
}
}
@ -134,19 +171,20 @@ func (p *parser) document() *node {
n := p.node(documentNode)
n.anchors = make(map[string]*node)
p.doc = n
p.skip()
p.expect(yaml_DOCUMENT_START_EVENT)
n.children = append(n.children, p.parse())
if p.event.typ != yaml_DOCUMENT_END_EVENT {
panic("expected end of document event but got " + strconv.Itoa(int(p.event.typ)))
}
p.skip()
p.expect(yaml_DOCUMENT_END_EVENT)
return n
}
func (p *parser) alias() *node {
n := p.node(aliasNode)
n.value = string(p.event.anchor)
p.skip()
n.alias = p.doc.anchors[n.value]
if n.alias == nil {
failf("unknown anchor '%s' referenced", n.value)
}
p.expect(yaml_ALIAS_EVENT)
return n
}
@ -156,29 +194,29 @@ func (p *parser) scalar() *node {
n.tag = string(p.event.tag)
n.implicit = p.event.implicit
p.anchor(n, p.event.anchor)
p.skip()
p.expect(yaml_SCALAR_EVENT)
return n
}
func (p *parser) sequence() *node {
n := p.node(sequenceNode)
p.anchor(n, p.event.anchor)
p.skip()
for p.event.typ != yaml_SEQUENCE_END_EVENT {
p.expect(yaml_SEQUENCE_START_EVENT)
for p.peek() != yaml_SEQUENCE_END_EVENT {
n.children = append(n.children, p.parse())
}
p.skip()
p.expect(yaml_SEQUENCE_END_EVENT)
return n
}
func (p *parser) mapping() *node {
n := p.node(mappingNode)
p.anchor(n, p.event.anchor)
p.skip()
for p.event.typ != yaml_MAPPING_END_EVENT {
p.expect(yaml_MAPPING_START_EVENT)
for p.peek() != yaml_MAPPING_END_EVENT {
n.children = append(n.children, p.parse(), p.parse())
}
p.skip()
p.expect(yaml_MAPPING_END_EVENT)
return n
}
@ -187,7 +225,7 @@ func (p *parser) mapping() *node {
type decoder struct {
doc *node
aliases map[string]bool
aliases map[*node]bool
mapType reflect.Type
terrors []string
strict bool
@ -198,11 +236,13 @@ var (
durationType = reflect.TypeOf(time.Duration(0))
defaultMapType = reflect.TypeOf(map[interface{}]interface{}{})
ifaceType = defaultMapType.Elem()
timeType = reflect.TypeOf(time.Time{})
ptrTimeType = reflect.TypeOf(&time.Time{})
)
func newDecoder(strict bool) *decoder {
d := &decoder{mapType: defaultMapType, strict: strict}
d.aliases = make(map[string]bool)
d.aliases = make(map[*node]bool)
return d
}
@ -251,7 +291,7 @@ func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) {
//
// If n holds a null value, prepare returns before doing anything.
func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "" && n.implicit) {
if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) {
return out, false, false
}
again := true
@ -308,16 +348,13 @@ func (d *decoder) document(n *node, out reflect.Value) (good bool) {
}
func (d *decoder) alias(n *node, out reflect.Value) (good bool) {
an, ok := d.doc.anchors[n.value]
if !ok {
failf("unknown anchor '%s' referenced", n.value)
}
if d.aliases[n.value] {
if d.aliases[n] {
// TODO this could actually be allowed in some circumstances.
failf("anchor '%s' value contains itself", n.value)
}
d.aliases[n.value] = true
good = d.unmarshal(an, out)
delete(d.aliases, n.value)
d.aliases[n] = true
good = d.unmarshal(n.alias, out)
delete(d.aliases, n)
return good
}
@ -329,7 +366,7 @@ func resetMap(out reflect.Value) {
}
}
func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
func (d *decoder) scalar(n *node, out reflect.Value) bool {
var tag string
var resolved interface{}
if n.tag == "" && !n.implicit {
@ -353,9 +390,26 @@ func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
}
return true
}
if s, ok := resolved.(string); ok && out.CanAddr() {
if u, ok := out.Addr().Interface().(encoding.TextUnmarshaler); ok {
err := u.UnmarshalText([]byte(s))
if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
// We've resolved to exactly the type we want, so use that.
out.Set(resolvedv)
return true
}
// Perhaps we can use the value as a TextUnmarshaler to
// set its value.
if out.CanAddr() {
u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
if ok {
var text []byte
if tag == yaml_BINARY_TAG {
text = []byte(resolved.(string))
} else {
// We let any value be unmarshaled into TextUnmarshaler.
// That might be more lax than we'd like, but the
// TextUnmarshaler itself should bowl out any dubious values.
text = []byte(n.value)
}
err := u.UnmarshalText(text)
if err != nil {
fail(err)
}
@ -366,46 +420,54 @@ func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
case reflect.String:
if tag == yaml_BINARY_TAG {
out.SetString(resolved.(string))
good = true
} else if resolved != nil {
return true
}
if resolved != nil {
out.SetString(n.value)
good = true
return true
}
case reflect.Interface:
if resolved == nil {
out.Set(reflect.Zero(out.Type()))
} else if tag == yaml_TIMESTAMP_TAG {
// It looks like a timestamp but for backward compatibility
// reasons we set it as a string, so that code that unmarshals
// timestamp-like values into interface{} will continue to
// see a string and not a time.Time.
// TODO(v3) Drop this.
out.Set(reflect.ValueOf(n.value))
} else {
out.Set(reflect.ValueOf(resolved))
}
good = true
return true
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch resolved := resolved.(type) {
case int:
if !out.OverflowInt(int64(resolved)) {
out.SetInt(int64(resolved))
good = true
return true
}
case int64:
if !out.OverflowInt(resolved) {
out.SetInt(resolved)
good = true
return true
}
case uint64:
if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
out.SetInt(int64(resolved))
good = true
return true
}
case float64:
if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
out.SetInt(int64(resolved))
good = true
return true
}
case string:
if out.Type() == durationType {
d, err := time.ParseDuration(resolved)
if err == nil {
out.SetInt(int64(d))
good = true
return true
}
}
}
@ -414,44 +476,49 @@ func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
case int:
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
out.SetUint(uint64(resolved))
good = true
return true
}
case int64:
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
out.SetUint(uint64(resolved))
good = true
return true
}
case uint64:
if !out.OverflowUint(uint64(resolved)) {
out.SetUint(uint64(resolved))
good = true
return true
}
case float64:
if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
out.SetUint(uint64(resolved))
good = true
return true
}
}
case reflect.Bool:
switch resolved := resolved.(type) {
case bool:
out.SetBool(resolved)
good = true
return true
}
case reflect.Float32, reflect.Float64:
switch resolved := resolved.(type) {
case int:
out.SetFloat(float64(resolved))
good = true
return true
case int64:
out.SetFloat(float64(resolved))
good = true
return true
case uint64:
out.SetFloat(float64(resolved))
good = true
return true
case float64:
out.SetFloat(resolved)
good = true
return true
}
case reflect.Struct:
if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
out.Set(resolvedv)
return true
}
case reflect.Ptr:
if out.Type().Elem() == reflect.TypeOf(resolved) {
@ -459,13 +526,11 @@ func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
elem := reflect.New(out.Type().Elem())
elem.Elem().Set(reflect.ValueOf(resolved))
out.Set(elem)
good = true
return true
}
}
if !good {
d.terror(n, tag, out)
}
return good
d.terror(n, tag, out)
return false
}
func settableValueOf(i interface{}) reflect.Value {
@ -482,6 +547,10 @@ func (d *decoder) sequence(n *node, out reflect.Value) (good bool) {
switch out.Kind() {
case reflect.Slice:
out.Set(reflect.MakeSlice(out.Type(), l, l))
case reflect.Array:
if l != out.Len() {
failf("invalid array: want %d elements but got %d", out.Len(), l)
}
case reflect.Interface:
// No type hints. Will have to use a generic sequence.
iface = out
@ -500,7 +569,9 @@ func (d *decoder) sequence(n *node, out reflect.Value) (good bool) {
j++
}
}
out.Set(out.Slice(0, j))
if out.Kind() != reflect.Array {
out.Set(out.Slice(0, j))
}
if iface.IsValid() {
iface.Set(out)
}
@ -561,7 +632,7 @@ func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
}
e := reflect.New(et).Elem()
if d.unmarshal(n.children[i+1], e) {
out.SetMapIndex(k, e)
d.setMapIndex(n.children[i+1], out, k, e)
}
}
}
@ -569,6 +640,14 @@ func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
return true
}
func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) {
if d.strict && out.MapIndex(k) != zeroValue {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface()))
return
}
out.SetMapIndex(k, v)
}
func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) {
outt := out.Type()
if outt.Elem() != mapItemType {
@ -616,6 +695,10 @@ func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
elemType = inlineMap.Type().Elem()
}
var doneFields []bool
if d.strict {
doneFields = make([]bool, len(sinfo.FieldsList))
}
for i := 0; i < l; i += 2 {
ni := n.children[i]
if isMerge(ni) {
@ -626,6 +709,13 @@ func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
continue
}
if info, ok := sinfo.FieldsMap[name.String()]; ok {
if d.strict {
if doneFields[info.Id] {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type()))
continue
}
doneFields[info.Id] = true
}
var field reflect.Value
if info.Inline == nil {
field = out.Field(info.Num)
@ -639,9 +729,9 @@ func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
}
value := reflect.New(elemType).Elem()
d.unmarshal(n.children[i+1], value)
inlineMap.SetMapIndex(name, value)
d.setMapIndex(n.children[i+1], inlineMap, name, value)
} else if d.strict {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in struct %s", n.line+1, name.String(), out.Type()))
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type()))
}
}
return true

1017
vendor/gopkg.in/yaml.v2/decode_test.go generated vendored

File diff suppressed because it is too large Load diff

11
vendor/gopkg.in/yaml.v2/emitterc.go generated vendored
View file

@ -2,6 +2,7 @@ package yaml
import (
"bytes"
"fmt"
)
// Flush the buffer if needed.
@ -664,7 +665,7 @@ func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t,
return yaml_emitter_emit_mapping_start(emitter, event)
default:
return yaml_emitter_set_emitter_error(emitter,
"expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS")
fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ))
}
}
@ -842,7 +843,7 @@ func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event
return true
}
// Write an achor.
// Write an anchor.
func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool {
if emitter.anchor_data.anchor == nil {
return true
@ -995,9 +996,9 @@ func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool {
space_break = false
preceded_by_whitespace = false
followed_by_whitespace = false
previous_space = false
previous_break = false
followed_by_whitespace = false
previous_space = false
previous_break = false
)
emitter.scalar_data.value = value

136
vendor/gopkg.in/yaml.v2/encode.go generated vendored
View file

@ -3,12 +3,14 @@ package yaml
import (
"encoding"
"fmt"
"io"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
"time"
"unicode/utf8"
)
type encoder struct {
@ -16,25 +18,39 @@ type encoder struct {
event yaml_event_t
out []byte
flow bool
// doneInit holds whether the initial stream_start_event has been
// emitted.
doneInit bool
}
func newEncoder() (e *encoder) {
e = &encoder{}
e.must(yaml_emitter_initialize(&e.emitter))
func newEncoder() *encoder {
e := &encoder{}
yaml_emitter_initialize(&e.emitter)
yaml_emitter_set_output_string(&e.emitter, &e.out)
yaml_emitter_set_unicode(&e.emitter, true)
e.must(yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING))
e.emit()
e.must(yaml_document_start_event_initialize(&e.event, nil, nil, true))
e.emit()
return e
}
func (e *encoder) finish() {
e.must(yaml_document_end_event_initialize(&e.event, true))
func newEncoderWithWriter(w io.Writer) *encoder {
e := &encoder{}
yaml_emitter_initialize(&e.emitter)
yaml_emitter_set_output_writer(&e.emitter, w)
yaml_emitter_set_unicode(&e.emitter, true)
return e
}
func (e *encoder) init() {
if e.doneInit {
return
}
yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)
e.emit()
e.doneInit = true
}
func (e *encoder) finish() {
e.emitter.open_ended = false
e.must(yaml_stream_end_event_initialize(&e.event))
yaml_stream_end_event_initialize(&e.event)
e.emit()
}
@ -44,9 +60,7 @@ func (e *encoder) destroy() {
func (e *encoder) emit() {
// This will internally delete the e.event value.
if !yaml_emitter_emit(&e.emitter, &e.event) && e.event.typ != yaml_DOCUMENT_END_EVENT && e.event.typ != yaml_STREAM_END_EVENT {
e.must(false)
}
e.must(yaml_emitter_emit(&e.emitter, &e.event))
}
func (e *encoder) must(ok bool) {
@ -59,13 +73,28 @@ func (e *encoder) must(ok bool) {
}
}
func (e *encoder) marshalDoc(tag string, in reflect.Value) {
e.init()
yaml_document_start_event_initialize(&e.event, nil, nil, true)
e.emit()
e.marshal(tag, in)
yaml_document_end_event_initialize(&e.event, true)
e.emit()
}
func (e *encoder) marshal(tag string, in reflect.Value) {
if !in.IsValid() {
if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() {
e.nilv()
return
}
iface := in.Interface()
if m, ok := iface.(Marshaler); ok {
switch m := iface.(type) {
case time.Time, *time.Time:
// Although time.Time implements TextMarshaler,
// we don't want to treat it as a string for YAML
// purposes because YAML has special support for
// timestamps.
case Marshaler:
v, err := m.MarshalYAML()
if err != nil {
fail(err)
@ -75,31 +104,34 @@ func (e *encoder) marshal(tag string, in reflect.Value) {
return
}
in = reflect.ValueOf(v)
} else if m, ok := iface.(encoding.TextMarshaler); ok {
case encoding.TextMarshaler:
text, err := m.MarshalText()
if err != nil {
fail(err)
}
in = reflect.ValueOf(string(text))
case nil:
e.nilv()
return
}
switch in.Kind() {
case reflect.Interface:
if in.IsNil() {
e.nilv()
} else {
e.marshal(tag, in.Elem())
}
e.marshal(tag, in.Elem())
case reflect.Map:
e.mapv(tag, in)
case reflect.Ptr:
if in.IsNil() {
e.nilv()
if in.Type() == ptrTimeType {
e.timev(tag, in.Elem())
} else {
e.marshal(tag, in.Elem())
}
case reflect.Struct:
e.structv(tag, in)
case reflect.Slice:
if in.Type() == timeType {
e.timev(tag, in)
} else {
e.structv(tag, in)
}
case reflect.Slice, reflect.Array:
if in.Type().Elem() == mapItemType {
e.itemsv(tag, in)
} else {
@ -191,10 +223,10 @@ func (e *encoder) mappingv(tag string, f func()) {
e.flow = false
style = yaml_FLOW_MAPPING_STYLE
}
e.must(yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)
e.emit()
f()
e.must(yaml_mapping_end_event_initialize(&e.event))
yaml_mapping_end_event_initialize(&e.event)
e.emit()
}
@ -240,23 +272,36 @@ var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0
func (e *encoder) stringv(tag string, in reflect.Value) {
var style yaml_scalar_style_t
s := in.String()
rtag, rs := resolve("", s)
if rtag == yaml_BINARY_TAG {
if tag == "" || tag == yaml_STR_TAG {
tag = rtag
s = rs.(string)
} else if tag == yaml_BINARY_TAG {
canUsePlain := true
switch {
case !utf8.ValidString(s):
if tag == yaml_BINARY_TAG {
failf("explicitly tagged !!binary data must be base64-encoded")
} else {
}
if tag != "" {
failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
}
// It can't be encoded directly as YAML so use a binary tag
// and encode it as base64.
tag = yaml_BINARY_TAG
s = encodeBase64(s)
case tag == "":
// Check to see if it would resolve to a specific
// tag when encoded unquoted. If it doesn't,
// there's no need to quote it.
rtag, _ := resolve("", s)
canUsePlain = rtag == yaml_STR_TAG && !isBase60Float(s)
}
if tag == "" && (rtag != yaml_STR_TAG || isBase60Float(s)) {
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
} else if strings.Contains(s, "\n") {
// Note: it's possible for user code to emit invalid YAML
// if they explicitly specify a tag and a string containing
// text that's incompatible with that tag.
switch {
case strings.Contains(s, "\n"):
style = yaml_LITERAL_SCALAR_STYLE
} else {
case canUsePlain:
style = yaml_PLAIN_SCALAR_STYLE
default:
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
}
e.emitScalar(s, "", tag, style)
}
@ -281,9 +326,20 @@ func (e *encoder) uintv(tag string, in reflect.Value) {
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
}
func (e *encoder) timev(tag string, in reflect.Value) {
t := in.Interface().(time.Time)
s := t.Format(time.RFC3339Nano)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
}
func (e *encoder) floatv(tag string, in reflect.Value) {
// FIXME: Handle 64 bits here.
s := strconv.FormatFloat(float64(in.Float()), 'g', -1, 32)
// Issue #352: When formatting, use the precision of the underlying value
precision := 64
if in.Kind() == reflect.Float32 {
precision = 32
}
s := strconv.FormatFloat(in.Float(), 'g', -1, precision)
switch s {
case "+Inf":
s = ".inf"

View file

@ -1,501 +0,0 @@
package yaml_test
import (
"fmt"
"math"
"strconv"
"strings"
"time"
. "gopkg.in/check.v1"
"gopkg.in/yaml.v2"
"net"
"os"
)
var marshalIntTest = 123
var marshalTests = []struct {
value interface{}
data string
}{
{
nil,
"null\n",
}, {
&struct{}{},
"{}\n",
}, {
map[string]string{"v": "hi"},
"v: hi\n",
}, {
map[string]interface{}{"v": "hi"},
"v: hi\n",
}, {
map[string]string{"v": "true"},
"v: \"true\"\n",
}, {
map[string]string{"v": "false"},
"v: \"false\"\n",
}, {
map[string]interface{}{"v": true},
"v: true\n",
}, {
map[string]interface{}{"v": false},
"v: false\n",
}, {
map[string]interface{}{"v": 10},
"v: 10\n",
}, {
map[string]interface{}{"v": -10},
"v: -10\n",
}, {
map[string]uint{"v": 42},
"v: 42\n",
}, {
map[string]interface{}{"v": int64(4294967296)},
"v: 4294967296\n",
}, {
map[string]int64{"v": int64(4294967296)},
"v: 4294967296\n",
}, {
map[string]uint64{"v": 4294967296},
"v: 4294967296\n",
}, {
map[string]interface{}{"v": "10"},
"v: \"10\"\n",
}, {
map[string]interface{}{"v": 0.1},
"v: 0.1\n",
}, {
map[string]interface{}{"v": float64(0.1)},
"v: 0.1\n",
}, {
map[string]interface{}{"v": -0.1},
"v: -0.1\n",
}, {
map[string]interface{}{"v": math.Inf(+1)},
"v: .inf\n",
}, {
map[string]interface{}{"v": math.Inf(-1)},
"v: -.inf\n",
}, {
map[string]interface{}{"v": math.NaN()},
"v: .nan\n",
}, {
map[string]interface{}{"v": nil},
"v: null\n",
}, {
map[string]interface{}{"v": ""},
"v: \"\"\n",
}, {
map[string][]string{"v": []string{"A", "B"}},
"v:\n- A\n- B\n",
}, {
map[string][]string{"v": []string{"A", "B\nC"}},
"v:\n- A\n- |-\n B\n C\n",
}, {
map[string][]interface{}{"v": []interface{}{"A", 1, map[string][]int{"B": []int{2, 3}}}},
"v:\n- A\n- 1\n- B:\n - 2\n - 3\n",
}, {
map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}},
"a:\n b: c\n",
}, {
map[string]interface{}{"a": "-"},
"a: '-'\n",
},
// Simple values.
{
&marshalIntTest,
"123\n",
},
// Structures
{
&struct{ Hello string }{"world"},
"hello: world\n",
}, {
&struct {
A struct {
B string
}
}{struct{ B string }{"c"}},
"a:\n b: c\n",
}, {
&struct {
A *struct {
B string
}
}{&struct{ B string }{"c"}},
"a:\n b: c\n",
}, {
&struct {
A *struct {
B string
}
}{},
"a: null\n",
}, {
&struct{ A int }{1},
"a: 1\n",
}, {
&struct{ A []int }{[]int{1, 2}},
"a:\n- 1\n- 2\n",
}, {
&struct {
B int "a"
}{1},
"a: 1\n",
}, {
&struct{ A bool }{true},
"a: true\n",
},
// Conditional flag
{
&struct {
A int "a,omitempty"
B int "b,omitempty"
}{1, 0},
"a: 1\n",
}, {
&struct {
A int "a,omitempty"
B int "b,omitempty"
}{0, 0},
"{}\n",
}, {
&struct {
A *struct{ X, y int } "a,omitempty,flow"
}{&struct{ X, y int }{1, 2}},
"a: {x: 1}\n",
}, {
&struct {
A *struct{ X, y int } "a,omitempty,flow"
}{nil},
"{}\n",
}, {
&struct {
A *struct{ X, y int } "a,omitempty,flow"
}{&struct{ X, y int }{}},
"a: {x: 0}\n",
}, {
&struct {
A struct{ X, y int } "a,omitempty,flow"
}{struct{ X, y int }{1, 2}},
"a: {x: 1}\n",
}, {
&struct {
A struct{ X, y int } "a,omitempty,flow"
}{struct{ X, y int }{0, 1}},
"{}\n",
}, {
&struct {
A float64 "a,omitempty"
B float64 "b,omitempty"
}{1, 0},
"a: 1\n",
},
// Flow flag
{
&struct {
A []int "a,flow"
}{[]int{1, 2}},
"a: [1, 2]\n",
}, {
&struct {
A map[string]string "a,flow"
}{map[string]string{"b": "c", "d": "e"}},
"a: {b: c, d: e}\n",
}, {
&struct {
A struct {
B, D string
} "a,flow"
}{struct{ B, D string }{"c", "e"}},
"a: {b: c, d: e}\n",
},
// Unexported field
{
&struct {
u int
A int
}{0, 1},
"a: 1\n",
},
// Ignored field
{
&struct {
A int
B int "-"
}{1, 2},
"a: 1\n",
},
// Struct inlining
{
&struct {
A int
C inlineB `yaml:",inline"`
}{1, inlineB{2, inlineC{3}}},
"a: 1\nb: 2\nc: 3\n",
},
// Map inlining
{
&struct {
A int
C map[string]int `yaml:",inline"`
}{1, map[string]int{"b": 2, "c": 3}},
"a: 1\nb: 2\nc: 3\n",
},
// Duration
{
map[string]time.Duration{"a": 3 * time.Second},
"a: 3s\n",
},
// Issue #24: bug in map merging logic.
{
map[string]string{"a": "<foo>"},
"a: <foo>\n",
},
// Issue #34: marshal unsupported base 60 floats quoted for compatibility
// with old YAML 1.1 parsers.
{
map[string]string{"a": "1:1"},
"a: \"1:1\"\n",
},
// Binary data.
{
map[string]string{"a": "\x00"},
"a: \"\\0\"\n",
}, {
map[string]string{"a": "\x80\x81\x82"},
"a: !!binary gIGC\n",
}, {
map[string]string{"a": strings.Repeat("\x90", 54)},
"a: !!binary |\n " + strings.Repeat("kJCQ", 17) + "kJ\n CQ\n",
},
// Ordered maps.
{
&yaml.MapSlice{{"b", 2}, {"a", 1}, {"d", 4}, {"c", 3}, {"sub", yaml.MapSlice{{"e", 5}}}},
"b: 2\na: 1\nd: 4\nc: 3\nsub:\n e: 5\n",
},
// Encode unicode as utf-8 rather than in escaped form.
{
map[string]string{"a": "你好"},
"a: 你好\n",
},
// Support encoding.TextMarshaler.
{
map[string]net.IP{"a": net.IPv4(1, 2, 3, 4)},
"a: 1.2.3.4\n",
},
{
map[string]time.Time{"a": time.Unix(1424801979, 0)},
"a: 2015-02-24T18:19:39Z\n",
},
// Ensure strings containing ": " are quoted (reported as PR #43, but not reproducible).
{
map[string]string{"a": "b: c"},
"a: 'b: c'\n",
},
// Containing hash mark ('#') in string should be quoted
{
map[string]string{"a": "Hello #comment"},
"a: 'Hello #comment'\n",
},
{
map[string]string{"a": "你好 #comment"},
"a: '你好 #comment'\n",
},
}
func (s *S) TestMarshal(c *C) {
defer os.Setenv("TZ", os.Getenv("TZ"))
os.Setenv("TZ", "UTC")
for _, item := range marshalTests {
data, err := yaml.Marshal(item.value)
c.Assert(err, IsNil)
c.Assert(string(data), Equals, item.data)
}
}
var marshalErrorTests = []struct {
value interface{}
error string
panic string
}{{
value: &struct {
B int
inlineB ",inline"
}{1, inlineB{2, inlineC{3}}},
panic: `Duplicated key 'b' in struct struct \{ B int; .*`,
}, {
value: &struct {
A int
B map[string]int ",inline"
}{1, map[string]int{"a": 2}},
panic: `Can't have key "a" in inlined map; conflicts with struct field`,
}}
func (s *S) TestMarshalErrors(c *C) {
for _, item := range marshalErrorTests {
if item.panic != "" {
c.Assert(func() { yaml.Marshal(item.value) }, PanicMatches, item.panic)
} else {
_, err := yaml.Marshal(item.value)
c.Assert(err, ErrorMatches, item.error)
}
}
}
func (s *S) TestMarshalTypeCache(c *C) {
var data []byte
var err error
func() {
type T struct{ A int }
data, err = yaml.Marshal(&T{})
c.Assert(err, IsNil)
}()
func() {
type T struct{ B int }
data, err = yaml.Marshal(&T{})
c.Assert(err, IsNil)
}()
c.Assert(string(data), Equals, "b: 0\n")
}
var marshalerTests = []struct {
data string
value interface{}
}{
{"_:\n hi: there\n", map[interface{}]interface{}{"hi": "there"}},
{"_:\n- 1\n- A\n", []interface{}{1, "A"}},
{"_: 10\n", 10},
{"_: null\n", nil},
{"_: BAR!\n", "BAR!"},
}
type marshalerType struct {
value interface{}
}
func (o marshalerType) MarshalText() ([]byte, error) {
panic("MarshalText called on type with MarshalYAML")
}
func (o marshalerType) MarshalYAML() (interface{}, error) {
return o.value, nil
}
type marshalerValue struct {
Field marshalerType "_"
}
func (s *S) TestMarshaler(c *C) {
for _, item := range marshalerTests {
obj := &marshalerValue{}
obj.Field.value = item.value
data, err := yaml.Marshal(obj)
c.Assert(err, IsNil)
c.Assert(string(data), Equals, string(item.data))
}
}
func (s *S) TestMarshalerWholeDocument(c *C) {
obj := &marshalerType{}
obj.value = map[string]string{"hello": "world!"}
data, err := yaml.Marshal(obj)
c.Assert(err, IsNil)
c.Assert(string(data), Equals, "hello: world!\n")
}
type failingMarshaler struct{}
func (ft *failingMarshaler) MarshalYAML() (interface{}, error) {
return nil, failingErr
}
func (s *S) TestMarshalerError(c *C) {
_, err := yaml.Marshal(&failingMarshaler{})
c.Assert(err, Equals, failingErr)
}
func (s *S) TestSortedOutput(c *C) {
order := []interface{}{
false,
true,
1,
uint(1),
1.0,
1.1,
1.2,
2,
uint(2),
2.0,
2.1,
"",
".1",
".2",
".a",
"1",
"2",
"a!10",
"a/2",
"a/10",
"a~10",
"ab/1",
"b/1",
"b/01",
"b/2",
"b/02",
"b/3",
"b/03",
"b1",
"b01",
"b3",
"c2.10",
"c10.2",
"d1",
"d12",
"d12a",
}
m := make(map[interface{}]int)
for _, k := range order {
m[k] = 1
}
data, err := yaml.Marshal(m)
c.Assert(err, IsNil)
out := "\n" + string(data)
last := 0
for i, k := range order {
repr := fmt.Sprint(k)
if s, ok := k.(string); ok {
if _, err = strconv.ParseFloat(repr, 32); s == "" || err == nil {
repr = `"` + repr + `"`
}
}
index := strings.Index(out, "\n"+repr+":")
if index == -1 {
c.Fatalf("%#v is not in the output: %#v", k, out)
}
if index < last {
c.Fatalf("%#v was generated before %#v: %q", k, order[i-1], out)
}
last = index
}
}

View file

@ -1,41 +0,0 @@
package yaml_test
import (
"fmt"
"log"
"gopkg.in/yaml.v2"
)
// An example showing how to unmarshal embedded
// structs from YAML.
type StructA struct {
A string `yaml:"a"`
}
type StructB struct {
// Embedded structs are not treated as embedded in YAML by default. To do that,
// add the ",inline" annotation below
StructA `yaml:",inline"`
B string `yaml:"b"`
}
var data = `
a: a string from struct A
b: a string from struct B
`
func ExampleUnmarshal_embedded() {
var b StructB
err := yaml.Unmarshal([]byte(data), &b)
if err != nil {
log.Fatal("cannot unmarshal data: %v", err)
}
fmt.Println(b.A)
fmt.Println(b.B)
// Output:
// a string from struct A
// a string from struct B
}

5
vendor/gopkg.in/yaml.v2/go.mod generated vendored Normal file
View file

@ -0,0 +1,5 @@
module "gopkg.in/yaml.v2"
require (
"gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405
)

20
vendor/gopkg.in/yaml.v2/readerc.go generated vendored
View file

@ -93,9 +93,18 @@ func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool {
panic("read handler must be set")
}
// [Go] This function was changed to guarantee the requested length size at EOF.
// The fact we need to do this is pretty awful, but the description above implies
// for that to be the case, and there are tests
// If the EOF flag is set and the raw buffer is empty, do nothing.
if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) {
return true
// [Go] ACTUALLY! Read the documentation of this function above.
// This is just broken. To return true, we need to have the
// given length in the buffer. Not doing that means every single
// check that calls this function to make sure the buffer has a
// given length is Go) panicking; or C) accessing invalid memory.
//return true
}
// Return if the buffer contains enough characters.
@ -389,6 +398,15 @@ func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool {
break
}
}
// [Go] Read the documentation of this function above. To return true,
// we need to have the given length in the buffer. Not doing that means
// every single check that calls this function to make sure the buffer
// has a given length is Go) panicking; or C) accessing invalid memory.
// This happens here due to the EOF above breaking early.
for buffer_len < length {
parser.buffer[buffer_len] = 0
buffer_len++
}
parser.buffer = parser.buffer[:buffer_len]
return true
}

80
vendor/gopkg.in/yaml.v2/resolve.go generated vendored
View file

@ -6,7 +6,7 @@ import (
"regexp"
"strconv"
"strings"
"unicode/utf8"
"time"
)
type resolveMapItem struct {
@ -75,7 +75,7 @@ func longTag(tag string) string {
func resolvableTag(tag string) bool {
switch tag {
case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG:
case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG, yaml_TIMESTAMP_TAG:
return true
}
return false
@ -92,6 +92,19 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
switch tag {
case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG:
return
case yaml_FLOAT_TAG:
if rtag == yaml_INT_TAG {
switch v := out.(type) {
case int64:
rtag = yaml_FLOAT_TAG
out = float64(v)
return
case int:
rtag = yaml_FLOAT_TAG
out = float64(v)
return
}
}
}
failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag))
}()
@ -125,6 +138,15 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
case 'D', 'S':
// Int, float, or timestamp.
// Only try values as a timestamp if the value is unquoted or there's an explicit
// !!timestamp tag.
if tag == "" || tag == yaml_TIMESTAMP_TAG {
t, ok := parseTimestamp(in)
if ok {
return yaml_TIMESTAMP_TAG, t
}
}
plain := strings.Replace(in, "_", "", -1)
intv, err := strconv.ParseInt(plain, 0, 64)
if err == nil {
@ -158,28 +180,20 @@ func resolve(tag string, in string) (rtag string, out interface{}) {
return yaml_INT_TAG, uintv
}
} else if strings.HasPrefix(plain, "-0b") {
intv, err := strconv.ParseInt(plain[3:], 2, 64)
intv, err := strconv.ParseInt("-" + plain[3:], 2, 64)
if err == nil {
if intv == int64(int(intv)) {
return yaml_INT_TAG, -int(intv)
if true || intv == int64(int(intv)) {
return yaml_INT_TAG, int(intv)
} else {
return yaml_INT_TAG, -intv
return yaml_INT_TAG, intv
}
}
}
// XXX Handle timestamps here.
default:
panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")")
}
}
if tag == yaml_BINARY_TAG {
return yaml_BINARY_TAG, in
}
if utf8.ValidString(in) {
return yaml_STR_TAG, in
}
return yaml_BINARY_TAG, encodeBase64(in)
return yaml_STR_TAG, in
}
// encodeBase64 encodes s as base64 that is broken up into multiple lines
@ -206,3 +220,39 @@ func encodeBase64(s string) string {
}
return string(out[:k])
}
// This is a subset of the formats allowed by the regular expression
// defined at http://yaml.org/type/timestamp.html.
var allowedTimestampFormats = []string{
"2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields.
"2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t".
"2006-1-2 15:4:5.999999999", // space separated with no time zone
"2006-1-2", // date only
// Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5"
// from the set of examples.
}
// parseTimestamp parses s as a timestamp string and
// returns the timestamp and reports whether it succeeded.
// Timestamp formats are defined at http://yaml.org/type/timestamp.html
func parseTimestamp(s string) (time.Time, bool) {
// TODO write code to check all the formats supported by
// http://yaml.org/type/timestamp.html instead of using time.Parse.
// Quick check: all date formats start with YYYY-.
i := 0
for ; i < len(s); i++ {
if c := s[i]; c < '0' || c > '9' {
break
}
}
if i != 4 || i == len(s) || s[i] != '-' {
return time.Time{}, false
}
for _, format := range allowedTimestampFormats {
if t, err := time.Parse(format, s); err == nil {
return t, true
}
}
return time.Time{}, false
}

29
vendor/gopkg.in/yaml.v2/scannerc.go generated vendored
View file

@ -871,12 +871,6 @@ func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
required := parser.flow_level == 0 && parser.indent == parser.mark.column
// A simple key is required only when it is the first token in the current
// line. Therefore it is always allowed. But we add a check anyway.
if required && !parser.simple_key_allowed {
panic("should not happen")
}
//
// If the current position may start a simple key, save it.
//
@ -2475,6 +2469,10 @@ func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, si
}
}
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
return false
}
// Check if we are at the end of the scalar.
if single {
if parser.buffer[parser.buffer_pos] == '\'' {
@ -2487,10 +2485,6 @@ func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, si
}
// Consume blank characters.
if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) {
return false
}
for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
if is_blank(parser.buffer, parser.buffer_pos) {
// Consume a space or a tab character.
@ -2592,19 +2586,10 @@ func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) b
// Consume non-blank characters.
for !is_blankz(parser.buffer, parser.buffer_pos) {
// Check for 'x:x' in the flow context. TODO: Fix the test "spec-08-13".
if parser.flow_level > 0 &&
parser.buffer[parser.buffer_pos] == ':' &&
!is_blankz(parser.buffer, parser.buffer_pos+1) {
yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
start_mark, "found unexpected ':'")
return false
}
// Check for indicators that may end a plain scalar.
if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) ||
(parser.flow_level > 0 &&
(parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == ':' ||
(parser.buffer[parser.buffer_pos] == ',' ||
parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' ||
parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' ||
parser.buffer[parser.buffer_pos] == '}')) {
@ -2656,10 +2641,10 @@ func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) b
for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) {
if is_blank(parser.buffer, parser.buffer_pos) {
// Check for tab character that abuse indentation.
// Check for tab characters that abuse indentation.
if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) {
yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
start_mark, "found a tab character that violate indentation")
start_mark, "found a tab character that violates indentation")
return false
}

9
vendor/gopkg.in/yaml.v2/sorter.go generated vendored
View file

@ -51,6 +51,15 @@ func (l keyList) Less(i, j int) bool {
}
var ai, bi int
var an, bn int64
if ar[i] == '0' || br[i] == '0' {
for j := i-1; j >= 0 && unicode.IsDigit(ar[j]); j-- {
if ar[j] != '0' {
an = 1
bn = 1
break
}
}
}
for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ {
an = an*10 + int64(ar[ai]-'0')
}

View file

@ -1,12 +0,0 @@
package yaml_test
import (
. "gopkg.in/check.v1"
"testing"
)
func Test(t *testing.T) { TestingT(t) }
type S struct{}
var _ = Suite(&S{})

65
vendor/gopkg.in/yaml.v2/writerc.go generated vendored
View file

@ -18,72 +18,9 @@ func yaml_emitter_flush(emitter *yaml_emitter_t) bool {
return true
}
// If the output encoding is UTF-8, we don't need to recode the buffer.
if emitter.encoding == yaml_UTF8_ENCODING {
if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil {
return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
}
emitter.buffer_pos = 0
return true
}
// Recode the buffer into the raw buffer.
var low, high int
if emitter.encoding == yaml_UTF16LE_ENCODING {
low, high = 0, 1
} else {
high, low = 1, 0
}
pos := 0
for pos < emitter.buffer_pos {
// See the "reader.c" code for more details on UTF-8 encoding. Note
// that we assume that the buffer contains a valid UTF-8 sequence.
// Read the next UTF-8 character.
octet := emitter.buffer[pos]
var w int
var value rune
switch {
case octet&0x80 == 0x00:
w, value = 1, rune(octet&0x7F)
case octet&0xE0 == 0xC0:
w, value = 2, rune(octet&0x1F)
case octet&0xF0 == 0xE0:
w, value = 3, rune(octet&0x0F)
case octet&0xF8 == 0xF0:
w, value = 4, rune(octet&0x07)
}
for k := 1; k < w; k++ {
octet = emitter.buffer[pos+k]
value = (value << 6) + (rune(octet) & 0x3F)
}
pos += w
// Write the character.
if value < 0x10000 {
var b [2]byte
b[high] = byte(value >> 8)
b[low] = byte(value & 0xFF)
emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1])
} else {
// Write the character using a surrogate pair (check "reader.c").
var b [4]byte
value -= 0x10000
b[high] = byte(0xD8 + (value >> 18))
b[low] = byte((value >> 10) & 0xFF)
b[high+2] = byte(0xDC + ((value >> 8) & 0xFF))
b[low+2] = byte(value & 0xFF)
emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1], b[2], b[3])
}
}
// Write the raw buffer.
if err := emitter.write_handler(emitter, emitter.raw_buffer); err != nil {
if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil {
return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
}
emitter.buffer_pos = 0
emitter.raw_buffer = emitter.raw_buffer[:0]
return true
}

125
vendor/gopkg.in/yaml.v2/yaml.go generated vendored
View file

@ -9,6 +9,7 @@ package yaml
import (
"errors"
"fmt"
"io"
"reflect"
"strings"
"sync"
@ -81,12 +82,58 @@ func Unmarshal(in []byte, out interface{}) (err error) {
}
// UnmarshalStrict is like Unmarshal except that any fields that are found
// in the data that do not have corresponding struct members will result in
// in the data that do not have corresponding struct members, or mapping
// keys that are duplicates, will result in
// an error.
func UnmarshalStrict(in []byte, out interface{}) (err error) {
return unmarshal(in, out, true)
}
// A Decorder reads and decodes YAML values from an input stream.
type Decoder struct {
strict bool
parser *parser
}
// NewDecoder returns a new decoder that reads from r.
//
// The decoder introduces its own buffering and may read
// data from r beyond the YAML values requested.
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{
parser: newParserFromReader(r),
}
}
// SetStrict sets whether strict decoding behaviour is enabled when
// decoding items in the data (see UnmarshalStrict). By default, decoding is not strict.
func (dec *Decoder) SetStrict(strict bool) {
dec.strict = strict
}
// Decode reads the next YAML-encoded value from its input
// and stores it in the value pointed to by v.
//
// See the documentation for Unmarshal for details about the
// conversion of YAML into a Go value.
func (dec *Decoder) Decode(v interface{}) (err error) {
d := newDecoder(dec.strict)
defer handleErr(&err)
node := dec.parser.parse()
if node == nil {
return io.EOF
}
out := reflect.ValueOf(v)
if out.Kind() == reflect.Ptr && !out.IsNil() {
out = out.Elem()
}
d.unmarshal(node, out)
if len(d.terrors) > 0 {
return &TypeError{d.terrors}
}
return nil
}
func unmarshal(in []byte, out interface{}, strict bool) (err error) {
defer handleErr(&err)
d := newDecoder(strict)
@ -110,8 +157,8 @@ func unmarshal(in []byte, out interface{}, strict bool) (err error) {
// of the generated document will reflect the structure of the value itself.
// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
//
// Struct fields are only unmarshalled if they are exported (have an upper case
// first letter), and are unmarshalled using the field name lowercased as the
// Struct fields are only marshalled if they are exported (have an upper case
// first letter), and are marshalled using the field name lowercased as the
// default key. Custom keys may be defined via the "yaml" name in the field
// tag: the content preceding the first comma is used as the key, and the
// following comma-separated options are used to tweak the marshalling process.
@ -125,7 +172,10 @@ func unmarshal(in []byte, out interface{}, strict bool) (err error) {
//
// omitempty Only include the field if it's not set to the zero
// value for the type or to empty slices or maps.
// Does not apply to zero valued structs.
// Zero valued structs will be omitted if all their public
// fields are zero, unless they implement an IsZero
// method (see the IsZeroer interface type), in which
// case the field will be included if that method returns true.
//
// flow Marshal using a flow style (useful for structs,
// sequences and maps).
@ -140,7 +190,7 @@ func unmarshal(in []byte, out interface{}, strict bool) (err error) {
// For example:
//
// type T struct {
// F int "a,omitempty"
// F int `yaml:"a,omitempty"`
// B int
// }
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
@ -150,12 +200,47 @@ func Marshal(in interface{}) (out []byte, err error) {
defer handleErr(&err)
e := newEncoder()
defer e.destroy()
e.marshal("", reflect.ValueOf(in))
e.marshalDoc("", reflect.ValueOf(in))
e.finish()
out = e.out
return
}
// An Encoder writes YAML values to an output stream.
type Encoder struct {
encoder *encoder
}
// NewEncoder returns a new encoder that writes to w.
// The Encoder should be closed after use to flush all data
// to w.
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{
encoder: newEncoderWithWriter(w),
}
}
// Encode writes the YAML encoding of v to the stream.
// If multiple items are encoded to the stream, the
// second and subsequent document will be preceded
// with a "---" document separator, but the first will not.
//
// See the documentation for Marshal for details about the conversion of Go
// values to YAML.
func (e *Encoder) Encode(v interface{}) (err error) {
defer handleErr(&err)
e.encoder.marshalDoc("", reflect.ValueOf(v))
return nil
}
// Close closes the encoder by writing any remaining data.
// It does not write a stream terminating string "...".
func (e *Encoder) Close() (err error) {
defer handleErr(&err)
e.encoder.finish()
return nil
}
func handleErr(err *error) {
if v := recover(); v != nil {
if e, ok := v.(yamlError); ok {
@ -211,6 +296,9 @@ type fieldInfo struct {
Num int
OmitEmpty bool
Flow bool
// Id holds the unique field identifier, so we can cheaply
// check for field duplicates without maintaining an extra map.
Id int
// Inline holds the field index if the field is part of an inlined struct.
Inline []int
@ -290,6 +378,7 @@ func getStructInfo(st reflect.Type) (*structInfo, error) {
} else {
finfo.Inline = append([]int{i}, finfo.Inline...)
}
finfo.Id = len(fieldsList)
fieldsMap[finfo.Key] = finfo
fieldsList = append(fieldsList, finfo)
}
@ -311,11 +400,16 @@ func getStructInfo(st reflect.Type) (*structInfo, error) {
return nil, errors.New(msg)
}
info.Id = len(fieldsList)
fieldsList = append(fieldsList, info)
fieldsMap[info.Key] = info
}
sinfo = &structInfo{fieldsMap, fieldsList, inlineMap}
sinfo = &structInfo{
FieldsMap: fieldsMap,
FieldsList: fieldsList,
InlineMap: inlineMap,
}
fieldMapMutex.Lock()
structMap[st] = sinfo
@ -323,8 +417,23 @@ func getStructInfo(st reflect.Type) (*structInfo, error) {
return sinfo, nil
}
// IsZeroer is used to check whether an object is zero to
// determine whether it should be omitted when marshaling
// with the omitempty flag. One notable implementation
// is time.Time.
type IsZeroer interface {
IsZero() bool
}
func isZero(v reflect.Value) bool {
switch v.Kind() {
kind := v.Kind()
if z, ok := v.Interface().(IsZeroer); ok {
if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
return true
}
return z.IsZero()
}
switch kind {
case reflect.String:
return len(v.String()) == 0
case reflect.Interface, reflect.Ptr:

30
vendor/gopkg.in/yaml.v2/yamlh.go generated vendored
View file

@ -1,6 +1,7 @@
package yaml
import (
"fmt"
"io"
)
@ -239,6 +240,27 @@ const (
yaml_MAPPING_END_EVENT // A MAPPING-END event.
)
var eventStrings = []string{
yaml_NO_EVENT: "none",
yaml_STREAM_START_EVENT: "stream start",
yaml_STREAM_END_EVENT: "stream end",
yaml_DOCUMENT_START_EVENT: "document start",
yaml_DOCUMENT_END_EVENT: "document end",
yaml_ALIAS_EVENT: "alias",
yaml_SCALAR_EVENT: "scalar",
yaml_SEQUENCE_START_EVENT: "sequence start",
yaml_SEQUENCE_END_EVENT: "sequence end",
yaml_MAPPING_START_EVENT: "mapping start",
yaml_MAPPING_END_EVENT: "mapping end",
}
func (e yaml_event_type_t) String() string {
if e < 0 || int(e) >= len(eventStrings) {
return fmt.Sprintf("unknown event %d", e)
}
return eventStrings[e]
}
// The event structure.
type yaml_event_t struct {
@ -521,9 +543,9 @@ type yaml_parser_t struct {
read_handler yaml_read_handler_t // Read handler.
input_file io.Reader // File input data.
input []byte // String input data.
input_pos int
input_reader io.Reader // File input data.
input []byte // String input data.
input_pos int
eof bool // EOF flag
@ -632,7 +654,7 @@ type yaml_emitter_t struct {
write_handler yaml_write_handler_t // Write handler.
output_buffer *[]byte // String output data.
output_file io.Writer // File output data.
output_writer io.Writer // File output data.
buffer []byte // The working buffer.
buffer_pos int // The current position of the buffer.