From fe18b6f9e0040b00b6647e2226a45d1345b5ae75 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Thu, 15 Jul 2021 01:56:37 -0400 Subject: [PATCH] Swap out sdk/helper libs with implementations in go-secure-stdlib (#12088) * Swap out sdk/helper libs with implementations in go-secure-stdlib * Fix transit batch test --- api/go.mod | 4 +- api/go.sum | 37 +- builtin/logical/transit/path_encrypt_test.go | 68 +- go.mod | 6 +- go.sum | 24 +- sdk/go.mod | 15 +- sdk/go.sum | 37 +- sdk/helper/base62/base62.go | 44 +- sdk/helper/base62/base62_test.go | 31 - sdk/helper/mlock/mlock.go | 13 +- sdk/helper/mlock/mlock_unavail.go | 13 - sdk/helper/mlock/mlock_unix.go | 18 - sdk/helper/parseutil/parseutil.go | 288 +------- sdk/helper/parseutil/parseutil_test.go | 284 -------- sdk/helper/password/password.go | 65 +- sdk/helper/password/password_solaris.go | 55 -- sdk/helper/password/password_test.go | 27 - sdk/helper/password/password_unix.go | 25 - sdk/helper/password/password_windows.go | 48 -- sdk/helper/strutil/strutil.go | 434 +----------- sdk/helper/strutil/strutil_test.go | 666 ------------------- sdk/helper/tlsutil/tlsutil.go | 224 +------ sdk/helper/tlsutil/tlsutil_test.go | 48 -- 23 files changed, 192 insertions(+), 2282 deletions(-) delete mode 100644 sdk/helper/base62/base62_test.go delete mode 100644 sdk/helper/mlock/mlock_unavail.go delete mode 100644 sdk/helper/mlock/mlock_unix.go delete mode 100644 sdk/helper/parseutil/parseutil_test.go delete mode 100644 sdk/helper/password/password_solaris.go delete mode 100644 sdk/helper/password/password_test.go delete mode 100644 sdk/helper/password/password_unix.go delete mode 100644 sdk/helper/password/password_windows.go delete mode 100644 sdk/helper/strutil/strutil_test.go delete mode 100644 sdk/helper/tlsutil/tlsutil_test.go diff --git a/api/go.mod b/api/go.mod index 5e38bc628..76830b187 100644 --- a/api/go.mod +++ b/api/go.mod @@ -16,8 +16,8 @@ require ( github.com/hashicorp/go-rootcerts v1.0.2 github.com/hashicorp/hcl v1.0.0 github.com/hashicorp/vault/sdk v0.2.1 - github.com/mitchellh/mapstructure v1.3.2 - golang.org/x/net v0.0.0-20200602114024-627f9648deb9 + github.com/mitchellh/mapstructure v1.4.1 + golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 gopkg.in/square/go-jose.v2 v2.5.1 ) diff --git a/api/go.sum b/api/go.sum index 5f428a910..735ef9a21 100644 --- a/api/go.sum +++ b/api/go.sum @@ -90,6 +90,14 @@ github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 h1:78ki3QBevHwYrVxnyVeaEz+7WtifHhauYF23es/0KlI= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 h1:nd0HIW15E6FG1MsnArYaHfuw9C2zgzM8LxkG5Ty/788= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -128,8 +136,9 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -168,14 +177,15 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM= -golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -186,12 +196,12 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -205,17 +215,21 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -253,7 +267,8 @@ gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/builtin/logical/transit/path_encrypt_test.go b/builtin/logical/transit/path_encrypt_test.go index b6a772a0a..1842e069a 100644 --- a/builtin/logical/transit/path_encrypt_test.go +++ b/builtin/logical/transit/path_encrypt_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "reflect" + "strings" "testing" "github.com/hashicorp/vault/sdk/logical" @@ -579,9 +580,10 @@ func TestTransit_BatchEncryptionCase12(t *testing.T) { // Test that the fast path function decodeBatchRequestItems behave like mapstructure.Decode() to decode []BatchRequestItem. func TestTransit_decodeBatchRequestItems(t *testing.T) { tests := []struct { - name string - src interface{} - dest []BatchRequestItem + name string + src interface{} + dest []BatchRequestItem + wantErrContains string }{ // basic edge cases of nil values {name: "nil-nil", src: nil, dest: nil}, @@ -611,9 +613,10 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) { dest: []BatchRequestItem{}, }, { - name: "src_plaintext_invalid-dest", - src: []interface{}{map[string]interface{}{"plaintext": 666}}, - dest: []BatchRequestItem{}, + name: "src_plaintext_invalid-dest", + src: []interface{}{map[string]interface{}{"plaintext": 666}}, + dest: []BatchRequestItem{}, + wantErrContains: "expected type 'string', got unconvertible type 'int'", }, { name: "src_ciphertext-dest", @@ -621,9 +624,10 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) { dest: []BatchRequestItem{}, }, { - name: "src_ciphertext_invalid-dest", - src: []interface{}{map[string]interface{}{"ciphertext": 666}}, - dest: []BatchRequestItem{}, + name: "src_ciphertext_invalid-dest", + src: []interface{}{map[string]interface{}{"ciphertext": 666}}, + dest: []BatchRequestItem{}, + wantErrContains: "expected type 'string', got unconvertible type 'int'", }, { name: "src_key_version-dest", @@ -631,14 +635,16 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) { dest: []BatchRequestItem{}, }, { - name: "src_key_version_invalid-dest", - src: []interface{}{map[string]interface{}{"key_version": "666"}}, - dest: []BatchRequestItem{}, + name: "src_key_version_invalid-dest", + src: []interface{}{map[string]interface{}{"key_version": "666"}}, + dest: []BatchRequestItem{}, + wantErrContains: "expected type 'int', got unconvertible type 'string'", }, { - name: "src_key_version_invalid-number-dest", - src: []interface{}{map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "key_version": json.Number("1.1")}}, - dest: []BatchRequestItem{}, + name: "src_key_version_invalid-number-dest", + src: []interface{}{map[string]interface{}{"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA==", "key_version": json.Number("1.1")}}, + dest: []BatchRequestItem{}, + wantErrContains: "error decoding json.Number into [0].key_version", }, { name: "src_nonce-dest", @@ -646,9 +652,10 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) { dest: []BatchRequestItem{}, }, { - name: "src_nonce_invalid-dest", - src: []interface{}{map[string]interface{}{"nonce": 666}}, - dest: []BatchRequestItem{}, + name: "src_nonce_invalid-dest", + src: []interface{}{map[string]interface{}{"nonce": 666}}, + dest: []BatchRequestItem{}, + wantErrContains: "expected type 'string', got unconvertible type 'int'", }, { name: "src_context-dest", @@ -656,9 +663,10 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) { dest: []BatchRequestItem{}, }, { - name: "src_context_invalid-dest", - src: []interface{}{map[string]interface{}{"context": 666}}, - dest: []BatchRequestItem{}, + name: "src_context_invalid-dest", + src: []interface{}{map[string]interface{}{"context": 666}}, + dest: []BatchRequestItem{}, + wantErrContains: "expected type 'string', got unconvertible type 'int'", }, { name: "src_multi_order-dest", @@ -676,7 +684,8 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) { map[string]interface{}{"context": "2", "key_version": "666"}, map[string]interface{}{"context": "3"}, }, - dest: []BatchRequestItem{}, + dest: []BatchRequestItem{}, + wantErrContains: "expected type 'int', got unconvertible type 'string'", }, { name: "src_multi_with_multi_invalid-dest", @@ -685,7 +694,8 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) { map[string]interface{}{"context": "2", "key_version": "666"}, map[string]interface{}{"context": "3", "key_version": "1337"}, }, - dest: []BatchRequestItem{}, + dest: []BatchRequestItem{}, + wantErrContains: "expected type 'int', got unconvertible type 'string'", }, { name: "src_plaintext-nil-nonce", @@ -701,8 +711,16 @@ func TestTransit_decodeBatchRequestItems(t *testing.T) { gotErr := decodeBatchRequestItems(tt.src, &tt.dest) gotDest := tt.dest - if !reflect.DeepEqual(expectedErr, gotErr) { - t.Errorf("decodeBatchRequestItems unexpected error value, want: '%v', got: '%v'", expectedErr, gotErr) + if expectedErr != nil { + if gotErr == nil { + t.Fatal("decodeBatchRequestItems unexpected error value; expected error but got none") + } + if tt.wantErrContains == "" { + t.Fatal("missing error condition") + } + if !strings.Contains(gotErr.Error(), tt.wantErrContains) { + t.Errorf("decodeBatchRequestItems unexpected error value, want err contains: '%v', got: '%v'", tt.wantErrContains, gotErr) + } } if !reflect.DeepEqual(expectedDest, gotDest) { diff --git a/go.mod b/go.mod index 0f6ddef91..9c6afa995 100644 --- a/go.mod +++ b/go.mod @@ -126,7 +126,7 @@ require ( github.com/mitchellh/go-testing-interface v1.14.0 github.com/mitchellh/go-wordwrap v1.0.0 github.com/mitchellh/gox v1.0.1 - github.com/mitchellh/mapstructure v1.3.3 + github.com/mitchellh/mapstructure v1.4.1 github.com/mitchellh/reflectwalk v1.0.1 github.com/mongodb/go-client-mongodb-atlas v0.1.2 github.com/morikuni/aec v1.0.0 // indirect @@ -167,11 +167,11 @@ require ( go.opentelemetry.io/otel/trace v0.20.0 go.uber.org/atomic v1.6.0 go.uber.org/goleak v1.1.10 - golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a + golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 golang.org/x/net v0.0.0-20210510120150-4163338589ed golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c google.golang.org/api v0.29.0 diff --git a/go.sum b/go.sum index c0bc5e5ee..1e4711bd1 100644 --- a/go.sum +++ b/go.sum @@ -349,8 +349,8 @@ github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVB github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.4.0/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60qkgn7rorfQ= github.com/frankban/quicktest v1.4.1/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60qkgn7rorfQ= -github.com/frankban/quicktest v1.10.0 h1:Gfh+GAJZOAoKZsIZeZbdn2JF10kN1XHNvjsvQK8gVkE= github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= +github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU= @@ -622,6 +622,18 @@ github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.1 h1:6KMBnfEv0/kLAz0O76sliN5mXbCDcLfs2kP7ssP7+DQ= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 h1:78ki3QBevHwYrVxnyVeaEz+7WtifHhauYF23es/0KlI= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/password v0.1.1 h1:6JzmBqXprakgFEHwBgdchsjaA9x3GyjdI568bXKxa60= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 h1:nd0HIW15E6FG1MsnArYaHfuw9C2zgzM8LxkG5Ty/788= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1 h1:Yc026VyMyIpq1UWRnakHRG01U8fJm+nEfEmjoAb00n8= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= github.com/hashicorp/go-slug v0.4.1 h1:/jAo8dNuLgSImoLXaX7Od7QB4TfYCVPam+OpAt5bZqc= github.com/hashicorp/go-slug v0.4.1/go.mod h1:I5tq5Lv0E2xcNXNkmx7BSfzi1PsJ2cNjs3cC3LwyhK8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= @@ -897,8 +909,9 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.0.0 h1:ATSdz4NWrmWPOF1CeCBU4sMCno2hgqdbSrRPFWQSVZI= github.com/mitchellh/pointerstructure v1.0.0/go.mod h1:k4XwG94++jLVsSiTxo7qdIfXA9pj9EAeo0QsNNJOLZ8= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -1286,8 +1299,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1455,8 +1469,10 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/sdk/go.mod b/sdk/go.mod index 14592a962..09e9444f1 100644 --- a/sdk/go.mod +++ b/sdk/go.mod @@ -20,6 +20,12 @@ require ( github.com/hashicorp/go-kms-wrapping/entropy v0.1.0 github.com/hashicorp/go-multierror v1.1.0 github.com/hashicorp/go-plugin v1.0.1 + github.com/hashicorp/go-secure-stdlib/base62 v0.1.1 + github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 + github.com/hashicorp/go-secure-stdlib/password v0.1.1 + github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 + github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1 github.com/hashicorp/go-sockaddr v1.0.2 github.com/hashicorp/go-uuid v1.0.2 github.com/hashicorp/go-version v1.2.0 @@ -28,15 +34,14 @@ require ( github.com/hashicorp/vault/api v1.1.1 github.com/mitchellh/copystructure v1.0.0 github.com/mitchellh/go-testing-interface v1.0.0 - github.com/mitchellh/mapstructure v1.3.2 + github.com/mitchellh/mapstructure v1.4.1 github.com/pierrec/lz4 v2.5.2+incompatible github.com/pkg/errors v0.9.1 github.com/ryanuber/go-glob v1.0.0 - github.com/stretchr/testify v1.5.1 + github.com/stretchr/testify v1.7.0 go.uber.org/atomic v1.6.0 - golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 - golang.org/x/net v0.0.0-20200602114024-627f9648deb9 - golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 + golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 + golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 google.golang.org/grpc v1.29.1 google.golang.org/protobuf v1.25.0 ) diff --git a/sdk/go.sum b/sdk/go.sum index 93243448d..60c18746e 100644 --- a/sdk/go.sum +++ b/sdk/go.sum @@ -142,6 +142,18 @@ github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.1 h1:6KMBnfEv0/kLAz0O76sliN5mXbCDcLfs2kP7ssP7+DQ= +github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 h1:cCRo8gK7oq6A2L6LICkUZ+/a5rLiRXFMf1Qd4xSwxTc= +github.com/hashicorp/go-secure-stdlib/mlock v0.1.1/go.mod h1:zq93CJChV6L9QTfGKtfBxKqD7BqqXx5O04A/ns2p5+I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 h1:78ki3QBevHwYrVxnyVeaEz+7WtifHhauYF23es/0KlI= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/password v0.1.1 h1:6JzmBqXprakgFEHwBgdchsjaA9x3GyjdI568bXKxa60= +github.com/hashicorp/go-secure-stdlib/password v0.1.1/go.mod h1:9hH302QllNwu1o2TGYtSk8I8kTAN0ca1EHpwhm5Mmzo= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 h1:nd0HIW15E6FG1MsnArYaHfuw9C2zgzM8LxkG5Ty/788= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1 h1:Yc026VyMyIpq1UWRnakHRG01U8fJm+nEfEmjoAb00n8= +github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -204,8 +216,9 @@ github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdI github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -276,8 +289,9 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -287,8 +301,9 @@ golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -309,8 +324,9 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -338,11 +354,17 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -403,8 +425,9 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= diff --git a/sdk/helper/base62/base62.go b/sdk/helper/base62/base62.go index 36c6bc9a2..981face42 100644 --- a/sdk/helper/base62/base62.go +++ b/sdk/helper/base62/base62.go @@ -1,52 +1,16 @@ -// Package base62 provides utilities for working with base62 strings. -// base62 strings will only contain characters: 0-9, a-z, A-Z +// DEPRECATED: this has been moved to go-secure-stdlib and will be removed package base62 import ( - "crypto/rand" "io" - uuid "github.com/hashicorp/go-uuid" + extbase62 "github.com/hashicorp/go-secure-stdlib/base62" ) -const ( - charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - csLen = byte(len(charset)) -) - -// Random generates a random string using base-62 characters. -// Resulting entropy is ~5.95 bits/character. func Random(length int) (string, error) { - return RandomWithReader(length, rand.Reader) + return extbase62.Random(length) } -// RandomWithReader generates a random string using base-62 characters and a given reader. -// Resulting entropy is ~5.95 bits/character. func RandomWithReader(length int, reader io.Reader) (string, error) { - if length == 0 { - return "", nil - } - output := make([]byte, 0, length) - - // Request a bit more than length to reduce the chance - // of needing more than one batch of random bytes - batchSize := length + length/4 - - for { - buf, err := uuid.GenerateRandomBytesWithReader(batchSize, reader) - if err != nil { - return "", err - } - - for _, b := range buf { - // Avoid bias by using a value range that's a multiple of 62 - if b < (csLen * 4) { - output = append(output, charset[b%csLen]) - - if len(output) == length { - return string(output), nil - } - } - } - } + return extbase62.RandomWithReader(length, reader) } diff --git a/sdk/helper/base62/base62_test.go b/sdk/helper/base62/base62_test.go deleted file mode 100644 index 4cd490237..000000000 --- a/sdk/helper/base62/base62_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package base62 - -import ( - "testing" -) - -func TestRandom(t *testing.T) { - strings := make(map[string]struct{}) - - for i := 0; i < 100000; i++ { - c, err := Random(16) - if err != nil { - t.Fatal(err) - } - if _, ok := strings[c]; ok { - t.Fatalf("Unexpected duplicate string: %s", c) - } - strings[c] = struct{}{} - - } - - for i := 0; i < 3000; i++ { - c, err := Random(i) - if err != nil { - t.Fatal(err) - } - if len(c) != i { - t.Fatalf("Expected length %d, got: %d", i, len(c)) - } - } -} diff --git a/sdk/helper/mlock/mlock.go b/sdk/helper/mlock/mlock.go index 1675633d3..1bbf8a0bb 100644 --- a/sdk/helper/mlock/mlock.go +++ b/sdk/helper/mlock/mlock.go @@ -1,15 +1,14 @@ +// DEPRECATED: this has been moved to go-secure-stdlib and will be removed package mlock -// This should be set by the OS-specific packages to tell whether LockMemory -// is supported or not. -var supported bool +import ( + extmlock "github.com/hashicorp/go-secure-stdlib/mlock" +) -// Supported returns true if LockMemory is functional on this system. func Supported() bool { - return supported + return extmlock.Supported() } -// LockMemory prevents any memory from being swapped to disk. func LockMemory() error { - return lockMemory() + return extmlock.LockMemory() } diff --git a/sdk/helper/mlock/mlock_unavail.go b/sdk/helper/mlock/mlock_unavail.go deleted file mode 100644 index 8084963f7..000000000 --- a/sdk/helper/mlock/mlock_unavail.go +++ /dev/null @@ -1,13 +0,0 @@ -// +build android darwin nacl netbsd plan9 windows - -package mlock - -func init() { - supported = false -} - -func lockMemory() error { - // XXX: No good way to do this on Windows. There is the VirtualLock - // method, but it requires a specific address and offset. - return nil -} diff --git a/sdk/helper/mlock/mlock_unix.go b/sdk/helper/mlock/mlock_unix.go deleted file mode 100644 index af0a69d48..000000000 --- a/sdk/helper/mlock/mlock_unix.go +++ /dev/null @@ -1,18 +0,0 @@ -// +build dragonfly freebsd linux openbsd solaris - -package mlock - -import ( - "syscall" - - "golang.org/x/sys/unix" -) - -func init() { - supported = true -} - -func lockMemory() error { - // Mlockall prevents all current and future pages from being swapped out. - return unix.Mlockall(syscall.MCL_CURRENT | syscall.MCL_FUTURE) -} diff --git a/sdk/helper/parseutil/parseutil.go b/sdk/helper/parseutil/parseutil.go index 405f37709..eda539424 100644 --- a/sdk/helper/parseutil/parseutil.go +++ b/sdk/helper/parseutil/parseutil.go @@ -1,309 +1,41 @@ +// DEPRECATED: this has been moved to go-secure-stdlib and will be removed package parseutil import ( - "encoding/json" - "errors" - "fmt" - "regexp" - "strconv" - "strings" "time" - "github.com/hashicorp/errwrap" + extparseutil "github.com/hashicorp/go-secure-stdlib/parseutil" sockaddr "github.com/hashicorp/go-sockaddr" - "github.com/hashicorp/vault/sdk/helper/strutil" - "github.com/mitchellh/mapstructure" ) -var validCapacityString = regexp.MustCompile("^[\t ]*([0-9]+)[\t ]?([kmgtKMGT][iI]?[bB])?[\t ]*$") - -// ParseCapacityString parses a capacity string and returns the number of bytes it represents. -// Capacity strings are things like 5gib or 10MB. Supported prefixes are kb, kib, mb, mib, gb, -// gib, tb, tib, which are not case sensitive. If no prefix is present, the number is assumed -// to be in bytes already. func ParseCapacityString(in interface{}) (uint64, error) { - var cap uint64 - - jsonIn, ok := in.(json.Number) - if ok { - in = jsonIn.String() - } - - switch inp := in.(type) { - case nil: - // return default of zero - case string: - if inp == "" { - return cap, nil - } - - matches := validCapacityString.FindStringSubmatch(inp) - - // no sub-groups means we couldn't parse it - if len(matches) <= 1 { - return cap, errors.New("could not parse capacity from input") - } - - var multiplier uint64 = 1 - switch strings.ToLower(matches[2]) { - case "kb": - multiplier = 1000 - case "kib": - multiplier = 1024 - case "mb": - multiplier = 1000 * 1000 - case "mib": - multiplier = 1024 * 1024 - case "gb": - multiplier = 1000 * 1000 * 1000 - case "gib": - multiplier = 1024 * 1024 * 1024 - case "tb": - multiplier = 1000 * 1000 * 1000 * 1000 - case "tib": - multiplier = 1024 * 1024 * 1024 * 1024 - } - - size, err := strconv.ParseUint(matches[1], 10, 64) - if err != nil { - return cap, err - } - - cap = size * multiplier - case int: - cap = uint64(inp) - case int32: - cap = uint64(inp) - case int64: - cap = uint64(inp) - case uint: - cap = uint64(inp) - case uint32: - cap = uint64(inp) - case uint64: - cap = uint64(inp) - case float32: - cap = uint64(inp) - case float64: - cap = uint64(inp) - default: - return cap, errors.New("could not parse capacity from input") - } - - return cap, nil + return extparseutil.ParseCapacityString(in) } func ParseDurationSecond(in interface{}) (time.Duration, error) { - var dur time.Duration - jsonIn, ok := in.(json.Number) - if ok { - in = jsonIn.String() - } - switch inp := in.(type) { - case nil: - // return default of zero - case string: - if inp == "" { - return dur, nil - } - var err error - // Look for a suffix otherwise its a plain second value - if strings.HasSuffix(inp, "s") || strings.HasSuffix(inp, "m") || strings.HasSuffix(inp, "h") || strings.HasSuffix(inp, "ms") { - dur, err = time.ParseDuration(inp) - if err != nil { - return dur, err - } - } else { - // Plain integer - secs, err := strconv.ParseInt(inp, 10, 64) - if err != nil { - return dur, err - } - dur = time.Duration(secs) * time.Second - } - case int: - dur = time.Duration(inp) * time.Second - case int32: - dur = time.Duration(inp) * time.Second - case int64: - dur = time.Duration(inp) * time.Second - case uint: - dur = time.Duration(inp) * time.Second - case uint32: - dur = time.Duration(inp) * time.Second - case uint64: - dur = time.Duration(inp) * time.Second - case float32: - dur = time.Duration(inp) * time.Second - case float64: - dur = time.Duration(inp) * time.Second - case time.Duration: - dur = inp - default: - return 0, errors.New("could not parse duration from input") - } - - return dur, nil + return extparseutil.ParseDurationSecond(in) } func ParseAbsoluteTime(in interface{}) (time.Time, error) { - var t time.Time - switch inp := in.(type) { - case nil: - // return default of zero - return t, nil - case string: - // Allow RFC3339 with nanoseconds, or without, - // or an epoch time as an integer. - var err error - t, err = time.Parse(time.RFC3339Nano, inp) - if err == nil { - break - } - t, err = time.Parse(time.RFC3339, inp) - if err == nil { - break - } - epochTime, err := strconv.ParseInt(inp, 10, 64) - if err == nil { - t = time.Unix(epochTime, 0) - break - } - return t, errors.New("could not parse string as date and time") - case json.Number: - epochTime, err := inp.Int64() - if err != nil { - return t, err - } - t = time.Unix(epochTime, 0) - case int: - t = time.Unix(int64(inp), 0) - case int32: - t = time.Unix(int64(inp), 0) - case int64: - t = time.Unix(inp, 0) - case uint: - t = time.Unix(int64(inp), 0) - case uint32: - t = time.Unix(int64(inp), 0) - case uint64: - t = time.Unix(int64(inp), 0) - default: - return t, errors.New("could not parse time from input type") - } - return t, nil + return extparseutil.ParseAbsoluteTime(in) } func ParseInt(in interface{}) (int64, error) { - var ret int64 - jsonIn, ok := in.(json.Number) - if ok { - in = jsonIn.String() - } - switch in.(type) { - case string: - inp := in.(string) - if inp == "" { - return 0, nil - } - var err error - left, err := strconv.ParseInt(inp, 10, 64) - if err != nil { - return ret, err - } - ret = left - case int: - ret = int64(in.(int)) - case int32: - ret = int64(in.(int32)) - case int64: - ret = in.(int64) - case uint: - ret = int64(in.(uint)) - case uint32: - ret = int64(in.(uint32)) - case uint64: - ret = int64(in.(uint64)) - default: - return 0, errors.New("could not parse value from input") - } - - return ret, nil + return extparseutil.ParseInt(in) } func ParseBool(in interface{}) (bool, error) { - var result bool - if err := mapstructure.WeakDecode(in, &result); err != nil { - return false, err - } - return result, nil + return extparseutil.ParseBool(in) } func ParseString(in interface{}) (string, error) { - var result string - if err := mapstructure.WeakDecode(in, &result); err != nil { - return "", err - } - return result, nil + return extparseutil.ParseString(in) } func ParseCommaStringSlice(in interface{}) ([]string, error) { - rawString, ok := in.(string) - if ok && rawString == "" { - return []string{}, nil - } - var result []string - config := &mapstructure.DecoderConfig{ - Result: &result, - WeaklyTypedInput: true, - DecodeHook: mapstructure.StringToSliceHookFunc(","), - } - decoder, err := mapstructure.NewDecoder(config) - if err != nil { - return nil, err - } - if err := decoder.Decode(in); err != nil { - return nil, err - } - return strutil.TrimStrings(result), nil + return extparseutil.ParseCommaStringSlice(in) } func ParseAddrs(addrs interface{}) ([]*sockaddr.SockAddrMarshaler, error) { - out := make([]*sockaddr.SockAddrMarshaler, 0) - stringAddrs := make([]string, 0) - - switch addrs.(type) { - case string: - stringAddrs = strutil.ParseArbitraryStringSlice(addrs.(string), ",") - if len(stringAddrs) == 0 { - return nil, fmt.Errorf("unable to parse addresses from %v", addrs) - } - - case []string: - stringAddrs = addrs.([]string) - - case []interface{}: - for _, v := range addrs.([]interface{}) { - stringAddr, ok := v.(string) - if !ok { - return nil, fmt.Errorf("error parsing %v as string", v) - } - stringAddrs = append(stringAddrs, stringAddr) - } - - default: - return nil, fmt.Errorf("unknown address input type %T", addrs) - } - - for _, addr := range stringAddrs { - sa, err := sockaddr.NewSockAddr(addr) - if err != nil { - return nil, errwrap.Wrapf(fmt.Sprintf("error parsing address %q: {{err}}", addr), err) - } - out = append(out, &sockaddr.SockAddrMarshaler{ - SockAddr: sa, - }) - } - - return out, nil + return extparseutil.ParseAddrs(addrs) } diff --git a/sdk/helper/parseutil/parseutil_test.go b/sdk/helper/parseutil/parseutil_test.go deleted file mode 100644 index a53df904b..000000000 --- a/sdk/helper/parseutil/parseutil_test.go +++ /dev/null @@ -1,284 +0,0 @@ -package parseutil - -import ( - "encoding/json" - "testing" - "time" -) - -func Test_ParseCapacityString(t *testing.T) { - testCases := []struct { - name string - inp interface{} - valid bool - expected uint64 - }{ - { - "bare number as an int", - 5, - true, - uint64(5), - }, - { - "bare number as a float", - 5.0, - true, - uint64(5), - }, - { - "bare number as a string", - "5", - true, - uint64(5), - }, - { - "string", - "haha", - false, - uint64(0), - }, - { - "random data structure", - struct{}{}, - false, - uint64(0), - }, - { - "kb", - "5kb", - true, - uint64(5000), - }, - { - "kib", - "5kib", - true, - uint64(5120), - }, - { - "KB", - "5KB", - true, - uint64(5000), - }, - { - "KIB", - "5KIB", - true, - uint64(5120), - }, - { - "kB", - "5kB", - true, - uint64(5000), - }, - { - "Kb", - "5Kb", - true, - uint64(5000), - }, - { - "space kb", - "5 kb", - true, - uint64(5000), - }, - { - "space KB", - "5 KB", - true, - uint64(5000), - }, - { - "kb surrounding spaces", - " 5 kb ", - true, - uint64(5000), - }, - { - "mb", - "5mb", - true, - uint64(5000000), - }, - { - "mib", - "5mib", - true, - uint64(5242880), - }, - { - "gb", - "5gb", - true, - uint64(5000000000), - }, - { - "gib", - "5gib", - true, - uint64(5368709120), - }, - { - "tb", - "5tb", - true, - uint64(5000000000000), - }, - { - "tib", - "5tib", - true, - uint64(5497558138880), - }, - } - - for _, tc := range testCases { - tc := tc - - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - - outp, err := ParseCapacityString(tc.inp) - if tc.valid && err != nil { - t.Errorf("failed to parse: %v. err: %v", tc.inp, err) - } - if !tc.valid && err == nil { - t.Errorf("no error for: %v", tc.inp) - } - if outp != tc.expected { - t.Errorf("input %v parsed as %v, expected %v", tc.inp, outp, tc.expected) - } - }) - } -} - -func Test_ParseDurationSecond(t *testing.T) { - outp, err := ParseDurationSecond("9876s") - if err != nil { - t.Fatal(err) - } - if outp != time.Duration(9876)*time.Second { - t.Fatal("not equivalent") - } - outp, err = ParseDurationSecond("9876") - if err != nil { - t.Fatal(err) - } - if outp != time.Duration(9876)*time.Second { - t.Fatal("not equivalent") - } - outp, err = ParseDurationSecond(json.Number("4352")) - if err != nil { - t.Fatal(err) - } - if outp != time.Duration(4352)*time.Second { - t.Fatal("not equivalent") - } -} - -func Test_ParseAbsoluteTime(t *testing.T) { - testCases := []struct { - inp interface{} - valid bool - expected time.Time - }{ - { - "2020-12-11T09:08:07.654321Z", - true, - time.Date(2020, 12, 11, 9, 8, 7, 654321000, time.UTC), - }, - { - "2020-12-11T09:08:07+02:00", - true, - time.Date(2020, 12, 11, 7, 8, 7, 0, time.UTC), - }, - { - "2021-12-11T09:08:07Z", - true, - time.Date(2021, 12, 11, 9, 8, 7, 0, time.UTC), - }, - { - "2021-12-11T09:08:07", - false, - time.Time{}, - }, - { - "1670749687", - true, - time.Date(2022, 12, 11, 9, 8, 7, 0, time.UTC), - }, - { - 1670749687, - true, - time.Date(2022, 12, 11, 9, 8, 7, 0, time.UTC), - }, - { - uint32(1670749687), - true, - time.Date(2022, 12, 11, 9, 8, 7, 0, time.UTC), - }, - { - json.Number("1670749687"), - true, - time.Date(2022, 12, 11, 9, 8, 7, 0, time.UTC), - }, - { - nil, - true, - time.Time{}, - }, - { - struct{}{}, - false, - time.Time{}, - }, - { - true, - false, - time.Time{}, - }, - } - for _, tc := range testCases { - outp, err := ParseAbsoluteTime(tc.inp) - if err != nil { - if tc.valid { - t.Errorf("failed to parse: %v", tc.inp) - } - continue - } - if err == nil && !tc.valid { - t.Errorf("no error for: %v", tc.inp) - continue - } - if !outp.Equal(tc.expected) { - t.Errorf("input %v parsed as %v, expected %v", tc.inp, outp, tc.expected) - } - } -} - -func Test_ParseBool(t *testing.T) { - outp, err := ParseBool("true") - if err != nil { - t.Fatal(err) - } - if !outp { - t.Fatal("wrong output") - } - outp, err = ParseBool(1) - if err != nil { - t.Fatal(err) - } - if !outp { - t.Fatal("wrong output") - } - outp, err = ParseBool(true) - if err != nil { - t.Fatal(err) - } - if !outp { - t.Fatal("wrong output") - } -} diff --git a/sdk/helper/password/password.go b/sdk/helper/password/password.go index 641da8239..84e6b594d 100644 --- a/sdk/helper/password/password.go +++ b/sdk/helper/password/password.go @@ -1,69 +1,14 @@ -// password is a package for reading a password securely from a terminal. -// The code in this package disables echo in the terminal so that the -// password is not echoed back in plaintext to the user. +// DEPRECATED: this has been moved to go-secure-stdlib and will be removed package password import ( - "errors" - "io" "os" - "os/signal" - "strings" + + extpassword "github.com/hashicorp/go-secure-stdlib/password" ) -var ErrInterrupted = errors.New("interrupted") +var ErrInterrupted = extpassword.ErrInterrupted -// Read reads the password from the given os.File. The password -// will not be echoed back to the user. Ctrl-C will automatically return -// from this function with a blank string and an ErrInterrupted. func Read(f *os.File) (string, error) { - ch := make(chan os.Signal, 1) - signal.Notify(ch, os.Interrupt) - defer signal.Stop(ch) - - // Run the actual read in a go-routine so that we can still detect signals - var result string - var resultErr error - doneCh := make(chan struct{}) - go func() { - defer close(doneCh) - result, resultErr = read(f) - }() - - // Wait on either the read to finish or the signal to come through - select { - case <-ch: - return "", ErrInterrupted - case <-doneCh: - return removeiTermDelete(result), resultErr - } -} - -func readline(f *os.File) (string, error) { - var buf [1]byte - resultBuf := make([]byte, 0, 64) - for { - n, err := f.Read(buf[:]) - if err != nil && err != io.EOF { - return "", err - } - if n == 0 || buf[0] == '\n' || buf[0] == '\r' { - break - } - - // ASCII code 3 is what is sent for a Ctrl-C while reading raw. - // If we see that, then get the interrupt. We have to do this here - // because terminals in raw mode won't catch it at the shell level. - if buf[0] == 3 { - return "", ErrInterrupted - } - - resultBuf = append(resultBuf, buf[0]) - } - - return string(resultBuf), nil -} - -func removeiTermDelete(input string) string { - return strings.TrimPrefix(input, "\x20\x7f") + return extpassword.Read(f) } diff --git a/sdk/helper/password/password_solaris.go b/sdk/helper/password/password_solaris.go deleted file mode 100644 index 66ec86dbc..000000000 --- a/sdk/helper/password/password_solaris.go +++ /dev/null @@ -1,55 +0,0 @@ -// +build solaris - -package password - -import ( - "fmt" - "os" - "syscall" - - "golang.org/x/sys/unix" -) - -func read(f *os.File) (string, error) { - fd := int(f.Fd()) - if !isTerminal(fd) { - return "", fmt.Errorf("file descriptor %d is not a terminal", fd) - } - - oldState, err := makeRaw(fd) - if err != nil { - return "", err - } - defer unix.IoctlSetTermios(fd, unix.TCSETS, oldState) - - return readline(f) -} - -// isTerminal returns true if there is a terminal attached to the given -// file descriptor. -// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c -func isTerminal(fd int) bool { - var termio unix.Termio - err := unix.IoctlSetTermio(fd, unix.TCGETA, &termio) - return err == nil -} - -// makeRaw puts the terminal connected to the given file descriptor into raw -// mode and returns the previous state of the terminal so that it can be -// restored. -// Source: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c -func makeRaw(fd int) (*unix.Termios, error) { - oldTermiosPtr, err := unix.IoctlGetTermios(int(fd), unix.TCGETS) - if err != nil { - return nil, err - } - oldTermios := *oldTermiosPtr - - newTermios := oldTermios - newTermios.Lflag &^= syscall.ECHO | syscall.ECHOE | syscall.ECHOK | syscall.ECHONL - if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil { - return nil, err - } - - return oldTermiosPtr, nil -} diff --git a/sdk/helper/password/password_test.go b/sdk/helper/password/password_test.go deleted file mode 100644 index 05022c22c..000000000 --- a/sdk/helper/password/password_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package password - -import "testing" - -type testCase struct { - name string - input string - expected string -} - -func TestRemoveiTermDelete(t *testing.T) { - tests := []testCase{ - {"NoDelete", "TestingStuff", "TestingStuff"}, - {"SingleDelete", "Testing\x7fStuff", "Testing\x7fStuff"}, - {"DeleteFirst", "\x7fTestingStuff", "\x7fTestingStuff"}, - {"DoubleDelete", "\x7f\x7fTestingStuff", "\x7f\x7fTestingStuff"}, - {"SpaceFirst", "\x20TestingStuff", "\x20TestingStuff"}, - {"iTermDelete", "\x20\x7fTestingStuff", "TestingStuff"}, - } - - for _, test := range tests { - result := removeiTermDelete(test.input) - if result != test.expected { - t.Errorf("Test %s failed, input: '%s', expected: '%s', output: '%s'", test.name, test.input, test.expected, result) - } - } -} diff --git a/sdk/helper/password/password_unix.go b/sdk/helper/password/password_unix.go deleted file mode 100644 index f22930fb1..000000000 --- a/sdk/helper/password/password_unix.go +++ /dev/null @@ -1,25 +0,0 @@ -// +build linux darwin freebsd netbsd openbsd dragonfly - -package password - -import ( - "fmt" - "os" - - "golang.org/x/crypto/ssh/terminal" -) - -func read(f *os.File) (string, error) { - fd := int(f.Fd()) - if !terminal.IsTerminal(fd) { - return "", fmt.Errorf("file descriptor %d is not a terminal", fd) - } - - oldState, err := terminal.MakeRaw(fd) - if err != nil { - return "", err - } - defer terminal.Restore(fd, oldState) - - return readline(f) -} diff --git a/sdk/helper/password/password_windows.go b/sdk/helper/password/password_windows.go deleted file mode 100644 index 7325698f8..000000000 --- a/sdk/helper/password/password_windows.go +++ /dev/null @@ -1,48 +0,0 @@ -// +build windows - -package password - -import ( - "os" - "syscall" -) - -var ( - kernel32 = syscall.MustLoadDLL("kernel32.dll") - setConsoleModeProc = kernel32.MustFindProc("SetConsoleMode") -) - -// Magic constant from MSDN to control whether characters read are -// repeated back on the console. -// -// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx -const ENABLE_ECHO_INPUT = 0x0004 - -func read(f *os.File) (string, error) { - handle := syscall.Handle(f.Fd()) - - // Grab the old console mode so we can reset it. We defer the reset - // right away because it doesn't matter (it is idempotent). - var oldMode uint32 - if err := syscall.GetConsoleMode(handle, &oldMode); err != nil { - return "", err - } - defer setConsoleMode(handle, oldMode) - - // The new mode is the old mode WITHOUT the echo input flag set. - var newMode uint32 = uint32(int(oldMode) & ^ENABLE_ECHO_INPUT) - if err := setConsoleMode(handle, newMode); err != nil { - return "", err - } - - return readline(f) -} - -func setConsoleMode(console syscall.Handle, mode uint32) error { - r, _, err := setConsoleModeProc.Call(uintptr(console), uintptr(mode)) - if r == 0 { - return err - } - - return nil -} diff --git a/sdk/helper/strutil/strutil.go b/sdk/helper/strutil/strutil.go index 5d0b36b11..09cc9425c 100644 --- a/sdk/helper/strutil/strutil.go +++ b/sdk/helper/strutil/strutil.go @@ -1,480 +1,94 @@ +// DEPRECATED: this has been moved to go-secure-stdlib and will be removed package strutil import ( - "encoding/base64" - "encoding/json" - "fmt" - "sort" - "strings" - - "github.com/hashicorp/errwrap" - glob "github.com/ryanuber/go-glob" + extstrutil "github.com/hashicorp/go-secure-stdlib/strutil" ) -// StrListContainsGlob looks for a string in a list of strings and allows -// globs. func StrListContainsGlob(haystack []string, needle string) bool { - for _, item := range haystack { - if glob.Glob(item, needle) { - return true - } - } - return false + return extstrutil.StrListContainsGlob(haystack, needle) } -// StrListContains looks for a string in a list of strings. func StrListContains(haystack []string, needle string) bool { - for _, item := range haystack { - if item == needle { - return true - } - } - return false + return extstrutil.StrListContains(haystack, needle) } -// StrListContainsCaseInsensitive looks for a string in a list of strings. func StrListContainsCaseInsensitive(haystack []string, needle string) bool { - for _, item := range haystack { - if strings.EqualFold(item, needle) { - return true - } - } - return false + return extstrutil.StrListContainsCaseInsensitive(haystack, needle) } -// StrListSubset checks if a given list is a subset -// of another set func StrListSubset(super, sub []string) bool { - for _, item := range sub { - if !StrListContains(super, item) { - return false - } - } - return true + return extstrutil.StrListSubset(super, sub) } -// ParseDedupAndSortStrings parses a comma separated list of strings -// into a slice of strings. The return slice will be sorted and will -// not contain duplicate or empty items. func ParseDedupAndSortStrings(input string, sep string) []string { - input = strings.TrimSpace(input) - parsed := []string{} - if input == "" { - // Don't return nil - return parsed - } - return RemoveDuplicates(strings.Split(input, sep), false) + return extstrutil.ParseDedupAndSortStrings(input, sep) } -// ParseDedupLowercaseAndSortStrings parses a comma separated list of -// strings into a slice of strings. The return slice will be sorted and -// will not contain duplicate or empty items. The values will be converted -// to lower case. func ParseDedupLowercaseAndSortStrings(input string, sep string) []string { - input = strings.TrimSpace(input) - parsed := []string{} - if input == "" { - // Don't return nil - return parsed - } - return RemoveDuplicates(strings.Split(input, sep), true) + return extstrutil.ParseDedupLowercaseAndSortStrings(input, sep) } -// ParseKeyValues parses a comma separated list of `=` tuples -// into a map[string]string. func ParseKeyValues(input string, out map[string]string, sep string) error { - if out == nil { - return fmt.Errorf("'out is nil") - } - - keyValues := ParseDedupLowercaseAndSortStrings(input, sep) - if len(keyValues) == 0 { - return nil - } - - for _, keyValue := range keyValues { - shards := strings.Split(keyValue, "=") - if len(shards) != 2 { - return fmt.Errorf("invalid format") - } - - key := strings.TrimSpace(shards[0]) - value := strings.TrimSpace(shards[1]) - if key == "" || value == "" { - return fmt.Errorf("invalid pair: key: %q value: %q", key, value) - } - out[key] = value - } - return nil + return extstrutil.ParseKeyValues(input, out, sep) } -// ParseArbitraryKeyValues parses arbitrary tuples. The input -// can be one of the following: -// * JSON string -// * Base64 encoded JSON string -// * Comma separated list of `=` pairs -// * Base64 encoded string containing comma separated list of -// `=` pairs -// -// Input will be parsed into the output parameter, which should -// be a non-nil map[string]string. func ParseArbitraryKeyValues(input string, out map[string]string, sep string) error { - input = strings.TrimSpace(input) - if input == "" { - return nil - } - if out == nil { - return fmt.Errorf("'out' is nil") - } - - // Try to base64 decode the input. If successful, consider the decoded - // value as input. - inputBytes, err := base64.StdEncoding.DecodeString(input) - if err == nil { - input = string(inputBytes) - } - - // Try to JSON unmarshal the input. If successful, consider that the - // metadata was supplied as JSON input. - err = json.Unmarshal([]byte(input), &out) - if err != nil { - // If JSON unmarshalling fails, consider that the input was - // supplied as a comma separated string of 'key=value' pairs. - if err = ParseKeyValues(input, out, sep); err != nil { - return errwrap.Wrapf("failed to parse the input: {{err}}", err) - } - } - - // Validate the parsed input - for key, value := range out { - if key != "" && value == "" { - return fmt.Errorf("invalid value for key %q", key) - } - } - - return nil + return extstrutil.ParseArbitraryKeyValues(input, out, sep) } -// ParseStringSlice parses a `sep`-separated list of strings into a -// []string with surrounding whitespace removed. -// -// The output will always be a valid slice but may be of length zero. func ParseStringSlice(input string, sep string) []string { - input = strings.TrimSpace(input) - if input == "" { - return []string{} - } - - splitStr := strings.Split(input, sep) - ret := make([]string, len(splitStr)) - for i, val := range splitStr { - ret[i] = strings.TrimSpace(val) - } - - return ret + return extstrutil.ParseStringSlice(input, sep) } -// ParseArbitraryStringSlice parses arbitrary string slice. The input -// can be one of the following: -// * JSON string -// * Base64 encoded JSON string -// * `sep` separated list of values -// * Base64-encoded string containing a `sep` separated list of values -// -// Note that the separator is ignored if the input is found to already be in a -// structured format (e.g., JSON) -// -// The output will always be a valid slice but may be of length zero. func ParseArbitraryStringSlice(input string, sep string) []string { - input = strings.TrimSpace(input) - if input == "" { - return []string{} - } - - // Try to base64 decode the input. If successful, consider the decoded - // value as input. - inputBytes, err := base64.StdEncoding.DecodeString(input) - if err == nil { - input = string(inputBytes) - } - - ret := []string{} - - // Try to JSON unmarshal the input. If successful, consider that the - // metadata was supplied as JSON input. - err = json.Unmarshal([]byte(input), &ret) - if err != nil { - // If JSON unmarshalling fails, consider that the input was - // supplied as a separated string of values. - return ParseStringSlice(input, sep) - } - - if ret == nil { - return []string{} - } - - return ret + return extstrutil.ParseArbitraryStringSlice(input, sep) } -// TrimStrings takes a slice of strings and returns a slice of strings -// with trimmed spaces func TrimStrings(items []string) []string { - ret := make([]string, len(items)) - for i, item := range items { - ret[i] = strings.TrimSpace(item) - } - return ret + return extstrutil.TrimStrings(items) } -// RemoveDuplicates removes duplicate and empty elements from a slice of -// strings. This also may convert the items in the slice to lower case and -// returns a sorted slice. func RemoveDuplicates(items []string, lowercase bool) []string { - itemsMap := map[string]bool{} - for _, item := range items { - item = strings.TrimSpace(item) - if lowercase { - item = strings.ToLower(item) - } - if item == "" { - continue - } - itemsMap[item] = true - } - items = make([]string, 0, len(itemsMap)) - for item := range itemsMap { - items = append(items, item) - } - sort.Strings(items) - return items + return extstrutil.RemoveDuplicates(items, lowercase) } -// RemoveDuplicatesStable removes duplicate and empty elements from a slice of -// strings, preserving order (and case) of the original slice. -// In all cases, strings are compared after trimming whitespace -// If caseInsensitive, strings will be compared after ToLower() func RemoveDuplicatesStable(items []string, caseInsensitive bool) []string { - itemsMap := make(map[string]bool, len(items)) - deduplicated := make([]string, 0, len(items)) - - for _, item := range items { - key := strings.TrimSpace(item) - if caseInsensitive { - key = strings.ToLower(key) - } - if key == "" || itemsMap[key] { - continue - } - itemsMap[key] = true - deduplicated = append(deduplicated, item) - } - return deduplicated + return extstrutil.RemoveDuplicatesStable(items, caseInsensitive) } -// RemoveEmpty removes empty elements from a slice of -// strings func RemoveEmpty(items []string) []string { - if len(items) == 0 { - return items - } - itemsSlice := make([]string, 0, len(items)) - for _, item := range items { - if item == "" { - continue - } - itemsSlice = append(itemsSlice, item) - } - return itemsSlice + return extstrutil.RemoveEmpty(items) } -// EquivalentSlices checks whether the given string sets are equivalent, as in, -// they contain the same values. func EquivalentSlices(a, b []string) bool { - if a == nil && b == nil { - return true - } - - if a == nil || b == nil { - return false - } - - // First we'll build maps to ensure unique values - mapA := map[string]bool{} - mapB := map[string]bool{} - for _, keyA := range a { - mapA[keyA] = true - } - for _, keyB := range b { - mapB[keyB] = true - } - - // Now we'll build our checking slices - var sortedA, sortedB []string - for keyA := range mapA { - sortedA = append(sortedA, keyA) - } - for keyB := range mapB { - sortedB = append(sortedB, keyB) - } - sort.Strings(sortedA) - sort.Strings(sortedB) - - // Finally, compare - if len(sortedA) != len(sortedB) { - return false - } - - for i := range sortedA { - if sortedA[i] != sortedB[i] { - return false - } - } - - return true + return extstrutil.EquivalentSlices(a, b) } -// EqualStringMaps tests whether two map[string]string objects are equal. -// Equal means both maps have the same sets of keys and values. This function -// is 6-10x faster than a call to reflect.DeepEqual(). func EqualStringMaps(a, b map[string]string) bool { - if len(a) != len(b) { - return false - } - - for k := range a { - v, ok := b[k] - if !ok || a[k] != v { - return false - } - } - - return true + return extstrutil.EqualStringMaps(a, b) } -// StrListDelete removes the first occurrence of the given item from the slice -// of strings if the item exists. func StrListDelete(s []string, d string) []string { - if s == nil { - return s - } - - for index, element := range s { - if element == d { - return append(s[:index], s[index+1:]...) - } - } - - return s + return extstrutil.StrListDelete(s, d) } -// GlobbedStringsMatch compares item to val with support for a leading and/or -// trailing wildcard '*' in item. func GlobbedStringsMatch(item, val string) bool { - if len(item) < 2 { - return val == item - } - - hasPrefix := strings.HasPrefix(item, "*") - hasSuffix := strings.HasSuffix(item, "*") - - if hasPrefix && hasSuffix { - return strings.Contains(val, item[1:len(item)-1]) - } else if hasPrefix { - return strings.HasSuffix(val, item[1:]) - } else if hasSuffix { - return strings.HasPrefix(val, item[:len(item)-1]) - } - - return val == item + return extstrutil.GlobbedStringsMatch(item, val) } -// AppendIfMissing adds a string to a slice if the given string is not present func AppendIfMissing(slice []string, i string) []string { - if StrListContains(slice, i) { - return slice - } - return append(slice, i) + return extstrutil.AppendIfMissing(slice, i) } -// MergeSlices adds an arbitrary number of slices together, uniquely func MergeSlices(args ...[]string) []string { - all := map[string]struct{}{} - for _, slice := range args { - for _, v := range slice { - all[v] = struct{}{} - } - } - - result := make([]string, 0, len(all)) - for k := range all { - result = append(result, k) - } - sort.Strings(result) - return result + return extstrutil.MergeSlices(args...) } -// Difference returns the set difference (A - B) of the two given slices. The -// result will also remove any duplicated values in set A regardless of whether -// that matches any values in set B. func Difference(a, b []string, lowercase bool) []string { - if len(a) == 0 { - return a - } - if len(b) == 0 { - if !lowercase { - return a - } - newA := make([]string, len(a)) - for i, v := range a { - newA[i] = strings.ToLower(v) - } - return newA - } - - a = RemoveDuplicates(a, lowercase) - b = RemoveDuplicates(b, lowercase) - - itemsMap := map[string]bool{} - for _, aVal := range a { - itemsMap[aVal] = true - } - - // Perform difference calculation - for _, bVal := range b { - if _, ok := itemsMap[bVal]; ok { - itemsMap[bVal] = false - } - } - - items := []string{} - for item, exists := range itemsMap { - if exists { - items = append(items, item) - } - } - sort.Strings(items) - return items + return extstrutil.Difference(a, b, lowercase) } -// GetString attempts to retrieve a value from the provided map and assert that it is a string. If the key does not -// exist in the map, this will return an empty string. If the key exists, but the value is not a string type, this will -// return an error. If no map or key is provied, this will return an error func GetString(m map[string]interface{}, key string) (string, error) { - if m == nil { - return "", fmt.Errorf("missing map") - } - if key == "" { - return "", fmt.Errorf("missing key") - } - - rawVal, ok := m[key] - if !ok { - return "", nil - } - - str, ok := rawVal.(string) - if !ok { - return "", fmt.Errorf("invalid value at %s: is a %T", key, rawVal) - } - return str, nil + return extstrutil.GetString(m, key) } diff --git a/sdk/helper/strutil/strutil_test.go b/sdk/helper/strutil/strutil_test.go deleted file mode 100644 index 8a9410bdb..000000000 --- a/sdk/helper/strutil/strutil_test.go +++ /dev/null @@ -1,666 +0,0 @@ -package strutil - -import ( - "encoding/base64" - "encoding/json" - "reflect" - "testing" -) - -func TestStrUtil_StrListDelete(t *testing.T) { - output := StrListDelete([]string{"item1", "item2", "item3"}, "item1") - if StrListContains(output, "item1") { - t.Fatal("bad: 'item1' should not have been present") - } - - output = StrListDelete([]string{"item1", "item2", "item3"}, "item2") - if StrListContains(output, "item2") { - t.Fatal("bad: 'item2' should not have been present") - } - - output = StrListDelete([]string{"item1", "item2", "item3"}, "item3") - if StrListContains(output, "item3") { - t.Fatal("bad: 'item3' should not have been present") - } - - output = StrListDelete([]string{"item1", "item1", "item3"}, "item1") - if !StrListContains(output, "item1") { - t.Fatal("bad: 'item1' should have been present") - } - - output = StrListDelete(output, "item1") - if StrListContains(output, "item1") { - t.Fatal("bad: 'item1' should not have been present") - } - - output = StrListDelete(output, "random") - if len(output) != 1 { - t.Fatalf("bad: expected: 1, actual: %d", len(output)) - } - - output = StrListDelete(output, "item3") - if StrListContains(output, "item3") { - t.Fatal("bad: 'item3' should not have been present") - } -} - -func TestStrutil_EquivalentSlices(t *testing.T) { - slice1 := []string{"test2", "test1", "test3"} - slice2 := []string{"test3", "test2", "test1"} - if !EquivalentSlices(slice1, slice2) { - t.Fatalf("bad: expected a match") - } - - slice2 = append(slice2, "test4") - if EquivalentSlices(slice1, slice2) { - t.Fatalf("bad: expected a mismatch") - } -} - -func TestStrutil_ListContainsGlob(t *testing.T) { - haystack := []string{ - "dev", - "ops*", - "root/*", - "*-dev", - "_*_", - } - if StrListContainsGlob(haystack, "tubez") { - t.Fatalf("Value shouldn't exist") - } - if !StrListContainsGlob(haystack, "root/test") { - t.Fatalf("Value should exist") - } - if !StrListContainsGlob(haystack, "ops_test") { - t.Fatalf("Value should exist") - } - if !StrListContainsGlob(haystack, "ops") { - t.Fatalf("Value should exist") - } - if !StrListContainsGlob(haystack, "dev") { - t.Fatalf("Value should exist") - } - if !StrListContainsGlob(haystack, "test-dev") { - t.Fatalf("Value should exist") - } - if !StrListContainsGlob(haystack, "_test_") { - t.Fatalf("Value should exist") - } -} - -func TestStrutil_ListContains(t *testing.T) { - haystack := []string{ - "dev", - "ops", - "prod", - "root", - } - if StrListContains(haystack, "tubez") { - t.Fatalf("Bad") - } - if !StrListContains(haystack, "root") { - t.Fatalf("Bad") - } -} - -func TestStrutil_ListSubset(t *testing.T) { - parent := []string{ - "dev", - "ops", - "prod", - "root", - } - child := []string{ - "prod", - "ops", - } - if !StrListSubset(parent, child) { - t.Fatalf("Bad") - } - if !StrListSubset(parent, parent) { - t.Fatalf("Bad") - } - if !StrListSubset(child, child) { - t.Fatalf("Bad") - } - if !StrListSubset(child, nil) { - t.Fatalf("Bad") - } - if StrListSubset(child, parent) { - t.Fatalf("Bad") - } - if StrListSubset(nil, child) { - t.Fatalf("Bad") - } -} - -func TestStrutil_ParseKeyValues(t *testing.T) { - actual := make(map[string]string) - expected := map[string]string{ - "key1": "value1", - "key2": "value2", - } - var input string - var err error - - input = "key1=value1,key2=value2" - err = ParseKeyValues(input, actual, ",") - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expected, actual) { - t.Fatalf("bad: expected: %#v\nactual: %#v", expected, actual) - } - for k := range actual { - delete(actual, k) - } - - input = "key1 = value1, key2 = value2" - err = ParseKeyValues(input, actual, ",") - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expected, actual) { - t.Fatalf("bad: expected: %#v\nactual: %#v", expected, actual) - } - for k := range actual { - delete(actual, k) - } - - input = "key1 = value1, key2 = " - err = ParseKeyValues(input, actual, ",") - if err == nil { - t.Fatalf("expected an error") - } - for k := range actual { - delete(actual, k) - } - - input = "key1 = value1, = value2 " - err = ParseKeyValues(input, actual, ",") - if err == nil { - t.Fatalf("expected an error") - } - for k := range actual { - delete(actual, k) - } - - input = "key1" - err = ParseKeyValues(input, actual, ",") - if err == nil { - t.Fatalf("expected an error") - } -} - -func TestStrutil_ParseArbitraryKeyValues(t *testing.T) { - actual := make(map[string]string) - expected := map[string]string{ - "key1": "value1", - "key2": "value2", - } - var input string - var err error - - // Test = as comma separated string - input = "key1=value1,key2=value2" - err = ParseArbitraryKeyValues(input, actual, ",") - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expected, actual) { - t.Fatalf("bad: expected: %#v\nactual: %#v", expected, actual) - } - for k := range actual { - delete(actual, k) - } - - // Test = as base64 encoded comma separated string - input = base64.StdEncoding.EncodeToString([]byte(input)) - err = ParseArbitraryKeyValues(input, actual, ",") - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expected, actual) { - t.Fatalf("bad: expected: %#v\nactual: %#v", expected, actual) - } - for k := range actual { - delete(actual, k) - } - - // Test JSON encoded = tuples - input = `{"key1":"value1", "key2":"value2"}` - err = ParseArbitraryKeyValues(input, actual, ",") - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expected, actual) { - t.Fatalf("bad: expected: %#v\nactual: %#v", expected, actual) - } - for k := range actual { - delete(actual, k) - } - - // Test base64 encoded JSON string of = tuples - input = base64.StdEncoding.EncodeToString([]byte(input)) - err = ParseArbitraryKeyValues(input, actual, ",") - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expected, actual) { - t.Fatalf("bad: expected: %#v\nactual: %#v", expected, actual) - } - for k := range actual { - delete(actual, k) - } -} - -func TestStrutil_ParseArbitraryStringSlice(t *testing.T) { - input := `CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';GRANT "foo-role" TO "{{name}}";ALTER ROLE "{{name}}" SET search_path = foo;GRANT CONNECT ON DATABASE "postgres" TO "{{name}}";` - - jsonExpected := []string{ - `DO $$ -BEGIN - IF NOT EXISTS (SELECT * FROM pg_catalog.pg_roles WHERE rolname='foo-role') THEN - CREATE ROLE "foo-role"; - CREATE SCHEMA IF NOT EXISTS foo AUTHORIZATION "foo-role"; - ALTER ROLE "foo-role" SET search_path = foo; - GRANT TEMPORARY ON DATABASE "postgres" TO "foo-role"; - GRANT ALL PRIVILEGES ON SCHEMA foo TO "foo-role"; - GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA foo TO "foo-role"; - GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA foo TO "foo-role"; - GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA foo TO "foo-role"; - END IF; -END -$$`, - `CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'`, - `GRANT "foo-role" TO "{{name}}"`, - `ALTER ROLE "{{name}}" SET search_path = foo`, - `GRANT CONNECT ON DATABASE "postgres" TO "{{name}}"`, - ``, - } - - nonJSONExpected := jsonExpected[1:] - - var actual []string - var inputB64 string - var err error - - // Test non-JSON string - actual = ParseArbitraryStringSlice(input, ";") - if !reflect.DeepEqual(nonJSONExpected, actual) { - t.Fatalf("bad: expected:\n%#v\nactual:\n%#v", nonJSONExpected, actual) - } - - // Test base64-encoded non-JSON string - inputB64 = base64.StdEncoding.EncodeToString([]byte(input)) - actual = ParseArbitraryStringSlice(inputB64, ";") - if !reflect.DeepEqual(nonJSONExpected, actual) { - t.Fatalf("bad: expected:\n%#v\nactual:\n%#v", nonJSONExpected, actual) - } - - // Test JSON encoded - inputJSON, err := json.Marshal(jsonExpected) - if err != nil { - t.Fatal(err) - } - - actual = ParseArbitraryStringSlice(string(inputJSON), ";") - if !reflect.DeepEqual(jsonExpected, actual) { - t.Fatalf("bad: expected:\n%#v\nactual:\n%#v", string(inputJSON), actual) - } - - // Test base64 encoded JSON string of = tuples - inputB64 = base64.StdEncoding.EncodeToString(inputJSON) - actual = ParseArbitraryStringSlice(inputB64, ";") - if !reflect.DeepEqual(jsonExpected, actual) { - t.Fatalf("bad: expected:\n%#v\nactual:\n%#v", jsonExpected, actual) - } -} - -func TestGlobbedStringsMatch(t *testing.T) { - type tCase struct { - item string - val string - expect bool - } - - tCases := []tCase{ - {"", "", true}, - {"*", "*", true}, - {"**", "**", true}, - {"*t", "t", true}, - {"*t", "test", true}, - {"t*", "test", true}, - {"*test", "test", true}, - {"*test", "a test", true}, - {"test", "a test", false}, - {"*test", "tests", false}, - {"test*", "test", true}, - {"test*", "testsss", true}, - {"test**", "testsss", false}, - {"test**", "test*", true}, - {"**test", "*test", true}, - {"TEST", "test", false}, - {"test", "test", true}, - } - - for _, tc := range tCases { - actual := GlobbedStringsMatch(tc.item, tc.val) - - if actual != tc.expect { - t.Fatalf("Bad testcase %#v, expected %t, got %t", tc, tc.expect, actual) - } - } -} - -func TestTrimStrings(t *testing.T) { - input := []string{"abc", "123", "abcd ", "123 "} - expected := []string{"abc", "123", "abcd", "123"} - actual := TrimStrings(input) - if !reflect.DeepEqual(expected, actual) { - t.Fatalf("Bad TrimStrings: expected:%#v, got:%#v", expected, actual) - } -} - -func TestRemoveEmpty(t *testing.T) { - input := []string{"abc", "", "abc", ""} - expected := []string{"abc", "abc"} - actual := RemoveEmpty(input) - if !reflect.DeepEqual(expected, actual) { - t.Fatalf("Bad TrimStrings: expected:%#v, got:%#v", expected, actual) - } - - input = []string{""} - expected = []string{} - actual = RemoveEmpty(input) - if !reflect.DeepEqual(expected, actual) { - t.Fatalf("Bad TrimStrings: expected:%#v, got:%#v", expected, actual) - } -} - -func TestStrutil_AppendIfMissing(t *testing.T) { - keys := []string{} - - keys = AppendIfMissing(keys, "foo") - - if len(keys) != 1 { - t.Fatalf("expected slice to be length of 1: %v", keys) - } - if keys[0] != "foo" { - t.Fatalf("expected slice to contain key 'foo': %v", keys) - } - - keys = AppendIfMissing(keys, "bar") - - if len(keys) != 2 { - t.Fatalf("expected slice to be length of 2: %v", keys) - } - if keys[0] != "foo" { - t.Fatalf("expected slice to contain key 'foo': %v", keys) - } - if keys[1] != "bar" { - t.Fatalf("expected slice to contain key 'bar': %v", keys) - } - - keys = AppendIfMissing(keys, "foo") - - if len(keys) != 2 { - t.Fatalf("expected slice to still be length of 2: %v", keys) - } - if keys[0] != "foo" { - t.Fatalf("expected slice to still contain key 'foo': %v", keys) - } - if keys[1] != "bar" { - t.Fatalf("expected slice to still contain key 'bar': %v", keys) - } -} - -func TestStrUtil_RemoveDuplicates(t *testing.T) { - type tCase struct { - input []string - expect []string - lowercase bool - } - - tCases := []tCase{ - {[]string{}, []string{}, false}, - {[]string{}, []string{}, true}, - {[]string{"a", "b", "a"}, []string{"a", "b"}, false}, - {[]string{"A", "b", "a"}, []string{"A", "a", "b"}, false}, - {[]string{"A", "b", "a"}, []string{"a", "b"}, true}, - } - - for _, tc := range tCases { - actual := RemoveDuplicates(tc.input, tc.lowercase) - - if !reflect.DeepEqual(actual, tc.expect) { - t.Fatalf("Bad testcase %#v, expected %v, got %v", tc, tc.expect, actual) - } - } -} - -func TestStrUtil_RemoveDuplicatesStable(t *testing.T) { - type tCase struct { - input []string - expect []string - caseInsensitive bool - } - - tCases := []tCase{ - {[]string{}, []string{}, false}, - {[]string{}, []string{}, true}, - {[]string{"a", "b", "a"}, []string{"a", "b"}, false}, - {[]string{"A", "b", "a"}, []string{"A", "b", "a"}, false}, - {[]string{"A", "b", "a"}, []string{"A", "b"}, true}, - {[]string{" ", "d", "c", "d"}, []string{"d", "c"}, false}, - {[]string{"Z ", " z", " z ", "y"}, []string{"Z ", "y"}, true}, - {[]string{"Z ", " z", " z ", "y"}, []string{"Z ", " z", "y"}, false}, - } - - for _, tc := range tCases { - actual := RemoveDuplicatesStable(tc.input, tc.caseInsensitive) - - if !reflect.DeepEqual(actual, tc.expect) { - t.Fatalf("Bad testcase %#v, expected %v, got %v", tc, tc.expect, actual) - } - } -} - -func TestStrUtil_ParseStringSlice(t *testing.T) { - type tCase struct { - input string - sep string - expect []string - } - - tCases := []tCase{ - {"", "", []string{}}, - {" ", ",", []string{}}, - {", ", ",", []string{"", ""}}, - {"a", ",", []string{"a"}}, - {" a, b, c ", ",", []string{"a", "b", "c"}}, - {" a; b; c ", ";", []string{"a", "b", "c"}}, - {" a :: b :: c ", "::", []string{"a", "b", "c"}}, - } - - for _, tc := range tCases { - actual := ParseStringSlice(tc.input, tc.sep) - - if !reflect.DeepEqual(actual, tc.expect) { - t.Fatalf("Bad testcase %#v, expected %v, got %v", tc, tc.expect, actual) - } - } -} - -func TestStrUtil_MergeSlices(t *testing.T) { - res := MergeSlices([]string{"a", "c", "d"}, []string{}, []string{"c", "f", "a"}, nil, []string{"foo"}) - - expect := []string{"a", "c", "d", "f", "foo"} - - if !reflect.DeepEqual(res, expect) { - t.Fatalf("expected %v, got %v", expect, res) - } -} - -func TestDifference(t *testing.T) { - testCases := []struct { - Name string - SetA []string - SetB []string - Lowercase bool - ExpectedResult []string - }{ - { - Name: "case_sensitive", - SetA: []string{"a", "b", "c"}, - SetB: []string{"b", "c"}, - Lowercase: false, - ExpectedResult: []string{"a"}, - }, - { - Name: "case_insensitive", - SetA: []string{"a", "B", "c"}, - SetB: []string{"b", "C"}, - Lowercase: true, - ExpectedResult: []string{"a"}, - }, - { - Name: "no_match", - SetA: []string{"a", "b", "c"}, - SetB: []string{"d"}, - Lowercase: false, - ExpectedResult: []string{"a", "b", "c"}, - }, - { - Name: "empty_set_a", - SetA: []string{}, - SetB: []string{"d", "e"}, - Lowercase: false, - ExpectedResult: []string{}, - }, - { - Name: "empty_set_b", - SetA: []string{"a", "b"}, - SetB: []string{}, - Lowercase: false, - ExpectedResult: []string{"a", "b"}, - }, - } - - for _, tc := range testCases { - t.Run(tc.Name, func(t *testing.T) { - actualResult := Difference(tc.SetA, tc.SetB, tc.Lowercase) - - if !reflect.DeepEqual(actualResult, tc.ExpectedResult) { - t.Fatalf("expected %v, got %v", tc.ExpectedResult, actualResult) - } - }) - } -} - -func TestStrUtil_EqualStringMaps(t *testing.T) { - m1 := map[string]string{ - "foo": "a", - } - m2 := map[string]string{ - "foo": "a", - "bar": "b", - } - var m3 map[string]string - - m4 := map[string]string{ - "dog": "", - } - - m5 := map[string]string{ - "cat": "", - } - - tests := []struct { - a map[string]string - b map[string]string - result bool - }{ - {m1, m1, true}, - {m2, m2, true}, - {m1, m2, false}, - {m2, m1, false}, - {m2, m2, true}, - {m3, m1, false}, - {m3, m3, true}, - {m4, m5, false}, - } - - for i, test := range tests { - actual := EqualStringMaps(test.a, test.b) - if actual != test.result { - t.Fatalf("case %d, expected %v, got %v", i, test.result, actual) - } - } -} - -func TestGetString(t *testing.T) { - type testCase struct { - m map[string]interface{} - key string - - expectedStr string - expectErr bool - } - - tests := map[string]testCase{ - "nil map": { - m: nil, - key: "foo", - expectedStr: "", - expectErr: true, - }, - "empty key": { - m: map[string]interface{}{ - "foo": "bar", - }, - key: "", - expectedStr: "", - expectErr: true, - }, - "missing key": { - m: map[string]interface{}{ - "foo": "bar", - }, - key: "baz", - expectedStr: "", - expectErr: false, - }, - "value is not a string": { - m: map[string]interface{}{ - "foo": 42, - }, - key: "foo", - expectedStr: "", - expectErr: true, - }, - "happy path": { - m: map[string]interface{}{ - "foo": "bar", - }, - key: "foo", - expectedStr: "bar", - expectErr: false, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actual, err := GetString(test.m, test.key) - if test.expectErr && err == nil { - t.Fatalf("err expected, got nil") - } - if !test.expectErr && err != nil { - t.Fatalf("no error expected, got: %s", err) - } - if actual != test.expectedStr { - t.Fatalf("Actual: [%s] Expected: [%s]", actual, test.expectedStr) - } - }) - } -} diff --git a/sdk/helper/tlsutil/tlsutil.go b/sdk/helper/tlsutil/tlsutil.go index 437d87860..e1e9b9484 100644 --- a/sdk/helper/tlsutil/tlsutil.go +++ b/sdk/helper/tlsutil/tlsutil.go @@ -1,238 +1,32 @@ +// DEPRECATED: this has been moved to go-secure-stdlib and will be removed package tlsutil import ( "crypto/tls" - "crypto/x509" - "errors" - "fmt" - "io/ioutil" - "net" - "strings" - "github.com/hashicorp/errwrap" - "github.com/hashicorp/vault/sdk/helper/parseutil" - "github.com/hashicorp/vault/sdk/helper/strutil" + exttlsutil "github.com/hashicorp/go-secure-stdlib/tlsutil" ) -var ErrInvalidCertParams = errors.New("invalid certificate parameters") +var ErrInvalidCertParams = exttlsutil.ErrInvalidCertParams -// TLSLookup maps the tls_min_version configuration to the internal value -var TLSLookup = map[string]uint16{ - "tls10": tls.VersionTLS10, - "tls11": tls.VersionTLS11, - "tls12": tls.VersionTLS12, - "tls13": tls.VersionTLS13, -} +var TLSLookup = exttlsutil.TLSLookup -// cipherMap maps the cipher suite names to the internal cipher suite code. -var cipherMap = map[string]uint16{ - "TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA, - "TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, - "TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA, - "TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA, - "TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256, - "TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256, - "TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384, - "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - "TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, - "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, - "TLS_AES_128_GCM_SHA256": tls.TLS_AES_128_GCM_SHA256, - "TLS_AES_256_GCM_SHA384": tls.TLS_AES_256_GCM_SHA384, - "TLS_CHACHA20_POLY1305_SHA256": tls.TLS_CHACHA20_POLY1305_SHA256, -} - -// ParseCiphers parse ciphersuites from the comma-separated string into recognized slice func ParseCiphers(cipherStr string) ([]uint16, error) { - suites := []uint16{} - ciphers := strutil.ParseStringSlice(cipherStr, ",") - for _, cipher := range ciphers { - if v, ok := cipherMap[cipher]; ok { - suites = append(suites, v) - } else { - return suites, fmt.Errorf("unsupported cipher %q", cipher) - } - } - - return suites, nil + return exttlsutil.ParseCiphers(cipherStr) } -// GetCipherName returns the name of a given cipher suite code or an error if the -// given cipher is unsupported. func GetCipherName(cipher uint16) (string, error) { - for cipherStr, cipherCode := range cipherMap { - if cipherCode == cipher { - return cipherStr, nil - } - } - return "", fmt.Errorf("unsupported cipher %d", cipher) + return exttlsutil.GetCipherName(cipher) } -// ClientTLSConfig parses the CA certificate, and optionally a public/private -// client certificate key pair. The certificates must be in PEM encoded format. func ClientTLSConfig(caCert []byte, clientCert []byte, clientKey []byte) (*tls.Config, error) { - var tlsConfig *tls.Config - var pool *x509.CertPool - - switch { - case len(caCert) != 0: - // Valid - case len(clientCert) != 0 && len(clientKey) != 0: - // Valid - default: - return nil, ErrInvalidCertParams - } - - if len(caCert) != 0 { - pool = x509.NewCertPool() - pool.AppendCertsFromPEM(caCert) - } - - tlsConfig = &tls.Config{ - RootCAs: pool, - ClientAuth: tls.RequireAndVerifyClientCert, - MinVersion: tls.VersionTLS12, - } - - var cert tls.Certificate - var err error - if len(clientCert) != 0 && len(clientKey) != 0 { - cert, err = tls.X509KeyPair(clientCert, clientKey) - if err != nil { - return nil, err - } - tlsConfig.Certificates = []tls.Certificate{cert} - } - tlsConfig.BuildNameToCertificate() - - return tlsConfig, nil + return exttlsutil.ClientTLSConfig(caCert, clientCert, clientKey) } -// LoadClientTLSConfig loads and parse the CA certificate, and optionally a -// public/private client certificate key pair. The certificates must be in PEM -// encoded format. func LoadClientTLSConfig(caCert, clientCert, clientKey string) (*tls.Config, error) { - var tlsConfig *tls.Config - var pool *x509.CertPool - - switch { - case len(caCert) != 0: - // Valid - case len(clientCert) != 0 && len(clientKey) != 0: - // Valid - default: - return nil, ErrInvalidCertParams - } - - if len(caCert) != 0 { - pool = x509.NewCertPool() - - data, err := ioutil.ReadFile(caCert) - if err != nil { - return nil, errwrap.Wrapf("failed to read CA file: {{err}}", err) - } - - if !pool.AppendCertsFromPEM(data) { - return nil, fmt.Errorf("failed to parse CA certificate") - } - } - - tlsConfig = &tls.Config{ - RootCAs: pool, - ClientAuth: tls.RequireAndVerifyClientCert, - MinVersion: tls.VersionTLS12, - } - - var cert tls.Certificate - var err error - if len(clientCert) != 0 && len(clientKey) != 0 { - cert, err = tls.LoadX509KeyPair(clientCert, clientKey) - if err != nil { - return nil, err - } - tlsConfig.Certificates = []tls.Certificate{cert} - } - tlsConfig.BuildNameToCertificate() - - return tlsConfig, nil + return exttlsutil.LoadClientTLSConfig(caCert, clientCert, clientKey) } func SetupTLSConfig(conf map[string]string, address string) (*tls.Config, error) { - serverName, _, err := net.SplitHostPort(address) - switch { - case err == nil: - case strings.Contains(err.Error(), "missing port"): - serverName = conf["address"] - default: - return nil, err - } - - insecureSkipVerify := false - tlsSkipVerify := conf["tls_skip_verify"] - - if tlsSkipVerify != "" { - b, err := parseutil.ParseBool(tlsSkipVerify) - if err != nil { - return nil, errwrap.Wrapf("failed parsing tls_skip_verify parameter: {{err}}", err) - } - insecureSkipVerify = b - } - - tlsMinVersionStr, ok := conf["tls_min_version"] - if !ok { - // Set the default value - tlsMinVersionStr = "tls12" - } - - tlsMinVersion, ok := TLSLookup[tlsMinVersionStr] - if !ok { - return nil, fmt.Errorf("invalid 'tls_min_version'") - } - - tlsClientConfig := &tls.Config{ - MinVersion: tlsMinVersion, - InsecureSkipVerify: insecureSkipVerify, - ServerName: serverName, - } - - _, okCert := conf["tls_cert_file"] - _, okKey := conf["tls_key_file"] - - if okCert && okKey { - tlsCert, err := tls.LoadX509KeyPair(conf["tls_cert_file"], conf["tls_key_file"]) - if err != nil { - return nil, errwrap.Wrapf("client tls setup failed: {{err}}", err) - } - - tlsClientConfig.Certificates = []tls.Certificate{tlsCert} - } else if okCert || okKey { - return nil, fmt.Errorf("both tls_cert_file and tls_key_file must be provided") - } - - if tlsCaFile, ok := conf["tls_ca_file"]; ok { - caPool := x509.NewCertPool() - - data, err := ioutil.ReadFile(tlsCaFile) - if err != nil { - return nil, errwrap.Wrapf("failed to read CA file: {{err}}", err) - } - - if !caPool.AppendCertsFromPEM(data) { - return nil, fmt.Errorf("failed to parse CA certificate") - } - - tlsClientConfig.RootCAs = caPool - } - return tlsClientConfig, nil + return exttlsutil.SetupTLSConfig(conf, address) } diff --git a/sdk/helper/tlsutil/tlsutil_test.go b/sdk/helper/tlsutil/tlsutil_test.go deleted file mode 100644 index 046760a57..000000000 --- a/sdk/helper/tlsutil/tlsutil_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package tlsutil - -import ( - "crypto/tls" - "reflect" - "testing" -) - -func TestParseCiphers(t *testing.T) { - testOk := "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305" - v, err := ParseCiphers(testOk) - if err != nil { - t.Fatal(err) - } - if len(v) != 17 { - t.Fatal("missed ciphers after parse") - } - - testBad := "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,cipherX" - if _, err := ParseCiphers(testBad); err == nil { - t.Fatal("should fail on unsupported cipherX") - } - - testOrder := "TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256" - v, _ = ParseCiphers(testOrder) - expected := []uint16{tls.TLS_RSA_WITH_AES_256_GCM_SHA384, tls.TLS_RSA_WITH_AES_128_GCM_SHA256} - if !reflect.DeepEqual(expected, v) { - t.Fatal("cipher order is not preserved") - } -} - -func TestGetCipherName(t *testing.T) { - testOkCipherStr := "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA" - testOkCipher := tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - cipherStr, err := GetCipherName(testOkCipher) - if err != nil { - t.Fatal(err) - } - if cipherStr != testOkCipherStr { - t.Fatalf("cipher string should be %s but is %s", testOkCipherStr, cipherStr) - } - - var testBadCipher uint16 = 0xC022 - cipherStr, err = GetCipherName(testBadCipher) - if err == nil { - t.Fatal("should fail on unsupported cipher 0xC022") - } -}