diff --git a/spi/gnap/go.mod b/spi/gnap/go.mod index 2bc5c69..987660c 100644 --- a/spi/gnap/go.mod +++ b/spi/gnap/go.mod @@ -9,21 +9,31 @@ go 1.17 require ( github.com/hyperledger/aries-framework-go v0.1.8 github.com/igor-pavlenko/httpsignatures-go v0.0.23 + github.com/lestrrat-go/jwx/v2 v2.0.0 github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693 github.com/stretchr/testify v1.7.5 + github.com/yaronf/httpsign v0.1.13 ) require ( github.com/btcsuite/btcd v0.22.0-beta // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/dunglas/httpsfv v0.1.1 // indirect + github.com/goccy/go-json v0.9.7 // indirect github.com/google/go-cmp v0.5.5 // indirect github.com/hyperledger/aries-framework-go/spi v0.0.0-20220322085443-50e8f9bd208b // indirect github.com/kilic/bls12-381 v0.1.1-0.20210503002446-7b7597926c69 // indirect github.com/kr/pretty v0.1.0 // indirect + github.com/lestrrat-go/blackmagic v1.0.1 // indirect + github.com/lestrrat-go/httpcc v1.0.1 // indirect + github.com/lestrrat-go/httprc v1.0.1 // indirect + github.com/lestrrat-go/iter v1.0.2 // indirect + github.com/lestrrat-go/option v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/teserakt-io/golang-ed25519 v0.0.0-20210104091850-3888c087a4c8 // indirect - golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect + golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/spi/gnap/go.sum b/spi/gnap/go.sum index 253e8f3..27f0411 100644 --- a/spi/gnap/go.sum +++ b/spi/gnap/go.sum @@ -40,6 +40,8 @@ github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go v1.35.1/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= @@ -74,7 +76,12 @@ github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/dunglas/httpsfv v0.1.1 h1:iV2PWNlj9Qbk+5I3fxPDJPTh9eM0rskrI1qdUVUNK1E= +github.com/dunglas/httpsfv v0.1.1/go.mod h1:zID2mqw9mFsnt7YC3vYQ9/cjq30q41W+1AnDwH8TiMg= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -92,6 +99,8 @@ github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -234,6 +243,18 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80= +github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= +github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= +github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= +github.com/lestrrat-go/httprc v1.0.1 h1:Cnc4NxIySph38pQPzKbjg5OkKsGR/Cf5xcWt5OlSUDI= +github.com/lestrrat-go/httprc v1.0.1/go.mod h1:5Ml+nB++j6IC0e6LzefJnrpMQDKgDwDCaIQQzhbqhJM= +github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= +github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= +github.com/lestrrat-go/jwx/v2 v2.0.0 h1:P0ufz+eqGrKDSIdcTQXRbtOhBZ8gTXG6zlnoc/AH7hM= +github.com/lestrrat-go/jwx/v2 v2.0.0/go.mod h1:6JfwCE7IwHTaUBdNgNUmTYN8Cxi557CjJM764daXDao= +github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4= +github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= @@ -273,6 +294,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693 h1:wD1IWQwAhdWclCwaf6DdzgCAe9Bfz1M+4AHRd7N786Y= github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693/go.mod h1:6hSY48PjDm4UObWmGLyJE9DxYVKTgR9kbCspXXJEhcU= @@ -282,8 +305,10 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf 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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q= github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/teserakt-io/golang-ed25519 v0.0.0-20200315192543-8255be791ce4/go.mod h1:9PdLyPiZIiW3UopXyRnPYyjUXSpiQNHRLu8fOsR3o8M= @@ -297,6 +322,8 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/yaronf/httpsign v0.1.13 h1:07WGHKAwjBEptyEMIXgCRVI/JF07Mov/cUQ1aJUXLzw= +github.com/yaronf/httpsign v0.1.13/go.mod h1:PkvQ/BBzOrL29m4K+LMwwkjCAwcEywfkmWlk4rKuQxA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -318,8 +345,10 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 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= @@ -380,6 +409,7 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -429,6 +459,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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= @@ -439,6 +470,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -571,17 +603,20 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 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.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/spi/gnap/internal/jwksignature/ecdsa_test.go b/spi/gnap/internal/jwksignature/ecdsa_test.go index e3adf1d..fafb05d 100644 --- a/spi/gnap/internal/jwksignature/ecdsa_test.go +++ b/spi/gnap/internal/jwksignature/ecdsa_test.go @@ -21,6 +21,12 @@ import ( "github.com/stretchr/testify/require" ) +const ( + es256Alg = "ES256" + es384Alg = "ES384" + es512Alg = "ES512" +) + func Test_ecdsaSign(t *testing.T) { tests := []struct { name string diff --git a/spi/gnap/internal/jwksignature/jwksignature.go b/spi/gnap/internal/jwksignature/jwksignature.go deleted file mode 100644 index 154bcf5..0000000 --- a/spi/gnap/internal/jwksignature/jwksignature.go +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package jwksignature - -import ( - "crypto/ecdsa" - "errors" - "fmt" - - "github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk" - "github.com/igor-pavlenko/httpsignatures-go" -) - -// SignatureAlgorithm provides http-signature JWK signatures. -type SignatureAlgorithm struct { - alg string -} - -// NewJWKAlgorithm -func NewJWKAlgorithm(alg string) *SignatureAlgorithm { - return &SignatureAlgorithm{ - alg: alg, - } -} - -// Algorithm returns the SignatureAlgorithm's algorithm. -func (s *SignatureAlgorithm) Algorithm() string { - return s.alg -} - -// Create implements http-signatures' Signer API. -func (s *SignatureAlgorithm) Create(secret httpsignatures.Secret, data []byte) ([]byte, error) { - priv := &jwk.JWK{} - - err := priv.UnmarshalJSON([]byte(secret.PrivateKey)) - if err != nil { - return nil, fmt.Errorf("parsing secret into JWK: %w", err) - } - - switch k := priv.Key.(type) { - case *ecdsa.PrivateKey: - return ecdsaSign(data, k, priv.Algorithm) - default: - return nil, errors.New("key type not supported") - } -} - -func (s *SignatureAlgorithm) Verify(secret httpsignatures.Secret, data []byte, signature []byte) error { - pub := &jwk.JWK{} - - // Note: httpsignatures-go uses PrivateKey value to store public key too. - err := pub.UnmarshalJSON([]byte(secret.PrivateKey)) - if err != nil { - return fmt.Errorf("parsing public key into JWK: %w", err) - } - - switch pub.Key.(type) { - case *ecdsa.PublicKey, *ecdsa.PrivateKey: - return ecdsaVerifier(pub, data, signature) - default: - return errors.New("key type not supported") - } -} diff --git a/spi/gnap/internal/jwksignature/jwksignature_test.go b/spi/gnap/internal/jwksignature/jwksignature_test.go deleted file mode 100644 index b26a636..0000000 --- a/spi/gnap/internal/jwksignature/jwksignature_test.go +++ /dev/null @@ -1,221 +0,0 @@ -/* -Copyright SecureKey Technologies Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package jwksignature - -import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "encoding/base64" - "encoding/json" - "fmt" - "testing" - - "github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk" - "github.com/igor-pavlenko/httpsignatures-go" - "github.com/square/go-jose/v3" - "github.com/stretchr/testify/require" -) - -const ( - es256Alg = "ES256" - es384Alg = "ES384" - es512Alg = "ES512" -) - -func TestSignatureAlgorithm_Algorithm(t *testing.T) { - mockAlg := "mock-alg" - - alg := NewJWKAlgorithm(mockAlg) - - require.Equal(t, mockAlg, alg.Algorithm()) -} - -func TestSignatureAlgorithm_Create(t *testing.T) { - t.Run("success", func(t *testing.T) { - _, privData := secretPair(t, es256Alg, elliptic.P256()) - - msg := []byte("the quick brown fox jumps over the lazy dog") - - alg := NewJWKAlgorithm(es256Alg) - - sig, err := alg.Create(privData, msg) - require.NoError(t, err) - require.NotEmpty(t, sig) - }) - - t.Run("unmarshal error", func(t *testing.T) { - privData := httpsignatures.Secret{ - PrivateKey: "foo bar baz", - } - - alg := NewJWKAlgorithm(es256Alg) - - sig, err := alg.Create(privData, nil) - require.Nil(t, sig) - require.Error(t, err) - require.Contains(t, err.Error(), "parsing secret") - }) - - t.Run("unsupported key type", func(t *testing.T) { - privData := httpsignatures.Secret{ - PrivateKey: `{ - "kty": "OKP", - "use": "enc", - "crv": "Ed25519", - "kid": "sample@sample.id", - "x": "sEHL6KXs8bUz9Ss2qSWWjhhRMHVjrog0lzFENM132R8", - "alg": "EdDSA" - }`, - } - - alg := NewJWKAlgorithm(es256Alg) - - sig, err := alg.Create(privData, nil) - require.Nil(t, sig) - require.Error(t, err) - require.Contains(t, err.Error(), "key type not supported") - }) -} - -func TestSignatureAlgorithm_Verify(t *testing.T) { - t.Run("success", func(t *testing.T) { - publicKey := `{ - "kty": "EC", - "kid": "key1", - "crv": "P-256", - "alg": "ES256", - "x": "igkN3pcl8OZ9bfzrLCRbflZ9cVmQVKfwXSHDbgN3G6U", - "y": "0qhuWhPxLeXgEWZnfUXObCZBb-n_wckAE-M5_4tGhWk" -}` - - pubData := httpsignatures.Secret{ - KeyID: "key1", - PrivateKey: publicKey, - Algorithm: es256Alg, - } - - sigString := `z4few6IW83cySeJa+JUsyAOpP3hfpL7BkXMiGyN7RS9kMzLDMIJ8PMULomGu3X3iMsQOqFH+B7EdUQdY7IDixA==` - - sig, err := base64.StdEncoding.DecodeString(sigString) - require.NoError(t, err) - - msg := []byte("the quick brown fox jumps over the lazy dog") - - alg := NewJWKAlgorithm(es256Alg) - - err = alg.Verify(pubData, msg, sig) - require.NoError(t, err) - - }) - - t.Run("unmarshal error", func(t *testing.T) { - privData := httpsignatures.Secret{ - PrivateKey: "foo bar baz", - } - - alg := NewJWKAlgorithm(es256Alg) - - err := alg.Verify(privData, nil, nil) - require.Error(t, err) - require.Contains(t, err.Error(), "parsing public key") - }) - - t.Run("unsupported key type", func(t *testing.T) { - privData := httpsignatures.Secret{ - PrivateKey: `{ - "kty": "OKP", - "use": "enc", - "crv": "Ed25519", - "kid": "sample@sample.id", - "x": "sEHL6KXs8bUz9Ss2qSWWjhhRMHVjrog0lzFENM132R8", - "alg": "EdDSA" - }`, - } - - alg := NewJWKAlgorithm(es256Alg) - - err := alg.Verify(privData, nil, nil) - require.Error(t, err) - require.Contains(t, err.Error(), "key type not supported") - }) -} - -func Test_SignVerify(t *testing.T) { - tests := []struct { - name string - crv elliptic.Curve - }{ - { - name: es256Alg, - crv: elliptic.P256(), - }, - { - name: es384Alg, - crv: elliptic.P384(), - }, - { - name: es512Alg, - crv: elliptic.P521(), - }, - } - - for _, tt := range tests { - tc := tt - - t.Run(fmt.Sprintf("success SignVerify %s", tc.name), func(t *testing.T) { - pubData, privData := secretPair(t, tc.name, tc.crv) - - msg := []byte("the quick brown fox jumps over the lazy dog") - - alg := NewJWKAlgorithm(tc.name) - - sig, err := alg.Create(privData, msg) - require.NoError(t, err) - - err = alg.Verify(pubData, msg, sig) - require.NoError(t, err) - }) - } -} - -func secretPair(t *testing.T, alg string, crv elliptic.Curve) (pub, priv httpsignatures.Secret) { - t.Helper() - - ecKey, err := ecdsa.GenerateKey(crv, rand.Reader) - require.NoError(t, err) - - kid := "key1" - - privJWK := &jwk.JWK{ - JSONWebKey: jose.JSONWebKey{ - Key: ecKey, - KeyID: kid, - Algorithm: alg, - }, - Kty: "EC", - Crv: crv.Params().Name, - } - - privBytes, err := json.Marshal(privJWK) - require.NoError(t, err) - - pubJWK := privJWK.Public() - - pubBytes, err := json.Marshal(&pubJWK) - require.NoError(t, err) - - return httpsignatures.Secret{ - KeyID: kid, - PrivateKey: string(pubBytes), - Algorithm: alg, - }, httpsignatures.Secret{ - KeyID: kid, - PrivateKey: string(privBytes), - Algorithm: alg, - } -} diff --git a/spi/gnap/models.go b/spi/gnap/models.go index 706e861..679cee7 100644 --- a/spi/gnap/models.go +++ b/spi/gnap/models.go @@ -74,15 +74,15 @@ type AuthResponse struct { // ResponseContinue https://www.ietf.org/archive/id/draft-ietf-gnap-core-protocol-09.html#section-3.1 type ResponseContinue struct { - URI string `json:"uri"` - AccessToken AccessToken `json:"access_token"` - Wait int `json:"wait"` + URI string `json:"uri,omitempty"` + AccessToken AccessToken `json:"access_token,omitempty"` + Wait int `json:"wait,omitempty"` } // ResponseInteract https://www.ietf.org/archive/id/draft-ietf-gnap-core-protocol-09.html#section-3.3 type ResponseInteract struct { - Redirect string `json:"redirect"` - Finish string `json:"finish"` + Redirect string `json:"redirect,omitempty"` + Finish string `json:"finish,omitempty"` } // Subject https://www.ietf.org/archive/id/draft-ietf-gnap-core-protocol-09.html#section-3.4 @@ -105,13 +105,13 @@ type SubjectAssertion struct { // AccessToken https://www.ietf.org/archive/id/draft-ietf-gnap-core-protocol-09.html#section-3.2.1 type AccessToken struct { - Value string `json:"value"` - Label string `json:"label"` - Manage string `json:"manage"` - Access []TokenAccess `json:"access"` - Expires int64 `json:"expires_in"` // integer value in seconds. - Key string `json:"key"` - Flags []AccessFlag `json:"flags"` + Value string `json:"value,omitempty"` + Label string `json:"label,omitempty"` + Manage string `json:"manage,omitempty"` + Access []TokenAccess `json:"access,omitempty"` + Expires int64 `json:"expires_in,omitempty"` // integer value in seconds. + Key string `json:"key,omitempty"` + Flags []AccessFlag `json:"flags,omitempty"` } // ContinueRequest https://www.ietf.org/archive/id/draft-ietf-gnap-core-protocol-09.html#section-5.1 diff --git a/spi/gnap/proof/httpsig/sign_verify_test.go b/spi/gnap/proof/httpsig/sign_verify_test.go index c766e1f..381e334 100644 --- a/spi/gnap/proof/httpsig/sign_verify_test.go +++ b/spi/gnap/proof/httpsig/sign_verify_test.go @@ -27,16 +27,19 @@ func TestSignVerify(t *testing.T) { crv elliptic.Curve alg string digestName string + body []byte }{ { crv: elliptic.P256(), alg: "ES256", digestName: "sha-256", + body: []byte("foo bar baz"), }, { crv: elliptic.P384(), alg: "ES384", - digestName: "sha-384", + digestName: "sha-512", // sha-384 is not a supported digest algorithm in the http-digest-headers spec. + body: []byte("foo bar baz"), }, { crv: elliptic.P521(), @@ -49,32 +52,18 @@ func TestSignVerify(t *testing.T) { tc := tt t.Run(fmt.Sprintf("success %s", tc.alg), func(t *testing.T) { - body := []byte("foo bar baz") - - req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", bytes.NewReader(body)) + var req *http.Request + if len(tc.body) > 0 { + req = httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", bytes.NewReader(tc.body)) + } else { + req = httptest.NewRequest(http.MethodGet, "http://foo.bar/baz", nil) + } req.Header.Add("Authorization", "Bearer OPEN-SESAME") - priv, err := ecdsa.GenerateKey(tc.crv, rand.Reader) - require.NoError(t, err) - - privJWK := &jwk.JWK{ - JSONWebKey: jose.JSONWebKey{ - Key: priv, - KeyID: "key1", - Algorithm: tc.alg, - }, - Kty: "EC", - Crv: tc.crv.Params().Name, - } - - pubJWK := jwk.JWK{ - JSONWebKey: privJWK.Public(), - Kty: "EC", - Crv: tc.crv.Params().Name, - } + privJWK, pubJWK := jwkPairECDSA(t, tc.alg, tc.crv) - req, err = Sign(req, body, privJWK, tc.digestName) + req, err := Sign(req, tc.body, privJWK, tc.digestName) require.NoError(t, err) v := NewVerifier(req) @@ -87,3 +76,28 @@ func TestSignVerify(t *testing.T) { }) } } + +func jwkPairECDSA(t *testing.T, alg string, crv elliptic.Curve) (*jwk.JWK, jwk.JWK) { + t.Helper() + + priv, err := ecdsa.GenerateKey(crv, rand.Reader) + require.NoError(t, err) + + privJWK := &jwk.JWK{ + JSONWebKey: jose.JSONWebKey{ + Key: priv, + KeyID: "key1", + Algorithm: alg, + }, + Kty: "EC", + Crv: crv.Params().Name, + } + + pubJWK := jwk.JWK{ + JSONWebKey: privJWK.Public(), + Kty: "EC", + Crv: crv.Params().Name, + } + + return privJWK, pubJWK +} diff --git a/spi/gnap/proof/httpsig/signer.go b/spi/gnap/proof/httpsig/signer.go index 4e2d0a7..8cb602d 100644 --- a/spi/gnap/proof/httpsig/signer.go +++ b/spi/gnap/proof/httpsig/signer.go @@ -7,15 +7,16 @@ SPDX-License-Identifier: Apache-2.0 package httpsig import ( - "encoding/base64" - "encoding/json" + "bytes" "fmt" + "io/ioutil" "net/http" "github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk" - "github.com/igor-pavlenko/httpsignatures-go" + "github.com/lestrrat-go/jwx/v2/jwa" + "github.com/yaronf/httpsign" + "github.com/trustbloc/auth/spi/gnap/internal/digest" - "github.com/trustbloc/auth/spi/gnap/internal/jwksignature" ) // Signer signs GNAP http requests using http-signature. @@ -23,6 +24,8 @@ type Signer struct { SigningKey *jwk.JWK } +const defaultSignatureName = "sig1" + // ProofType returns "httpsig", the GNAP proof type of the http-signature proof method. func (s *Signer) ProofType() string { return "httpsig" @@ -33,56 +36,48 @@ func (s *Signer) Sign(request *http.Request, requestBody []byte) (*http.Request, return Sign(request, requestBody, s.SigningKey, digest.SHA256) } -// Sign signs a GNAP http request, adding http-signature headers. func Sign(req *http.Request, bodyBytes []byte, signingKey *jwk.JWK, digestName string) (*http.Request, error) { - keyBytes, err := json.Marshal(signingKey) - if err != nil { - return nil, fmt.Errorf("marshalling signing key: %w", err) - } + conf := httpsign.NewSignConfig().SignAlg(false) - ss := httpsignatures.NewSimpleSecretsStorage(map[string]httpsignatures.Secret{ - signingKey.KeyID: { - KeyID: signingKey.KeyID, - PublicKey: "", - PrivateKey: string(keyBytes), - Algorithm: signingKey.Algorithm, - }, - }) - hs := httpsignatures.NewHTTPSignatures(ss) - hs.SetSignatureHashAlgorithm(jwksignature.NewJWKAlgorithm(signingKey.Algorithm)) - - coveredComponents := []string{ - "(request-target)", // in this implementation, this string is the code for method + target-uri - } + fields := httpsign.Headers("@request-target") + + if len(bodyBytes) > 0 { + body := ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) - if len(bodyBytes) != 0 { - digestAlgorithm, err := digest.GetDigest(digestName) + cdHeader, err := httpsign.GenerateContentDigestHeader(&body, []string{digestName}) if err != nil { return nil, err } - contentDigest, err := digestAlgorithm(bodyBytes) - if err != nil { - return nil, fmt.Errorf("creating content-digest: %w", err) - } + req.Header.Add("content-digest", cdHeader) - digestValue := digestName + "=:" + base64.StdEncoding.EncodeToString(contentDigest) + ":" + fields.AddHeader("content-digest") + } - req.Header.Add("Content-Digest", digestValue) + authHeader := req.Header.Get("Authorization") - coveredComponents = append(coveredComponents, "content-digest") + if authHeader != "" { + fields.AddHeader("Authorization") } - if req.Header.Get("Authorization") != "" { - coveredComponents = append(coveredComponents, "authorization") + signer, err := httpsign.NewJWSSigner( + jwa.SignatureAlgorithm(signingKey.Algorithm), + signingKey.KeyID, + signingKey.Key, + conf, + fields, + ) + if err != nil { + return nil, fmt.Errorf("creating signer: %w", err) } - hs.SetDefaultSignatureHeaders(coveredComponents) - - err = hs.Sign(signingKey.KeyID, req) + sigInput, sig, err := httpsign.SignRequest(defaultSignatureName, *signer, req) if err != nil { - return nil, fmt.Errorf("failed to sign: %w", err) + return nil, fmt.Errorf("signing request: %w", err) } + req.Header.Add("Signature", sig) + req.Header.Add("Signature-Input", sigInput) + return req, nil } diff --git a/spi/gnap/proof/httpsig/signer_test.go b/spi/gnap/proof/httpsig/signer_test.go index eb70253..868ec87 100644 --- a/spi/gnap/proof/httpsig/signer_test.go +++ b/spi/gnap/proof/httpsig/signer_test.go @@ -8,9 +8,7 @@ package httpsig import ( "bytes" - "crypto/ecdsa" "crypto/elliptic" - "crypto/rand" "net/http" "net/http/httptest" "testing" @@ -18,138 +16,71 @@ import ( "github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk" "github.com/square/go-jose/v3" "github.com/stretchr/testify/require" - "github.com/trustbloc/auth/spi/gnap/internal/digest" ) -func TestSigner(t *testing.T) { - t.Run("ProofType", func(t *testing.T) { - require.Equal(t, "httpsig", (&Signer{}).ProofType()) - }) - - t.Run("Sign", func(t *testing.T) { - body := []byte("foo bar baz") - - req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", bytes.NewReader(body)) - - req.Header.Add("Authorization", "Bearer OPEN-SESAME") - - priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - require.NoError(t, err) - - privJWK := &jwk.JWK{ - JSONWebKey: jose.JSONWebKey{ - Key: priv, - KeyID: "key1", - Algorithm: "ES256", - }, - Kty: "EC", - Crv: "P-256", - } - - signer := &Signer{ - SigningKey: privJWK, - } - - req, err = signer.Sign(req, body) - require.NoError(t, err) - }) - +func TestProofType(t *testing.T) { + require.Equal(t, "httpsig", (&Signer{}).ProofType()) } func TestSign(t *testing.T) { t.Run("success", func(t *testing.T) { + priv, _ := jwkPairECDSA(t, "ES256", elliptic.P256()) + body := []byte("foo bar baz") req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", bytes.NewReader(body)) - req.Header.Add("Authorization", "Bearer OPEN-SESAME") - - priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - require.NoError(t, err) + // include an auth header to be signed as well + req.Header.Add("Authorization", "FOO bar") - privJWK := &jwk.JWK{ - JSONWebKey: jose.JSONWebKey{ - Key: priv, - KeyID: "key1", - Algorithm: "ES256", - }, - Kty: "EC", - Crv: "P-256", + signer := Signer{ + SigningKey: priv, } - req, err = Sign(req, body, privJWK, digest.SHA256) + signedReq, err := signer.Sign(req, body) require.NoError(t, err) - }) - t.Run("jwk marshal error", func(t *testing.T) { - body := []byte("foo bar baz") - - req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", bytes.NewReader(body)) - - req.Header.Add("Authorization", "Bearer OPEN-SESAME") + sig := signedReq.Header.Get("signature") + require.NotEmpty(t, sig) + sigParams := signedReq.Header.Get("signature-input") + require.NotEmpty(t, sigParams) + }) - privJWK := &jwk.JWK{ + t.Run("fail to create signer", func(t *testing.T) { + priv := &jwk.JWK{ JSONWebKey: jose.JSONWebKey{ - Key: []byte{}, - KeyID: "key1", - Algorithm: "ES256", + Algorithm: "foo", }, - Kty: "OKP", // incorrect type data, to force a marshalling error - Crv: "X25519", } - _, err := Sign(req, body, privJWK, digest.SHA256) - require.Error(t, err) - require.Contains(t, err.Error(), "marshalling signing key") - }) - - t.Run("unsupported digest", func(t *testing.T) { body := []byte("foo bar baz") req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", bytes.NewReader(body)) - req.Header.Add("Authorization", "Bearer OPEN-SESAME") - - priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - require.NoError(t, err) - - privJWK := &jwk.JWK{ - JSONWebKey: jose.JSONWebKey{ - Key: priv, - KeyID: "key1", - Algorithm: "ES256", - }, - Kty: "EC", - Crv: "P-256", + signer := Signer{ + SigningKey: priv, } - req, err = Sign(req, body, privJWK, "unknown digest") + _, err := signer.Sign(req, body) require.Error(t, err) - require.Contains(t, err.Error(), "unsupported digest") + require.Contains(t, err.Error(), "creating signer") }) - t.Run("fail to sign", func(t *testing.T) { - body := []byte("foo bar baz") + t.Run("fail to sign invalid request", func(t *testing.T) { + priv, _ := jwkPairECDSA(t, "ES256", elliptic.P256()) - req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", bytes.NewReader(body)) + body := []byte("") - req.Header.Add("Authorization", "Bearer OPEN-SESAME") + req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", nil) - priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - require.NoError(t, err) + req.Header.Add("@invalid-header", "foo") - privJWK := &jwk.JWK{ - JSONWebKey: jose.JSONWebKey{ - Key: &priv.PublicKey, // jwk algorithm will fail to sign given a public key - KeyID: "key1", - Algorithm: "ES256", - }, - Kty: "EC", - Crv: "P-256", + signer := Signer{ + SigningKey: priv, } - req, err = Sign(req, body, privJWK, digest.SHA256) + _, err := signer.Sign(req, body) require.Error(t, err) - require.Contains(t, err.Error(), "failed to sign") + require.Contains(t, err.Error(), "signing request") }) } diff --git a/spi/gnap/proof/httpsig/verifier.go b/spi/gnap/proof/httpsig/verifier.go index 5d2e54b..1de17ae 100644 --- a/spi/gnap/proof/httpsig/verifier.go +++ b/spi/gnap/proof/httpsig/verifier.go @@ -8,19 +8,13 @@ package httpsig import ( "bytes" - "encoding/base64" - "encoding/json" - "errors" "fmt" "io/ioutil" "net/http" - "strings" - - "github.com/igor-pavlenko/httpsignatures-go" + "github.com/lestrrat-go/jwx/v2/jwa" "github.com/trustbloc/auth/spi/gnap" - "github.com/trustbloc/auth/spi/gnap/internal/digest" - "github.com/trustbloc/auth/spi/gnap/internal/jwksignature" + "github.com/yaronf/httpsign" ) // Verifier verifies that the client request is signed by the client key, using http-signature verification. @@ -35,26 +29,16 @@ func NewVerifier(req *http.Request) *Verifier { // Verify verifies that the Verifier's client request is signed by the client key, using http-signature verification. func (v *Verifier) Verify(key *gnap.ClientKey) error { - keyBytes, err := json.Marshal(&key.JWK) - if err != nil { - return fmt.Errorf("marshalling verification key: %w", err) - } + verKey := key.JWK - ss := httpsignatures.NewSimpleSecretsStorage(map[string]httpsignatures.Secret{ - key.JWK.KeyID: { - KeyID: key.JWK.KeyID, - PublicKey: "", - PrivateKey: string(keyBytes), - Algorithm: key.JWK.Algorithm, - }, - }) - hs := httpsignatures.NewHTTPSignatures(ss) - hs.SetSignatureHashAlgorithm(jwksignature.NewJWKAlgorithm(key.JWK.Algorithm)) + fields := httpsign.Headers("@request-target") - var bodyBytes []byte + if v.req.Header.Get("Authorization") != "" { + fields.AddHeader("Authorization") + } if v.req.Body != nil { - bodyBytes, err = ioutil.ReadAll(v.req.Body) + bodyBytes, err := ioutil.ReadAll(v.req.Body) if err != nil { return err } @@ -62,53 +46,24 @@ func (v *Verifier) Verify(key *gnap.ClientKey) error { v.req.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) if len(bodyBytes) > 0 { - err = verifyDigest(v.req, bodyBytes) - if err != nil { - return err - } - - // TODO: confirm that the content-digest header is included in the http-signature input. + fields.AddHeader("content-digest") } } - err = hs.Verify(v.req) + verifier, err := httpsign.NewJWSVerifier( + jwa.SignatureAlgorithm(verKey.Algorithm), + verKey.Key, + verKey.KeyID, + nil, + fields, + ) if err != nil { - return fmt.Errorf("failed verification: %w", err) + return fmt.Errorf("creating verifier: %w", err) } - return nil -} - -func verifyDigest(req *http.Request, bodyBytes []byte) error { - contentDigest := req.Header.Get("Content-Digest") - if len(contentDigest) == 0 { - return errors.New("request with body should have a content-digest header") - } - - digestParts := strings.Split(contentDigest, ":") - if len(digestParts) < 2 { - return errors.New("content-digest header should have name and value") - } - - digestName := strings.Trim(digestParts[0], "=") - - digestAlg, err := digest.GetDigest(digestName) - if err != nil { - return err - } - - digestValue, err := base64.StdEncoding.DecodeString(digestParts[1]) + err = httpsign.VerifyRequest(defaultSignatureName, *verifier, v.req) if err != nil { - return fmt.Errorf("decoding digest value: %w", err) - } - - computedDigest, err := digestAlg(bodyBytes) - if err != nil { - return fmt.Errorf("computing expected digest: %w", err) - } - - if !bytes.Equal(computedDigest, digestValue) { - return errors.New("content-digest header does not match digest of request body") + return fmt.Errorf("verifying request: %w", err) } return nil diff --git a/spi/gnap/proof/httpsig/verifier_test.go b/spi/gnap/proof/httpsig/verifier_test.go index 62e421b..5f5ec18 100644 --- a/spi/gnap/proof/httpsig/verifier_test.go +++ b/spi/gnap/proof/httpsig/verifier_test.go @@ -8,166 +8,86 @@ package httpsig import ( "bytes" - "crypto/ecdsa" "crypto/elliptic" - "crypto/rand" "errors" "net/http" "net/http/httptest" "testing" "github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk" - "github.com/square/go-jose/v3" "github.com/stretchr/testify/require" "github.com/trustbloc/auth/spi/gnap" - "github.com/trustbloc/auth/spi/gnap/internal/digest" ) -func TestNewVerifier(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/example/path", nil) +func TestVerify(t *testing.T) { + t.Run("success", func(t *testing.T) { + priv, pub := jwkPairECDSA(t, "ES256", elliptic.P256()) - v := NewVerifier(req) - - require.NotNil(t, v) - require.Equal(t, req, v.req) -} - -func TestVerifier_Verify(t *testing.T) { - t.Run("jwk marshal error", func(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "/example/path", nil) - - v := NewVerifier(req) - - err := v.Verify(&gnap.ClientKey{ - JWK: jwk.JWK{ - JSONWebKey: jose.JSONWebKey{ - Key: []byte{}, - KeyID: "key1", - Algorithm: "ES256", - }, - Kty: "OKP", // incorrect type data, to force a marshalling error - Crv: "X25519", - }, - }) - require.Error(t, err) - require.Contains(t, err.Error(), "marshalling verification key") - }) - - t.Run("fail to read body", func(t *testing.T) { - expectErr := errors.New("expected error") - - req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", &errorReader{err: expectErr}) - - v := NewVerifier(req) - - err := v.Verify(clientKey(t)) - require.Error(t, err) - require.ErrorIs(t, err, expectErr) - }) - - t.Run("has body but no content-digest", func(t *testing.T) { body := []byte("foo bar baz") req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", bytes.NewReader(body)) - v := NewVerifier(req) - - err := v.Verify(clientKey(t)) - require.Error(t, err) - require.Contains(t, err.Error(), "should have a content-digest") - }) - - t.Run("content-digest header has invalid format", func(t *testing.T) { - body := []byte("foo bar baz") + // include an auth header to be verified as well + req.Header.Add("Authorization", "FOO bar") - req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", bytes.NewReader(body)) + signer := Signer{ + SigningKey: priv, + } - req.Header.Set("content-digest", "foo") + signedReq, err := signer.Sign(req, body) + require.NoError(t, err) - v := NewVerifier(req) + verifier := NewVerifier(signedReq) - err := v.Verify(clientKey(t)) - require.Error(t, err) - require.Contains(t, err.Error(), "content-digest header should have name and value") + require.NoError(t, verifier.Verify(&gnap.ClientKey{ + JWK: pub, + })) }) - t.Run("unsupported content-digest algorithm", func(t *testing.T) { - body := []byte("foo bar baz") - - req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", bytes.NewReader(body)) + t.Run("fail to read malformed body", func(t *testing.T) { + req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", badBody("fail to read body")) - req.Header.Set("content-digest", "foo:bar:") + verifier := NewVerifier(req) - v := NewVerifier(req) + err := verifier.Verify(&gnap.ClientKey{ + JWK: jwk.JWK{}, + }) - err := v.Verify(clientKey(t)) require.Error(t, err) - require.Contains(t, err.Error(), "unsupported digest") + require.Contains(t, err.Error(), "fail to read body") }) - t.Run("invalid digest value", func(t *testing.T) { - body := []byte("foo bar baz") - - req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", bytes.NewReader(body)) + t.Run("fail to create httpsign verifier", func(t *testing.T) { + req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", nil) - req.Header.Set("content-digest", digest.SHA256+"=:#&^^%##$:") + verifier := NewVerifier(req) - v := NewVerifier(req) + err := verifier.Verify(&gnap.ClientKey{ + JWK: jwk.JWK{}, + }) - err := v.Verify(clientKey(t)) require.Error(t, err) - require.Contains(t, err.Error(), "decoding digest value") + require.Contains(t, err.Error(), "creating verifier") }) - t.Run("digest does not match", func(t *testing.T) { - body := []byte("foo bar baz") - - req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", bytes.NewReader(body)) - - req.Header.Set("content-digest", digest.SHA256+"=:eyJk:") - - v := NewVerifier(req) + t.Run("verification error", func(t *testing.T) { + req := httptest.NewRequest(http.MethodPost, "http://foo.bar/baz", nil) - err := v.Verify(clientKey(t)) - require.Error(t, err) - require.Contains(t, err.Error(), "content-digest header does not match digest") - }) + _, pub := jwkPairECDSA(t, "ES256", elliptic.P256()) - t.Run("signature verification error", func(t *testing.T) { - req := httptest.NewRequest(http.MethodGet, "http://foo.bar/baz", nil) + verifier := NewVerifier(req) - v := NewVerifier(req) + err := verifier.Verify(&gnap.ClientKey{ + JWK: pub, + }) - err := v.Verify(clientKey(t)) require.Error(t, err) - require.Contains(t, err.Error(), "failed verification") + require.Contains(t, err.Error(), "verifying request") }) - } -func clientKey(t *testing.T) *gnap.ClientKey { - t.Helper() - - priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - require.NoError(t, err) - - return &gnap.ClientKey{ - JWK: jwk.JWK{ - JSONWebKey: jose.JSONWebKey{ - Key: &(priv.PublicKey), - KeyID: "key1", - Algorithm: "ES256", - }, - Kty: "EC", - Crv: "P-256", - }, - } -} - -type errorReader struct { - err error -} +type badBody string -func (e *errorReader) Read([]byte) (int, error) { - return 0, e.err +func (b badBody) Read([]byte) (int, error) { + return 0, errors.New(string(b)) }