mirror of
https://github.com/GoogleContainerTools/kaniko
synced 2026-10-19 13:41:08 +02:00
chore(deps): bump google.golang.org/api from 0.110.0 to 0.120.0 (#2484)
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.110.0 to 0.120.0. - [Release notes](https://github.com/googleapis/google-api-go-client/releases) - [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.110.0...v0.120.0) --- updated-dependencies: - dependency-name: google.golang.org/api dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
@@ -26,8 +26,8 @@ require (
|
||||
github.com/spf13/afero v1.9.2
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
golang.org/x/net v0.8.0
|
||||
golang.org/x/oauth2 v0.6.0
|
||||
golang.org/x/net v0.9.0
|
||||
golang.org/x/oauth2 v0.7.0
|
||||
golang.org/x/sync v0.1.0
|
||||
)
|
||||
|
||||
@@ -41,9 +41,9 @@ require (
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.110.0 // indirect
|
||||
cloud.google.com/go/compute v1.18.0 // indirect
|
||||
cloud.google.com/go/compute v1.19.0 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v0.12.0 // indirect
|
||||
cloud.google.com/go/iam v0.13.0 // indirect
|
||||
github.com/Azure/azure-pipeline-go v0.2.3 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
@@ -94,7 +94,7 @@ require (
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.7.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.8.0 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||
github.com/hashicorp/go-memdb v1.3.2 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.1 // indirect
|
||||
@@ -136,15 +136,15 @@ require (
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.uber.org/goleak v1.2.1 // indirect
|
||||
golang.org/x/crypto v0.2.0 // indirect
|
||||
golang.org/x/sys v0.6.0
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/sys v0.7.0
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
golang.org/x/time v0.1.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/api v0.110.0
|
||||
google.golang.org/api v0.120.0
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
|
||||
google.golang.org/grpc v1.53.0 // indirect
|
||||
google.golang.org/protobuf v1.29.1 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
google.golang.org/grpc v1.54.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
||||
@@ -153,5 +153,6 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.15.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.12.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/s2a-go v0.1.2 // indirect
|
||||
github.com/moby/swarmkit/v2 v2.0.0-20230315203717-e28e8ba9bc83 // indirect
|
||||
)
|
||||
|
||||
@@ -52,13 +52,18 @@ cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wx
|
||||
cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o=
|
||||
cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE=
|
||||
cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM=
|
||||
cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ=
|
||||
cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=
|
||||
cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=
|
||||
cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg=
|
||||
cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ=
|
||||
cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k=
|
||||
cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw=
|
||||
cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=
|
||||
cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4=
|
||||
cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M=
|
||||
cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE=
|
||||
cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE=
|
||||
cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk=
|
||||
cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc=
|
||||
cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8=
|
||||
@@ -67,25 +72,35 @@ cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn
|
||||
cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8=
|
||||
cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY=
|
||||
cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM=
|
||||
cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc=
|
||||
cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU=
|
||||
cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI=
|
||||
cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8=
|
||||
cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno=
|
||||
cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak=
|
||||
cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84=
|
||||
cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A=
|
||||
cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E=
|
||||
cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4=
|
||||
cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0=
|
||||
cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY=
|
||||
cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k=
|
||||
cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ=
|
||||
cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk=
|
||||
cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0=
|
||||
cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc=
|
||||
cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI=
|
||||
cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ=
|
||||
cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI=
|
||||
cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08=
|
||||
cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o=
|
||||
cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s=
|
||||
cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0=
|
||||
cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ=
|
||||
cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY=
|
||||
cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo=
|
||||
cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg=
|
||||
cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw=
|
||||
cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY=
|
||||
cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw=
|
||||
cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI=
|
||||
@@ -106,6 +121,7 @@ cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oe
|
||||
cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4=
|
||||
cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8=
|
||||
cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM=
|
||||
cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
@@ -116,12 +132,16 @@ cloud.google.com/go/bigquery v1.17.0/go.mod h1:pUlbH9kNOnp6ayShsqKLB6w49z14ILAaq
|
||||
cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA=
|
||||
cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw=
|
||||
cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc=
|
||||
cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E=
|
||||
cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac=
|
||||
cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q=
|
||||
cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU=
|
||||
cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY=
|
||||
cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s=
|
||||
cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI=
|
||||
cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y=
|
||||
cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss=
|
||||
cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc=
|
||||
cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM=
|
||||
cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI=
|
||||
cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0=
|
||||
@@ -133,9 +153,12 @@ cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5v
|
||||
cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk=
|
||||
cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk=
|
||||
cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE=
|
||||
cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU=
|
||||
cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U=
|
||||
cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA=
|
||||
cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M=
|
||||
cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg=
|
||||
cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s=
|
||||
cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM=
|
||||
cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk=
|
||||
cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA=
|
||||
@@ -144,6 +167,7 @@ cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uX
|
||||
cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4=
|
||||
cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI=
|
||||
cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y=
|
||||
cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs=
|
||||
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
|
||||
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
|
||||
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
|
||||
@@ -156,8 +180,9 @@ cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x
|
||||
cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE=
|
||||
cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo=
|
||||
cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA=
|
||||
cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY=
|
||||
cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs=
|
||||
cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ=
|
||||
cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU=
|
||||
cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU=
|
||||
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
|
||||
@@ -169,9 +194,12 @@ cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iW
|
||||
cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg=
|
||||
cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo=
|
||||
cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4=
|
||||
cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM=
|
||||
cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA=
|
||||
cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I=
|
||||
cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4=
|
||||
cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI=
|
||||
cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s=
|
||||
cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0=
|
||||
cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs=
|
||||
cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc=
|
||||
@@ -179,6 +207,7 @@ cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H
|
||||
cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM=
|
||||
cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M=
|
||||
cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0=
|
||||
cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8=
|
||||
cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM=
|
||||
cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ=
|
||||
cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE=
|
||||
@@ -186,6 +215,7 @@ cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KF
|
||||
cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE=
|
||||
cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0=
|
||||
cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA=
|
||||
cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE=
|
||||
cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38=
|
||||
cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w=
|
||||
cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8=
|
||||
@@ -195,6 +225,7 @@ cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxB
|
||||
cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA=
|
||||
cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A=
|
||||
cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ=
|
||||
cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs=
|
||||
cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s=
|
||||
cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI=
|
||||
cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4=
|
||||
@@ -205,14 +236,17 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/datastore v1.5.0/go.mod h1:RGUNM0FFAVkYA94BLTxoXBgfIyY1Riq67TwaBXH0lwc=
|
||||
cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM=
|
||||
cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c=
|
||||
cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo=
|
||||
cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ=
|
||||
cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g=
|
||||
cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4=
|
||||
cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs=
|
||||
cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww=
|
||||
cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c=
|
||||
cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s=
|
||||
cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI=
|
||||
cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ=
|
||||
cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4=
|
||||
cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0=
|
||||
cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8=
|
||||
@@ -220,6 +254,7 @@ cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz
|
||||
cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0=
|
||||
cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM=
|
||||
cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4=
|
||||
cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE=
|
||||
cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM=
|
||||
cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q=
|
||||
cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4=
|
||||
@@ -228,12 +263,14 @@ cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX
|
||||
cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k=
|
||||
cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4=
|
||||
cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM=
|
||||
cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs=
|
||||
cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y=
|
||||
cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg=
|
||||
cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE=
|
||||
cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk=
|
||||
cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w=
|
||||
cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc=
|
||||
cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY=
|
||||
cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU=
|
||||
cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI=
|
||||
cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8=
|
||||
@@ -241,9 +278,11 @@ cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aU
|
||||
cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc=
|
||||
cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw=
|
||||
cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw=
|
||||
cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY=
|
||||
cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w=
|
||||
cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI=
|
||||
cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs=
|
||||
cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE=
|
||||
cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk=
|
||||
@@ -251,6 +290,8 @@ cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZ
|
||||
cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY=
|
||||
cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08=
|
||||
cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw=
|
||||
cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA=
|
||||
cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c=
|
||||
cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM=
|
||||
cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA=
|
||||
cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w=
|
||||
@@ -265,6 +306,7 @@ cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+o
|
||||
cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0=
|
||||
cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0=
|
||||
cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E=
|
||||
cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw=
|
||||
cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA=
|
||||
cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI=
|
||||
cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y=
|
||||
@@ -279,21 +321,28 @@ cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHD
|
||||
cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg=
|
||||
cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE=
|
||||
cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY=
|
||||
cloud.google.com/go/iam v0.12.0 h1:DRtTY29b75ciH6Ov1PHb4/iat2CLCvrOm40Q0a6DFpE=
|
||||
cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY=
|
||||
cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k=
|
||||
cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0=
|
||||
cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc=
|
||||
cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A=
|
||||
cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk=
|
||||
cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo=
|
||||
cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74=
|
||||
cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM=
|
||||
cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY=
|
||||
cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4=
|
||||
cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs=
|
||||
cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g=
|
||||
cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o=
|
||||
cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE=
|
||||
cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA=
|
||||
cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg=
|
||||
cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0=
|
||||
cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg=
|
||||
cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w=
|
||||
cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24=
|
||||
cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI=
|
||||
cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic=
|
||||
cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI=
|
||||
cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE=
|
||||
@@ -313,6 +362,7 @@ cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtq
|
||||
cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA=
|
||||
cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI=
|
||||
cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw=
|
||||
cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY=
|
||||
cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4=
|
||||
cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w=
|
||||
cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I=
|
||||
@@ -330,22 +380,26 @@ cloud.google.com/go/monitoring v1.1.0/go.mod h1:L81pzz7HKn14QCMaCs6NTQkdBnE87TEl
|
||||
cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk=
|
||||
cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4=
|
||||
cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w=
|
||||
cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw=
|
||||
cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA=
|
||||
cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o=
|
||||
cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM=
|
||||
cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8=
|
||||
cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E=
|
||||
cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM=
|
||||
cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8=
|
||||
cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4=
|
||||
cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY=
|
||||
cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ=
|
||||
cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU=
|
||||
cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k=
|
||||
cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU=
|
||||
cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY=
|
||||
cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34=
|
||||
cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA=
|
||||
cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0=
|
||||
cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE=
|
||||
cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ=
|
||||
cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4=
|
||||
cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs=
|
||||
cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI=
|
||||
@@ -371,9 +425,11 @@ cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2om
|
||||
cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg=
|
||||
cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE=
|
||||
cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw=
|
||||
cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc=
|
||||
cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0=
|
||||
cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI=
|
||||
cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg=
|
||||
cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
@@ -382,8 +438,10 @@ cloud.google.com/go/pubsub v1.11.0-beta.schemas/go.mod h1:llNLsvx+RnsZJoY481TzC1
|
||||
cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI=
|
||||
cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0=
|
||||
cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8=
|
||||
cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4=
|
||||
cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg=
|
||||
cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k=
|
||||
cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM=
|
||||
cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4=
|
||||
cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o=
|
||||
cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk=
|
||||
@@ -391,6 +449,7 @@ cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7d
|
||||
cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE=
|
||||
cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U=
|
||||
cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA=
|
||||
cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c=
|
||||
cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg=
|
||||
cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4=
|
||||
cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac=
|
||||
@@ -407,6 +466,8 @@ cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0
|
||||
cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA=
|
||||
cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0=
|
||||
cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots=
|
||||
cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo=
|
||||
cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI=
|
||||
cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU=
|
||||
cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg=
|
||||
cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA=
|
||||
@@ -418,11 +479,13 @@ cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQk
|
||||
cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do=
|
||||
cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo=
|
||||
cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM=
|
||||
cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg=
|
||||
cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s=
|
||||
cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI=
|
||||
cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk=
|
||||
cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44=
|
||||
cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc=
|
||||
cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc=
|
||||
cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA=
|
||||
cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4=
|
||||
cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4=
|
||||
@@ -433,36 +496,45 @@ cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3s
|
||||
cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q=
|
||||
cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA=
|
||||
cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8=
|
||||
cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0=
|
||||
cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU=
|
||||
cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc=
|
||||
cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk=
|
||||
cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk=
|
||||
cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0=
|
||||
cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag=
|
||||
cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU=
|
||||
cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s=
|
||||
cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA=
|
||||
cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc=
|
||||
cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk=
|
||||
cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs=
|
||||
cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg=
|
||||
cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4=
|
||||
cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U=
|
||||
cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY=
|
||||
cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s=
|
||||
cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco=
|
||||
cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo=
|
||||
cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc=
|
||||
cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4=
|
||||
cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E=
|
||||
cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU=
|
||||
cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec=
|
||||
cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA=
|
||||
cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4=
|
||||
cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw=
|
||||
cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A=
|
||||
cloud.google.com/go/spanner v1.36.0/go.mod h1:RKVKnqXxTMDuBPAsjxohvcSTH6qiRB6E0oMljFIKPr0=
|
||||
cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos=
|
||||
cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk=
|
||||
cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M=
|
||||
cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM=
|
||||
cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ=
|
||||
cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0=
|
||||
cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco=
|
||||
cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0=
|
||||
cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
@@ -479,6 +551,7 @@ cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjp
|
||||
cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w=
|
||||
cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I=
|
||||
cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4=
|
||||
cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw=
|
||||
cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
|
||||
cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g=
|
||||
cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM=
|
||||
@@ -494,12 +567,18 @@ cloud.google.com/go/trace v1.0.0/go.mod h1:4iErSByzxkyHWzzlAj63/Gmjz0NH1ASqhJguH
|
||||
cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28=
|
||||
cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y=
|
||||
cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA=
|
||||
cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk=
|
||||
cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs=
|
||||
cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg=
|
||||
cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0=
|
||||
cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos=
|
||||
cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos=
|
||||
cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk=
|
||||
cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw=
|
||||
cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg=
|
||||
cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk=
|
||||
cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ=
|
||||
cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ=
|
||||
cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU=
|
||||
cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4=
|
||||
cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M=
|
||||
@@ -511,11 +590,14 @@ cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiC
|
||||
cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY=
|
||||
cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E=
|
||||
cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY=
|
||||
cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0=
|
||||
cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE=
|
||||
cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g=
|
||||
cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc=
|
||||
cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY=
|
||||
cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208=
|
||||
cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8=
|
||||
cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY=
|
||||
cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w=
|
||||
cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8=
|
||||
cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes=
|
||||
@@ -738,6 +820,7 @@ github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220418222510-f25a4f6275ed/go.m
|
||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||
github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
|
||||
github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0=
|
||||
github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI=
|
||||
github.com/apache/beam/sdks/v2 v2.0.0-20211012030016-ef4364519c94/go.mod h1:/kOom7hCyHVzAC/Z7HbZywkZZv6ywF+wb4CvgDVdcB8=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
|
||||
@@ -1488,6 +1571,8 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg=
|
||||
github.com/google/s2a-go v0.1.2 h1:WVtYAYuYxKeYajAmThMRYWP6K3wXkcqbGHeUgeubUHY=
|
||||
github.com/google/s2a-go v0.1.2/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/slowjam v1.0.0 h1:dA9flW4oGTJcSy8FpEvdq8JKwPFVgqYwMmjhqlb2L+s=
|
||||
github.com/google/slowjam v1.0.0/go.mod h1:mNktULbvWfYVMKKmpt94Rp3jMtmhQZLS0iR+W84S0mM=
|
||||
@@ -1519,8 +1604,10 @@ github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99
|
||||
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
|
||||
github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
|
||||
github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
|
||||
github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ=
|
||||
github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
|
||||
github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
|
||||
github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc=
|
||||
github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
|
||||
@@ -2714,8 +2801,9 @@ golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -2752,8 +2840,9 @@ golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri
|
||||
golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
|
||||
golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
|
||||
golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
|
||||
golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
|
||||
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
|
||||
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
|
||||
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
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=
|
||||
@@ -2940,8 +3029,9 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/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/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -2952,8 +3042,9 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -2969,8 +3060,9 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
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=
|
||||
@@ -2984,6 +3076,8 @@ golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
|
||||
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -3177,8 +3271,11 @@ google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4q
|
||||
google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
|
||||
google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
|
||||
google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY=
|
||||
google.golang.org/api v0.110.0 h1:l+rh0KYUooe9JGbGVx71tbFo4SMbMTXK3I3ia2QSEeU=
|
||||
google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI=
|
||||
google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=
|
||||
google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
|
||||
google.golang.org/api v0.120.0 h1:TTmhTei0mkR+kiBSW2UzZmAbkTaBfUUzfchyXnzG9Hs=
|
||||
google.golang.org/api v0.120.0/go.mod h1:CrSvlNEFCFLae9ZUtL1z+61+rEBD7J/aCYwVYKZoWFU=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@@ -3337,8 +3434,15 @@ google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ
|
||||
google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||
google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA=
|
||||
google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw=
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
|
||||
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw=
|
||||
google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA=
|
||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||
google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
|
||||
google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
|
||||
google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
|
||||
google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
@@ -3385,8 +3489,9 @@ google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCD
|
||||
google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
|
||||
google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
|
||||
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
|
||||
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
|
||||
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0/go.mod h1:DNq5QpG7LJqD2AamLZ7zvKE0DEpVl2BSEVjFycAAjRY=
|
||||
google.golang.org/grpc/examples v0.0.0-20201130180447-c456688b1860/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE=
|
||||
@@ -3406,8 +3511,9 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.29.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM=
|
||||
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
+1
-1
@@ -15,4 +15,4 @@
|
||||
package internal
|
||||
|
||||
// Version is the current tagged release of the library.
|
||||
const Version = "1.18.0"
|
||||
const Version = "1.19.0"
|
||||
|
||||
+7
@@ -1,5 +1,12 @@
|
||||
# Changes
|
||||
|
||||
## [0.13.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.12.0...iam/v0.13.0) (2023-03-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **iam:** Update iam and longrunning deps ([91a1f78](https://github.com/googleapis/google-cloud-go/commit/91a1f784a109da70f63b96414bba8a9b4254cddd))
|
||||
|
||||
## [0.12.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.11.0...iam/v0.12.0) (2023-02-17)
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.21.12
|
||||
// protoc v3.21.9
|
||||
// source: google/iam/v1/iam_policy.proto
|
||||
|
||||
package iampb
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.21.12
|
||||
// protoc v3.21.9
|
||||
// source: google/iam/v1/options.proto
|
||||
|
||||
package iampb
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.21.12
|
||||
// protoc v3.21.9
|
||||
// source: google/iam/v1/policy.proto
|
||||
|
||||
package iampb
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
bazel-*
|
||||
|
||||
# Ignore binaries without extension
|
||||
//example/client/client
|
||||
//example/server/server
|
||||
//internal/v2/fakes2av2_server/fakes2av2_server
|
||||
|
||||
.idea/
|
||||
|
||||
*BUILD.bazel
|
||||
WORKSPACE
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
# Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of
|
||||
experience, education, socio-economic status, nationality, personal appearance,
|
||||
race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, or to ban temporarily or permanently any
|
||||
contributor for other behaviors that they deem inappropriate, threatening,
|
||||
offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
This Code of Conduct also applies outside the project spaces when the Project
|
||||
Steward has a reasonable belief that an individual's behavior may have a
|
||||
negative impact on the project or its community.
|
||||
|
||||
## Conflict Resolution
|
||||
|
||||
We do not believe that all conflict is bad; healthy debate and disagreement
|
||||
often yield positive results. However, it is never okay to be disrespectful or
|
||||
to engage in behavior that violates the project’s code of conduct.
|
||||
|
||||
If you see someone violating the code of conduct, you are encouraged to address
|
||||
the behavior directly with those involved. Many issues can be resolved quickly
|
||||
and easily, and this gives people more control over the outcome of their
|
||||
dispute. If you are unable to resolve the matter for any reason, or if the
|
||||
behavior is threatening or harassing, report it. We are dedicated to providing
|
||||
an environment where participants feel welcome and safe.
|
||||
|
||||
Reports should be directed to *[PROJECT STEWARD NAME(s) AND EMAIL(s)]*, the
|
||||
Project Steward(s) for *[PROJECT NAME]*. It is the Project Steward’s duty to
|
||||
receive and address reported violations of the code of conduct. They will then
|
||||
work with a committee consisting of representatives from the Open Source
|
||||
Programs Office and the Google Open Source Strategy team. If for any reason you
|
||||
are uncomfortable reaching out to the Project Steward, please email
|
||||
opensource@google.com.
|
||||
|
||||
We will investigate every complaint, but you may not receive a direct response.
|
||||
We will use our discretion in determining when and how to follow up on reported
|
||||
incidents, which may range from not taking action to permanent expulsion from
|
||||
the project and project-sponsored spaces. We will notify the accused of the
|
||||
report and provide them an opportunity to discuss it before any action is taken.
|
||||
The identity of the reporter will be omitted from the details of the report
|
||||
supplied to the accused. In potentially harmful situations, such as ongoing
|
||||
harassment or threats to anyone's safety, we may take action without notice.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
|
||||
available at
|
||||
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# How to Contribute
|
||||
|
||||
We'd love to accept your patches and contributions to this project. There are
|
||||
just a few small guidelines you need to follow.
|
||||
|
||||
## Contributor License Agreement
|
||||
|
||||
Contributions to this project must be accompanied by a Contributor License
|
||||
Agreement (CLA). You (or your employer) retain the copyright to your
|
||||
contribution; this simply gives us permission to use and redistribute your
|
||||
contributions as part of the project. Head over to
|
||||
<https://cla.developers.google.com/> to see your current agreements on file or
|
||||
to sign a new one.
|
||||
|
||||
You generally only need to submit a CLA once, so if you've already submitted one
|
||||
(even if it was for a different project), you probably don't need to do it
|
||||
again.
|
||||
|
||||
## Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use GitHub pull requests for this purpose. Consult
|
||||
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
|
||||
information on using pull requests.
|
||||
|
||||
## Community Guidelines
|
||||
|
||||
This project follows
|
||||
[Google's Open Source Community Guidelines](https://opensource.google/conduct/).
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
# Secure Session Agent Client Libraries
|
||||
|
||||
The Secure Session Agent is a service that enables a workload to offload select
|
||||
operations from the mTLS handshake and protects a workload's private key
|
||||
material from exfiltration. Specifically, the workload asks the Secure Session
|
||||
Agent for the TLS configuration to use during the handshake, to perform private
|
||||
key operations, and to validate the peer certificate chain. The Secure Session
|
||||
Agent's client libraries enable applications to communicate with the Secure
|
||||
Session Agent during the TLS handshake, and to encrypt traffic to the peer
|
||||
after the TLS handshake is complete.
|
||||
|
||||
This repository contains the source code for the Secure Session Agent's Go
|
||||
client libraries, which allow gRPC-Go applications to use the Secure Session
|
||||
Agent. This repository supports the Bazel and Golang build systems.
|
||||
|
||||
All code in this repository is experimental and subject to change. We do not
|
||||
guarantee API stability at this time.
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package fallback provides default implementations of fallback options when S2A fails.
|
||||
package fallback
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
const (
|
||||
alpnProtoStrH2 = "h2"
|
||||
alpnProtoStrHTTP = "http/1.1"
|
||||
defaultHTTPSPort = "443"
|
||||
)
|
||||
|
||||
// FallbackTLSConfigGRPC is a tls.Config used by the DefaultFallbackClientHandshakeFunc function.
|
||||
// It supports GRPC use case, thus the alpn is set to 'h2'.
|
||||
var FallbackTLSConfigGRPC = tls.Config{
|
||||
MinVersion: tls.VersionTLS13,
|
||||
ClientSessionCache: nil,
|
||||
NextProtos: []string{alpnProtoStrH2},
|
||||
}
|
||||
|
||||
// FallbackTLSConfigHTTP is a tls.Config used by the DefaultFallbackDialerAndAddress func.
|
||||
// It supports the HTTP use case and the alpn is set to both 'http/1.1' and 'h2'.
|
||||
var FallbackTLSConfigHTTP = tls.Config{
|
||||
MinVersion: tls.VersionTLS13,
|
||||
ClientSessionCache: nil,
|
||||
NextProtos: []string{alpnProtoStrH2, alpnProtoStrHTTP},
|
||||
}
|
||||
|
||||
// ClientHandshake establishes a TLS connection and returns it, plus its auth info.
|
||||
// Inputs:
|
||||
//
|
||||
// targetServer: the server attempted with S2A.
|
||||
// conn: the tcp connection to the server at address targetServer that was passed into S2A's ClientHandshake func.
|
||||
// If fallback is successful, the `conn` should be closed.
|
||||
// err: the error encountered when performing the client-side TLS handshake with S2A.
|
||||
type ClientHandshake func(ctx context.Context, targetServer string, conn net.Conn, err error) (net.Conn, credentials.AuthInfo, error)
|
||||
|
||||
// DefaultFallbackClientHandshakeFunc returns a ClientHandshake function,
|
||||
// which establishes a TLS connection to the provided fallbackAddr, returns the new connection and its auth info.
|
||||
// Example use:
|
||||
//
|
||||
// transportCreds, _ = s2a.NewClientCreds(&s2a.ClientOptions{
|
||||
// S2AAddress: s2aAddress,
|
||||
// FallbackOpts: &s2a.FallbackOptions{ // optional
|
||||
// FallbackClientHandshakeFunc: fallback.DefaultFallbackClientHandshakeFunc(fallbackAddr),
|
||||
// },
|
||||
// })
|
||||
//
|
||||
// The fallback server's certificate must be verifiable using OS root store.
|
||||
// The fallbackAddr is expected to be a network address, e.g. example.com:port. If port is not specified,
|
||||
// it uses default port 443.
|
||||
// In the returned function's TLS config, ClientSessionCache is explicitly set to nil to disable TLS resumption,
|
||||
// and min TLS version is set to 1.3.
|
||||
func DefaultFallbackClientHandshakeFunc(fallbackAddr string) (ClientHandshake, error) {
|
||||
var fallbackDialer = tls.Dialer{Config: &FallbackTLSConfigGRPC}
|
||||
return defaultFallbackClientHandshakeFuncInternal(fallbackAddr, fallbackDialer.DialContext)
|
||||
}
|
||||
|
||||
func defaultFallbackClientHandshakeFuncInternal(fallbackAddr string, dialContextFunc func(context.Context, string, string) (net.Conn, error)) (ClientHandshake, error) {
|
||||
fallbackServerAddr, err := processFallbackAddr(fallbackAddr)
|
||||
if err != nil {
|
||||
if grpclog.V(1) {
|
||||
grpclog.Infof("error processing fallback address [%s]: %v", fallbackAddr, err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return func(ctx context.Context, targetServer string, conn net.Conn, s2aErr error) (net.Conn, credentials.AuthInfo, error) {
|
||||
fbConn, fbErr := dialContextFunc(ctx, "tcp", fallbackServerAddr)
|
||||
if fbErr != nil {
|
||||
grpclog.Infof("dialing to fallback server %s failed: %v", fallbackServerAddr, fbErr)
|
||||
return nil, nil, fmt.Errorf("dialing to fallback server %s failed: %v; S2A client handshake with %s error: %w", fallbackServerAddr, fbErr, targetServer, s2aErr)
|
||||
}
|
||||
|
||||
tc, success := fbConn.(*tls.Conn)
|
||||
if !success {
|
||||
grpclog.Infof("the connection with fallback server is expected to be tls but isn't")
|
||||
return nil, nil, fmt.Errorf("the connection with fallback server is expected to be tls but isn't; S2A client handshake with %s error: %w", targetServer, s2aErr)
|
||||
}
|
||||
|
||||
tlsInfo := credentials.TLSInfo{
|
||||
State: tc.ConnectionState(),
|
||||
CommonAuthInfo: credentials.CommonAuthInfo{
|
||||
SecurityLevel: credentials.PrivacyAndIntegrity,
|
||||
},
|
||||
}
|
||||
if grpclog.V(1) {
|
||||
grpclog.Infof("ConnectionState.NegotiatedProtocol: %v", tc.ConnectionState().NegotiatedProtocol)
|
||||
grpclog.Infof("ConnectionState.HandshakeComplete: %v", tc.ConnectionState().HandshakeComplete)
|
||||
grpclog.Infof("ConnectionState.ServerName: %v", tc.ConnectionState().ServerName)
|
||||
}
|
||||
conn.Close()
|
||||
return fbConn, tlsInfo, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DefaultFallbackDialerAndAddress returns a TLS dialer and the network address to dial.
|
||||
// Example use:
|
||||
//
|
||||
// fallbackDialer, fallbackServerAddr := fallback.DefaultFallbackDialerAndAddress(fallbackAddr)
|
||||
// dialTLSContext := s2a.NewS2aDialTLSContextFunc(&s2a.ClientOptions{
|
||||
// S2AAddress: s2aAddress, // required
|
||||
// FallbackOpts: &s2a.FallbackOptions{
|
||||
// FallbackDialer: &s2a.FallbackDialer{
|
||||
// Dialer: fallbackDialer,
|
||||
// ServerAddr: fallbackServerAddr,
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
//
|
||||
// The fallback server's certificate should be verifiable using OS root store.
|
||||
// The fallbackAddr is expected to be a network address, e.g. example.com:port. If port is not specified,
|
||||
// it uses default port 443.
|
||||
// In the returned function's TLS config, ClientSessionCache is explicitly set to nil to disable TLS resumption,
|
||||
// and min TLS version is set to 1.3.
|
||||
func DefaultFallbackDialerAndAddress(fallbackAddr string) (*tls.Dialer, string, error) {
|
||||
fallbackServerAddr, err := processFallbackAddr(fallbackAddr)
|
||||
if err != nil {
|
||||
if grpclog.V(1) {
|
||||
grpclog.Infof("error processing fallback address [%s]: %v", fallbackAddr, err)
|
||||
}
|
||||
return nil, "", err
|
||||
}
|
||||
return &tls.Dialer{Config: &FallbackTLSConfigHTTP}, fallbackServerAddr, nil
|
||||
}
|
||||
|
||||
func processFallbackAddr(fallbackAddr string) (string, error) {
|
||||
var fallbackServerAddr string
|
||||
var err error
|
||||
|
||||
if fallbackAddr == "" {
|
||||
return "", fmt.Errorf("empty fallback address")
|
||||
}
|
||||
_, _, err = net.SplitHostPort(fallbackAddr)
|
||||
if err != nil {
|
||||
// fallbackAddr does not have port suffix
|
||||
fallbackServerAddr = net.JoinHostPort(fallbackAddr, defaultHTTPSPort)
|
||||
} else {
|
||||
// FallbackServerAddr already has port suffix
|
||||
fallbackServerAddr = fallbackAddr
|
||||
}
|
||||
return fallbackServerAddr, nil
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package authinfo provides authentication and authorization information that
|
||||
// results from the TLS handshake.
|
||||
package authinfo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
commonpb "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
contextpb "github.com/google/s2a-go/internal/proto/s2a_context_go_proto"
|
||||
grpcpb "github.com/google/s2a-go/internal/proto/s2a_go_proto"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
var _ credentials.AuthInfo = (*S2AAuthInfo)(nil)
|
||||
|
||||
const s2aAuthType = "s2a"
|
||||
|
||||
// S2AAuthInfo exposes authentication and authorization information from the
|
||||
// S2A session result to the gRPC stack.
|
||||
type S2AAuthInfo struct {
|
||||
s2aContext *contextpb.S2AContext
|
||||
commonAuthInfo credentials.CommonAuthInfo
|
||||
}
|
||||
|
||||
// NewS2AAuthInfo returns a new S2AAuthInfo object from the S2A session result.
|
||||
func NewS2AAuthInfo(result *grpcpb.SessionResult) (credentials.AuthInfo, error) {
|
||||
return newS2AAuthInfo(result)
|
||||
}
|
||||
|
||||
func newS2AAuthInfo(result *grpcpb.SessionResult) (*S2AAuthInfo, error) {
|
||||
if result == nil {
|
||||
return nil, errors.New("NewS2aAuthInfo given nil session result")
|
||||
}
|
||||
return &S2AAuthInfo{
|
||||
s2aContext: &contextpb.S2AContext{
|
||||
ApplicationProtocol: result.GetApplicationProtocol(),
|
||||
TlsVersion: result.GetState().GetTlsVersion(),
|
||||
Ciphersuite: result.GetState().GetTlsCiphersuite(),
|
||||
PeerIdentity: result.GetPeerIdentity(),
|
||||
LocalIdentity: result.GetLocalIdentity(),
|
||||
PeerCertFingerprint: result.GetPeerCertFingerprint(),
|
||||
LocalCertFingerprint: result.GetLocalCertFingerprint(),
|
||||
IsHandshakeResumed: result.GetState().GetIsHandshakeResumed(),
|
||||
},
|
||||
commonAuthInfo: credentials.CommonAuthInfo{SecurityLevel: credentials.PrivacyAndIntegrity},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AuthType returns the authentication type.
|
||||
func (s *S2AAuthInfo) AuthType() string {
|
||||
return s2aAuthType
|
||||
}
|
||||
|
||||
// ApplicationProtocol returns the application protocol, e.g. "grpc".
|
||||
func (s *S2AAuthInfo) ApplicationProtocol() string {
|
||||
return s.s2aContext.GetApplicationProtocol()
|
||||
}
|
||||
|
||||
// TLSVersion returns the TLS version negotiated during the handshake.
|
||||
func (s *S2AAuthInfo) TLSVersion() commonpb.TLSVersion {
|
||||
return s.s2aContext.GetTlsVersion()
|
||||
}
|
||||
|
||||
// Ciphersuite returns the ciphersuite negotiated during the handshake.
|
||||
func (s *S2AAuthInfo) Ciphersuite() commonpb.Ciphersuite {
|
||||
return s.s2aContext.GetCiphersuite()
|
||||
}
|
||||
|
||||
// PeerIdentity returns the authenticated identity of the peer.
|
||||
func (s *S2AAuthInfo) PeerIdentity() *commonpb.Identity {
|
||||
return s.s2aContext.GetPeerIdentity()
|
||||
}
|
||||
|
||||
// LocalIdentity returns the local identity of the application used during
|
||||
// session setup.
|
||||
func (s *S2AAuthInfo) LocalIdentity() *commonpb.Identity {
|
||||
return s.s2aContext.GetLocalIdentity()
|
||||
}
|
||||
|
||||
// PeerCertFingerprint returns the SHA256 hash of the peer certificate used in
|
||||
// the S2A handshake.
|
||||
func (s *S2AAuthInfo) PeerCertFingerprint() []byte {
|
||||
return s.s2aContext.GetPeerCertFingerprint()
|
||||
}
|
||||
|
||||
// LocalCertFingerprint returns the SHA256 hash of the local certificate used
|
||||
// in the S2A handshake.
|
||||
func (s *S2AAuthInfo) LocalCertFingerprint() []byte {
|
||||
return s.s2aContext.GetLocalCertFingerprint()
|
||||
}
|
||||
|
||||
// IsHandshakeResumed returns true if a cached session was used to resume
|
||||
// the handshake.
|
||||
func (s *S2AAuthInfo) IsHandshakeResumed() bool {
|
||||
return s.s2aContext.GetIsHandshakeResumed()
|
||||
}
|
||||
|
||||
// SecurityLevel returns the security level of the connection.
|
||||
func (s *S2AAuthInfo) SecurityLevel() credentials.SecurityLevel {
|
||||
return s.commonAuthInfo.SecurityLevel
|
||||
}
|
||||
+438
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package handshaker communicates with the S2A handshaker service.
|
||||
package handshaker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/google/s2a-go/internal/authinfo"
|
||||
commonpb "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
s2apb "github.com/google/s2a-go/internal/proto/s2a_go_proto"
|
||||
"github.com/google/s2a-go/internal/record"
|
||||
"github.com/google/s2a-go/internal/tokenmanager"
|
||||
grpc "google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
var (
|
||||
// appProtocol contains the application protocol accepted by the handshaker.
|
||||
appProtocol = "grpc"
|
||||
// frameLimit is the maximum size of a frame in bytes.
|
||||
frameLimit = 1024 * 64
|
||||
// peerNotRespondingError is the error thrown when the peer doesn't respond.
|
||||
errPeerNotResponding = errors.New("peer is not responding and re-connection should be attempted")
|
||||
)
|
||||
|
||||
// Handshaker defines a handshaker interface.
|
||||
type Handshaker interface {
|
||||
// ClientHandshake starts and completes a TLS handshake from the client side,
|
||||
// and returns a secure connection along with additional auth information.
|
||||
ClientHandshake(ctx context.Context) (net.Conn, credentials.AuthInfo, error)
|
||||
// ServerHandshake starts and completes a TLS handshake from the server side,
|
||||
// and returns a secure connection along with additional auth information.
|
||||
ServerHandshake(ctx context.Context) (net.Conn, credentials.AuthInfo, error)
|
||||
// Close terminates the Handshaker. It should be called when the handshake
|
||||
// is complete.
|
||||
Close() error
|
||||
}
|
||||
|
||||
// ClientHandshakerOptions contains the options needed to configure the S2A
|
||||
// handshaker service on the client-side.
|
||||
type ClientHandshakerOptions struct {
|
||||
// MinTLSVersion specifies the min TLS version supported by the client.
|
||||
MinTLSVersion commonpb.TLSVersion
|
||||
// MaxTLSVersion specifies the max TLS version supported by the client.
|
||||
MaxTLSVersion commonpb.TLSVersion
|
||||
// TLSCiphersuites is the ordered list of ciphersuites supported by the
|
||||
// client.
|
||||
TLSCiphersuites []commonpb.Ciphersuite
|
||||
// TargetIdentities contains a list of allowed server identities. One of the
|
||||
// target identities should match the peer identity in the handshake
|
||||
// result; otherwise, the handshake fails.
|
||||
TargetIdentities []*commonpb.Identity
|
||||
// LocalIdentity is the local identity of the client application. If none is
|
||||
// provided, then the S2A will choose the default identity.
|
||||
LocalIdentity *commonpb.Identity
|
||||
// TargetName is the allowed server name, which may be used for server
|
||||
// authorization check by the S2A if it is provided.
|
||||
TargetName string
|
||||
// EnsureProcessSessionTickets allows users to wait and ensure that all
|
||||
// available session tickets are sent to S2A before a process completes.
|
||||
EnsureProcessSessionTickets *sync.WaitGroup
|
||||
}
|
||||
|
||||
// ServerHandshakerOptions contains the options needed to configure the S2A
|
||||
// handshaker service on the server-side.
|
||||
type ServerHandshakerOptions struct {
|
||||
// MinTLSVersion specifies the min TLS version supported by the server.
|
||||
MinTLSVersion commonpb.TLSVersion
|
||||
// MaxTLSVersion specifies the max TLS version supported by the server.
|
||||
MaxTLSVersion commonpb.TLSVersion
|
||||
// TLSCiphersuites is the ordered list of ciphersuites supported by the
|
||||
// server.
|
||||
TLSCiphersuites []commonpb.Ciphersuite
|
||||
// LocalIdentities is the list of local identities that may be assumed by
|
||||
// the server. If no local identity is specified, then the S2A chooses a
|
||||
// default local identity.
|
||||
LocalIdentities []*commonpb.Identity
|
||||
}
|
||||
|
||||
// s2aHandshaker performs a TLS handshake using the S2A handshaker service.
|
||||
type s2aHandshaker struct {
|
||||
// stream is used to communicate with the S2A handshaker service.
|
||||
stream s2apb.S2AService_SetUpSessionClient
|
||||
// conn is the connection to the peer.
|
||||
conn net.Conn
|
||||
// clientOpts should be non-nil iff the handshaker is client-side.
|
||||
clientOpts *ClientHandshakerOptions
|
||||
// serverOpts should be non-nil iff the handshaker is server-side.
|
||||
serverOpts *ServerHandshakerOptions
|
||||
// isClient determines if the handshaker is client or server side.
|
||||
isClient bool
|
||||
// hsAddr stores the address of the S2A handshaker service.
|
||||
hsAddr string
|
||||
// tokenManager manages access tokens for authenticating to S2A.
|
||||
tokenManager tokenmanager.AccessTokenManager
|
||||
// localIdentities is the set of local identities for whom the
|
||||
// tokenManager should fetch a token when preparing a request to be
|
||||
// sent to S2A.
|
||||
localIdentities []*commonpb.Identity
|
||||
}
|
||||
|
||||
// NewClientHandshaker creates an s2aHandshaker instance that performs a
|
||||
// client-side TLS handshake using the S2A handshaker service.
|
||||
func NewClientHandshaker(ctx context.Context, conn *grpc.ClientConn, c net.Conn, hsAddr string, opts *ClientHandshakerOptions) (Handshaker, error) {
|
||||
stream, err := s2apb.NewS2AServiceClient(conn).SetUpSession(ctx, grpc.WaitForReady(true))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokenManager, err := tokenmanager.NewSingleTokenAccessTokenManager()
|
||||
if err != nil {
|
||||
grpclog.Infof("failed to create single token access token manager: %v", err)
|
||||
}
|
||||
return newClientHandshaker(stream, c, hsAddr, opts, tokenManager), nil
|
||||
}
|
||||
|
||||
func newClientHandshaker(stream s2apb.S2AService_SetUpSessionClient, c net.Conn, hsAddr string, opts *ClientHandshakerOptions, tokenManager tokenmanager.AccessTokenManager) *s2aHandshaker {
|
||||
var localIdentities []*commonpb.Identity
|
||||
if opts != nil {
|
||||
localIdentities = []*commonpb.Identity{opts.LocalIdentity}
|
||||
}
|
||||
return &s2aHandshaker{
|
||||
stream: stream,
|
||||
conn: c,
|
||||
clientOpts: opts,
|
||||
isClient: true,
|
||||
hsAddr: hsAddr,
|
||||
tokenManager: tokenManager,
|
||||
localIdentities: localIdentities,
|
||||
}
|
||||
}
|
||||
|
||||
// NewServerHandshaker creates an s2aHandshaker instance that performs a
|
||||
// server-side TLS handshake using the S2A handshaker service.
|
||||
func NewServerHandshaker(ctx context.Context, conn *grpc.ClientConn, c net.Conn, hsAddr string, opts *ServerHandshakerOptions) (Handshaker, error) {
|
||||
stream, err := s2apb.NewS2AServiceClient(conn).SetUpSession(ctx, grpc.WaitForReady(true))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokenManager, err := tokenmanager.NewSingleTokenAccessTokenManager()
|
||||
if err != nil {
|
||||
grpclog.Infof("failed to create single token access token manager: %v", err)
|
||||
}
|
||||
return newServerHandshaker(stream, c, hsAddr, opts, tokenManager), nil
|
||||
}
|
||||
|
||||
func newServerHandshaker(stream s2apb.S2AService_SetUpSessionClient, c net.Conn, hsAddr string, opts *ServerHandshakerOptions, tokenManager tokenmanager.AccessTokenManager) *s2aHandshaker {
|
||||
var localIdentities []*commonpb.Identity
|
||||
if opts != nil {
|
||||
localIdentities = opts.LocalIdentities
|
||||
}
|
||||
return &s2aHandshaker{
|
||||
stream: stream,
|
||||
conn: c,
|
||||
serverOpts: opts,
|
||||
isClient: false,
|
||||
hsAddr: hsAddr,
|
||||
tokenManager: tokenManager,
|
||||
localIdentities: localIdentities,
|
||||
}
|
||||
}
|
||||
|
||||
// ClientHandshake performs a client-side TLS handshake using the S2A handshaker
|
||||
// service. When complete, returns a TLS connection.
|
||||
func (h *s2aHandshaker) ClientHandshake(_ context.Context) (net.Conn, credentials.AuthInfo, error) {
|
||||
if !h.isClient {
|
||||
return nil, nil, errors.New("only handshakers created using NewClientHandshaker can perform a client-side handshake")
|
||||
}
|
||||
// Extract the hostname from the target name. The target name is assumed to be an authority.
|
||||
hostname, _, err := net.SplitHostPort(h.clientOpts.TargetName)
|
||||
if err != nil {
|
||||
// If the target name had no host port or could not be parsed, use it as is.
|
||||
hostname = h.clientOpts.TargetName
|
||||
}
|
||||
|
||||
// Prepare a client start message to send to the S2A handshaker service.
|
||||
req := &s2apb.SessionReq{
|
||||
ReqOneof: &s2apb.SessionReq_ClientStart{
|
||||
ClientStart: &s2apb.ClientSessionStartReq{
|
||||
ApplicationProtocols: []string{appProtocol},
|
||||
MinTlsVersion: h.clientOpts.MinTLSVersion,
|
||||
MaxTlsVersion: h.clientOpts.MaxTLSVersion,
|
||||
TlsCiphersuites: h.clientOpts.TLSCiphersuites,
|
||||
TargetIdentities: h.clientOpts.TargetIdentities,
|
||||
LocalIdentity: h.clientOpts.LocalIdentity,
|
||||
TargetName: hostname,
|
||||
},
|
||||
},
|
||||
AuthMechanisms: h.getAuthMechanisms(),
|
||||
}
|
||||
conn, result, err := h.setUpSession(req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
authInfo, err := authinfo.NewS2AAuthInfo(result)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return conn, authInfo, nil
|
||||
}
|
||||
|
||||
// ServerHandshake performs a server-side TLS handshake using the S2A handshaker
|
||||
// service. When complete, returns a TLS connection.
|
||||
func (h *s2aHandshaker) ServerHandshake(_ context.Context) (net.Conn, credentials.AuthInfo, error) {
|
||||
if h.isClient {
|
||||
return nil, nil, errors.New("only handshakers created using NewServerHandshaker can perform a server-side handshake")
|
||||
}
|
||||
p := make([]byte, frameLimit)
|
||||
n, err := h.conn.Read(p)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Prepare a server start message to send to the S2A handshaker service.
|
||||
req := &s2apb.SessionReq{
|
||||
ReqOneof: &s2apb.SessionReq_ServerStart{
|
||||
ServerStart: &s2apb.ServerSessionStartReq{
|
||||
ApplicationProtocols: []string{appProtocol},
|
||||
MinTlsVersion: h.serverOpts.MinTLSVersion,
|
||||
MaxTlsVersion: h.serverOpts.MaxTLSVersion,
|
||||
TlsCiphersuites: h.serverOpts.TLSCiphersuites,
|
||||
LocalIdentities: h.serverOpts.LocalIdentities,
|
||||
InBytes: p[:n],
|
||||
},
|
||||
},
|
||||
AuthMechanisms: h.getAuthMechanisms(),
|
||||
}
|
||||
conn, result, err := h.setUpSession(req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
authInfo, err := authinfo.NewS2AAuthInfo(result)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return conn, authInfo, nil
|
||||
}
|
||||
|
||||
// setUpSession proxies messages between the peer and the S2A handshaker
|
||||
// service.
|
||||
func (h *s2aHandshaker) setUpSession(req *s2apb.SessionReq) (net.Conn, *s2apb.SessionResult, error) {
|
||||
resp, err := h.accessHandshakerService(req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Check if the returned status is an error.
|
||||
if resp.GetStatus() != nil {
|
||||
if got, want := resp.GetStatus().Code, uint32(codes.OK); got != want {
|
||||
return nil, nil, fmt.Errorf("%v", resp.GetStatus().Details)
|
||||
}
|
||||
}
|
||||
// Calculate the extra unread bytes from the Session. Attempting to consume
|
||||
// more than the bytes sent will throw an error.
|
||||
var extra []byte
|
||||
if req.GetServerStart() != nil {
|
||||
if resp.GetBytesConsumed() > uint32(len(req.GetServerStart().GetInBytes())) {
|
||||
return nil, nil, errors.New("handshaker service consumed bytes value is out-of-bounds")
|
||||
}
|
||||
extra = req.GetServerStart().GetInBytes()[resp.GetBytesConsumed():]
|
||||
}
|
||||
result, extra, err := h.processUntilDone(resp, extra)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if result.GetLocalIdentity() == nil {
|
||||
return nil, nil, errors.New("local identity must be populated in session result")
|
||||
}
|
||||
|
||||
// Create a new TLS record protocol using the Session Result.
|
||||
newConn, err := record.NewConn(&record.ConnParameters{
|
||||
NetConn: h.conn,
|
||||
Ciphersuite: result.GetState().GetTlsCiphersuite(),
|
||||
TLSVersion: result.GetState().GetTlsVersion(),
|
||||
InTrafficSecret: result.GetState().GetInKey(),
|
||||
OutTrafficSecret: result.GetState().GetOutKey(),
|
||||
UnusedBuf: extra,
|
||||
InSequence: result.GetState().GetInSequence(),
|
||||
OutSequence: result.GetState().GetOutSequence(),
|
||||
HSAddr: h.hsAddr,
|
||||
ConnectionID: result.GetState().GetConnectionId(),
|
||||
LocalIdentity: result.GetLocalIdentity(),
|
||||
EnsureProcessSessionTickets: h.ensureProcessSessionTickets(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return newConn, result, nil
|
||||
}
|
||||
|
||||
func (h *s2aHandshaker) ensureProcessSessionTickets() *sync.WaitGroup {
|
||||
if h.clientOpts == nil {
|
||||
return nil
|
||||
}
|
||||
return h.clientOpts.EnsureProcessSessionTickets
|
||||
}
|
||||
|
||||
// accessHandshakerService sends the session request to the S2A handshaker
|
||||
// service and returns the session response.
|
||||
func (h *s2aHandshaker) accessHandshakerService(req *s2apb.SessionReq) (*s2apb.SessionResp, error) {
|
||||
if err := h.stream.Send(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := h.stream.Recv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// processUntilDone continues proxying messages between the peer and the S2A
|
||||
// handshaker service until the handshaker service returns the SessionResult at
|
||||
// the end of the handshake or an error occurs.
|
||||
func (h *s2aHandshaker) processUntilDone(resp *s2apb.SessionResp, unusedBytes []byte) (*s2apb.SessionResult, []byte, error) {
|
||||
for {
|
||||
if len(resp.OutFrames) > 0 {
|
||||
if _, err := h.conn.Write(resp.OutFrames); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
if resp.Result != nil {
|
||||
return resp.Result, unusedBytes, nil
|
||||
}
|
||||
buf := make([]byte, frameLimit)
|
||||
n, err := h.conn.Read(buf)
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, nil, err
|
||||
}
|
||||
// If there is nothing to send to the handshaker service and nothing is
|
||||
// received from the peer, then we are stuck. This covers the case when
|
||||
// the peer is not responding. Note that handshaker service connection
|
||||
// issues are caught in accessHandshakerService before we even get
|
||||
// here.
|
||||
if len(resp.OutFrames) == 0 && n == 0 {
|
||||
return nil, nil, errPeerNotResponding
|
||||
}
|
||||
// Append extra bytes from the previous interaction with the handshaker
|
||||
// service with the current buffer read from conn.
|
||||
p := append(unusedBytes, buf[:n]...)
|
||||
// From here on, p and unusedBytes point to the same slice.
|
||||
resp, err = h.accessHandshakerService(&s2apb.SessionReq{
|
||||
ReqOneof: &s2apb.SessionReq_Next{
|
||||
Next: &s2apb.SessionNextReq{
|
||||
InBytes: p,
|
||||
},
|
||||
},
|
||||
AuthMechanisms: h.getAuthMechanisms(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Cache the local identity returned by S2A, if it is populated. This
|
||||
// overwrites any existing local identities. This is done because, once the
|
||||
// S2A has selected a local identity, then only that local identity should
|
||||
// be asserted in future requests until the end of the current handshake.
|
||||
if resp.GetLocalIdentity() != nil {
|
||||
h.localIdentities = []*commonpb.Identity{resp.GetLocalIdentity()}
|
||||
}
|
||||
|
||||
// Set unusedBytes based on the handshaker service response.
|
||||
if resp.GetBytesConsumed() > uint32(len(p)) {
|
||||
return nil, nil, errors.New("handshaker service consumed bytes value is out-of-bounds")
|
||||
}
|
||||
unusedBytes = p[resp.GetBytesConsumed():]
|
||||
}
|
||||
}
|
||||
|
||||
// Close shuts down the handshaker and the stream to the S2A handshaker service
|
||||
// when the handshake is complete. It should be called when the caller obtains
|
||||
// the secure connection at the end of the handshake.
|
||||
func (h *s2aHandshaker) Close() error {
|
||||
return h.stream.CloseSend()
|
||||
}
|
||||
|
||||
func (h *s2aHandshaker) getAuthMechanisms() []*s2apb.AuthenticationMechanism {
|
||||
if h.tokenManager == nil {
|
||||
return nil
|
||||
}
|
||||
// First handle the special case when no local identities have been provided
|
||||
// by the application. In this case, an AuthenticationMechanism with no local
|
||||
// identity will be sent.
|
||||
if len(h.localIdentities) == 0 {
|
||||
token, err := h.tokenManager.DefaultToken()
|
||||
if err != nil {
|
||||
grpclog.Infof("unable to get token for empty local identity: %v", err)
|
||||
return nil
|
||||
}
|
||||
return []*s2apb.AuthenticationMechanism{
|
||||
{
|
||||
MechanismOneof: &s2apb.AuthenticationMechanism_Token{
|
||||
Token: token,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Next, handle the case where the application (or the S2A) has provided
|
||||
// one or more local identities.
|
||||
var authMechanisms []*s2apb.AuthenticationMechanism
|
||||
for _, localIdentity := range h.localIdentities {
|
||||
token, err := h.tokenManager.Token(localIdentity)
|
||||
if err != nil {
|
||||
grpclog.Infof("unable to get token for local identity %v: %v", localIdentity, err)
|
||||
continue
|
||||
}
|
||||
|
||||
authMechanism := &s2apb.AuthenticationMechanism{
|
||||
Identity: localIdentity,
|
||||
MechanismOneof: &s2apb.AuthenticationMechanism_Token{
|
||||
Token: token,
|
||||
},
|
||||
}
|
||||
authMechanisms = append(authMechanisms, authMechanism)
|
||||
}
|
||||
return authMechanisms
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package service is a utility for calling the S2A handshaker service.
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"google.golang.org/appengine"
|
||||
"google.golang.org/appengine/socket"
|
||||
grpc "google.golang.org/grpc"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
var (
|
||||
// enableAppEngineDialer indicates whether an AppEngine-specific dial option
|
||||
// should be used.
|
||||
enableAppEngineDialer bool
|
||||
// appEngineDialerHook is an AppEngine-specific dial option that is set
|
||||
// during init time. If nil, then the application is not running on Google
|
||||
// AppEngine.
|
||||
appEngineDialerHook func(context.Context) grpc.DialOption
|
||||
// mu guards hsConnMap and hsDialer.
|
||||
mu sync.Mutex
|
||||
// hsConnMap represents a mapping from an S2A handshaker service address
|
||||
// to a corresponding connection to an S2A handshaker service instance.
|
||||
hsConnMap = make(map[string]*grpc.ClientConn)
|
||||
// hsDialer will be reassigned in tests.
|
||||
hsDialer = grpc.Dial
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.BoolVar(&enableAppEngineDialer, "s2a_enable_appengine_dialer", false, "If true, opportunistically use AppEngine-specific dialer to call S2A.")
|
||||
if !appengine.IsAppEngine() && !appengine.IsDevAppServer() {
|
||||
return
|
||||
}
|
||||
appEngineDialerHook = func(ctx context.Context) grpc.DialOption {
|
||||
return grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
|
||||
return socket.DialTimeout(ctx, "tcp", addr, timeout)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Dial dials the S2A handshaker service. If a connection has already been
|
||||
// established, this function returns it. Otherwise, a new connection is
|
||||
// created.
|
||||
func Dial(handshakerServiceAddress string) (*grpc.ClientConn, error) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
hsConn, ok := hsConnMap[handshakerServiceAddress]
|
||||
if !ok {
|
||||
// Create a new connection to the S2A handshaker service. Note that
|
||||
// this connection stays open until the application is closed.
|
||||
grpcOpts := []grpc.DialOption{
|
||||
grpc.WithInsecure(),
|
||||
}
|
||||
if enableAppEngineDialer && appEngineDialerHook != nil {
|
||||
if grpclog.V(1) {
|
||||
grpclog.Info("Using AppEngine-specific dialer to talk to S2A.")
|
||||
}
|
||||
grpcOpts = append(grpcOpts, appEngineDialerHook(context.Background()))
|
||||
}
|
||||
var err error
|
||||
hsConn, err = hsDialer(handshakerServiceAddress, grpcOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hsConnMap[handshakerServiceAddress] = hsConn
|
||||
}
|
||||
return hsConn, nil
|
||||
}
|
||||
+389
@@ -0,0 +1,389 @@
|
||||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: internal/proto/common/common.proto
|
||||
|
||||
package common_go_proto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// The ciphersuites supported by S2A. The name determines the confidentiality,
|
||||
// and authentication ciphers as well as the hash algorithm used for PRF in
|
||||
// TLS 1.2 or HKDF in TLS 1.3. Thus, the components of the name are:
|
||||
// - AEAD -- for encryption and authentication, e.g., AES_128_GCM.
|
||||
// - Hash algorithm -- used in PRF or HKDF, e.g., SHA256.
|
||||
type Ciphersuite int32
|
||||
|
||||
const (
|
||||
Ciphersuite_AES_128_GCM_SHA256 Ciphersuite = 0
|
||||
Ciphersuite_AES_256_GCM_SHA384 Ciphersuite = 1
|
||||
Ciphersuite_CHACHA20_POLY1305_SHA256 Ciphersuite = 2
|
||||
)
|
||||
|
||||
// Enum value maps for Ciphersuite.
|
||||
var (
|
||||
Ciphersuite_name = map[int32]string{
|
||||
0: "AES_128_GCM_SHA256",
|
||||
1: "AES_256_GCM_SHA384",
|
||||
2: "CHACHA20_POLY1305_SHA256",
|
||||
}
|
||||
Ciphersuite_value = map[string]int32{
|
||||
"AES_128_GCM_SHA256": 0,
|
||||
"AES_256_GCM_SHA384": 1,
|
||||
"CHACHA20_POLY1305_SHA256": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x Ciphersuite) Enum() *Ciphersuite {
|
||||
p := new(Ciphersuite)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x Ciphersuite) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (Ciphersuite) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_internal_proto_common_common_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (Ciphersuite) Type() protoreflect.EnumType {
|
||||
return &file_internal_proto_common_common_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x Ciphersuite) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Ciphersuite.Descriptor instead.
|
||||
func (Ciphersuite) EnumDescriptor() ([]byte, []int) {
|
||||
return file_internal_proto_common_common_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
// The TLS versions supported by S2A's handshaker module.
|
||||
type TLSVersion int32
|
||||
|
||||
const (
|
||||
TLSVersion_TLS1_2 TLSVersion = 0
|
||||
TLSVersion_TLS1_3 TLSVersion = 1
|
||||
)
|
||||
|
||||
// Enum value maps for TLSVersion.
|
||||
var (
|
||||
TLSVersion_name = map[int32]string{
|
||||
0: "TLS1_2",
|
||||
1: "TLS1_3",
|
||||
}
|
||||
TLSVersion_value = map[string]int32{
|
||||
"TLS1_2": 0,
|
||||
"TLS1_3": 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (x TLSVersion) Enum() *TLSVersion {
|
||||
p := new(TLSVersion)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x TLSVersion) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (TLSVersion) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_internal_proto_common_common_proto_enumTypes[1].Descriptor()
|
||||
}
|
||||
|
||||
func (TLSVersion) Type() protoreflect.EnumType {
|
||||
return &file_internal_proto_common_common_proto_enumTypes[1]
|
||||
}
|
||||
|
||||
func (x TLSVersion) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TLSVersion.Descriptor instead.
|
||||
func (TLSVersion) EnumDescriptor() ([]byte, []int) {
|
||||
return file_internal_proto_common_common_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
type Identity struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// Types that are assignable to IdentityOneof:
|
||||
//
|
||||
// *Identity_SpiffeId
|
||||
// *Identity_Hostname
|
||||
// *Identity_Uid
|
||||
// *Identity_MdbUsername
|
||||
// *Identity_GaiaId
|
||||
IdentityOneof isIdentity_IdentityOneof `protobuf_oneof:"identity_oneof"`
|
||||
// Additional identity-specific attributes.
|
||||
Attributes map[string]string `protobuf:"bytes,3,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
}
|
||||
|
||||
func (x *Identity) Reset() {
|
||||
*x = Identity{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_internal_proto_common_common_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Identity) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Identity) ProtoMessage() {}
|
||||
|
||||
func (x *Identity) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_internal_proto_common_common_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Identity.ProtoReflect.Descriptor instead.
|
||||
func (*Identity) Descriptor() ([]byte, []int) {
|
||||
return file_internal_proto_common_common_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (m *Identity) GetIdentityOneof() isIdentity_IdentityOneof {
|
||||
if m != nil {
|
||||
return m.IdentityOneof
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Identity) GetSpiffeId() string {
|
||||
if x, ok := x.GetIdentityOneof().(*Identity_SpiffeId); ok {
|
||||
return x.SpiffeId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Identity) GetHostname() string {
|
||||
if x, ok := x.GetIdentityOneof().(*Identity_Hostname); ok {
|
||||
return x.Hostname
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Identity) GetUid() string {
|
||||
if x, ok := x.GetIdentityOneof().(*Identity_Uid); ok {
|
||||
return x.Uid
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Identity) GetMdbUsername() string {
|
||||
if x, ok := x.GetIdentityOneof().(*Identity_MdbUsername); ok {
|
||||
return x.MdbUsername
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Identity) GetGaiaId() string {
|
||||
if x, ok := x.GetIdentityOneof().(*Identity_GaiaId); ok {
|
||||
return x.GaiaId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Identity) GetAttributes() map[string]string {
|
||||
if x != nil {
|
||||
return x.Attributes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isIdentity_IdentityOneof interface {
|
||||
isIdentity_IdentityOneof()
|
||||
}
|
||||
|
||||
type Identity_SpiffeId struct {
|
||||
// The SPIFFE ID of a connection endpoint.
|
||||
SpiffeId string `protobuf:"bytes,1,opt,name=spiffe_id,json=spiffeId,proto3,oneof"`
|
||||
}
|
||||
|
||||
type Identity_Hostname struct {
|
||||
// The hostname of a connection endpoint.
|
||||
Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3,oneof"`
|
||||
}
|
||||
|
||||
type Identity_Uid struct {
|
||||
// The UID of a connection endpoint.
|
||||
Uid string `protobuf:"bytes,4,opt,name=uid,proto3,oneof"`
|
||||
}
|
||||
|
||||
type Identity_MdbUsername struct {
|
||||
// The MDB username of a connection endpoint.
|
||||
MdbUsername string `protobuf:"bytes,5,opt,name=mdb_username,json=mdbUsername,proto3,oneof"`
|
||||
}
|
||||
|
||||
type Identity_GaiaId struct {
|
||||
// The Gaia ID of a connection endpoint.
|
||||
GaiaId string `protobuf:"bytes,6,opt,name=gaia_id,json=gaiaId,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*Identity_SpiffeId) isIdentity_IdentityOneof() {}
|
||||
|
||||
func (*Identity_Hostname) isIdentity_IdentityOneof() {}
|
||||
|
||||
func (*Identity_Uid) isIdentity_IdentityOneof() {}
|
||||
|
||||
func (*Identity_MdbUsername) isIdentity_IdentityOneof() {}
|
||||
|
||||
func (*Identity_GaiaId) isIdentity_IdentityOneof() {}
|
||||
|
||||
var File_internal_proto_common_common_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_internal_proto_common_common_proto_rawDesc = []byte{
|
||||
0x0a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
|
||||
0xb1, 0x02, 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1d, 0x0a, 0x09,
|
||||
0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48,
|
||||
0x00, 0x52, 0x08, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x08, 0x68,
|
||||
0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52,
|
||||
0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x03, 0x75, 0x69, 0x64,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x23, 0x0a,
|
||||
0x0c, 0x6d, 0x64, 0x62, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x6d, 0x64, 0x62, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x19, 0x0a, 0x07, 0x67, 0x61, 0x69, 0x61, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20,
|
||||
0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x67, 0x61, 0x69, 0x61, 0x49, 0x64, 0x12, 0x43, 0x0a,
|
||||
0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
|
||||
0x0b, 0x32, 0x23, 0x2e, 0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x64,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
|
||||
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
|
||||
0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
||||
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
|
||||
0x01, 0x42, 0x10, 0x0a, 0x0e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6f, 0x6e,
|
||||
0x65, 0x6f, 0x66, 0x2a, 0x5b, 0x0a, 0x0b, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x73, 0x75, 0x69,
|
||||
0x74, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43,
|
||||
0x4d, 0x5f, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x45,
|
||||
0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f, 0x47, 0x43, 0x4d, 0x5f, 0x53, 0x48, 0x41, 0x33, 0x38, 0x34,
|
||||
0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x48, 0x41, 0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x50,
|
||||
0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x5f, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x02,
|
||||
0x2a, 0x24, 0x0a, 0x0a, 0x54, 0x4c, 0x53, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0a,
|
||||
0x0a, 0x06, 0x54, 0x4c, 0x53, 0x31, 0x5f, 0x32, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x4c,
|
||||
0x53, 0x31, 0x5f, 0x33, 0x10, 0x01, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x32, 0x61, 0x2f,
|
||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x67, 0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_internal_proto_common_common_proto_rawDescOnce sync.Once
|
||||
file_internal_proto_common_common_proto_rawDescData = file_internal_proto_common_common_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_internal_proto_common_common_proto_rawDescGZIP() []byte {
|
||||
file_internal_proto_common_common_proto_rawDescOnce.Do(func() {
|
||||
file_internal_proto_common_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_proto_common_common_proto_rawDescData)
|
||||
})
|
||||
return file_internal_proto_common_common_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_internal_proto_common_common_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_internal_proto_common_common_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_internal_proto_common_common_proto_goTypes = []interface{}{
|
||||
(Ciphersuite)(0), // 0: s2a.proto.Ciphersuite
|
||||
(TLSVersion)(0), // 1: s2a.proto.TLSVersion
|
||||
(*Identity)(nil), // 2: s2a.proto.Identity
|
||||
nil, // 3: s2a.proto.Identity.AttributesEntry
|
||||
}
|
||||
var file_internal_proto_common_common_proto_depIdxs = []int32{
|
||||
3, // 0: s2a.proto.Identity.attributes:type_name -> s2a.proto.Identity.AttributesEntry
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_internal_proto_common_common_proto_init() }
|
||||
func file_internal_proto_common_common_proto_init() {
|
||||
if File_internal_proto_common_common_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_internal_proto_common_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Identity); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
file_internal_proto_common_common_proto_msgTypes[0].OneofWrappers = []interface{}{
|
||||
(*Identity_SpiffeId)(nil),
|
||||
(*Identity_Hostname)(nil),
|
||||
(*Identity_Uid)(nil),
|
||||
(*Identity_MdbUsername)(nil),
|
||||
(*Identity_GaiaId)(nil),
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_internal_proto_common_common_proto_rawDesc,
|
||||
NumEnums: 2,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_internal_proto_common_common_proto_goTypes,
|
||||
DependencyIndexes: file_internal_proto_common_common_proto_depIdxs,
|
||||
EnumInfos: file_internal_proto_common_common_proto_enumTypes,
|
||||
MessageInfos: file_internal_proto_common_common_proto_msgTypes,
|
||||
}.Build()
|
||||
File_internal_proto_common_common_proto = out.File
|
||||
file_internal_proto_common_common_proto_rawDesc = nil
|
||||
file_internal_proto_common_common_proto_goTypes = nil
|
||||
file_internal_proto_common_common_proto_depIdxs = nil
|
||||
}
|
||||
Generated
Vendored
+267
@@ -0,0 +1,267 @@
|
||||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: internal/proto/s2a_context/s2a_context.proto
|
||||
|
||||
package s2a_context_go_proto
|
||||
|
||||
import (
|
||||
common_go_proto "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type S2AContext struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// The application protocol negotiated for this connection, e.g., 'grpc'.
|
||||
ApplicationProtocol string `protobuf:"bytes,1,opt,name=application_protocol,json=applicationProtocol,proto3" json:"application_protocol,omitempty"`
|
||||
// The TLS version number that the S2A's handshaker module used to set up the
|
||||
// session.
|
||||
TlsVersion common_go_proto.TLSVersion `protobuf:"varint,2,opt,name=tls_version,json=tlsVersion,proto3,enum=s2a.proto.TLSVersion" json:"tls_version,omitempty"`
|
||||
// The TLS ciphersuite negotiated by the S2A's handshaker module.
|
||||
Ciphersuite common_go_proto.Ciphersuite `protobuf:"varint,3,opt,name=ciphersuite,proto3,enum=s2a.proto.Ciphersuite" json:"ciphersuite,omitempty"`
|
||||
// The authenticated identity of the peer.
|
||||
PeerIdentity *common_go_proto.Identity `protobuf:"bytes,4,opt,name=peer_identity,json=peerIdentity,proto3" json:"peer_identity,omitempty"`
|
||||
// The local identity used during session setup. This could be:
|
||||
// - The local identity that the client specifies in ClientSessionStartReq.
|
||||
// - One of the local identities that the server specifies in
|
||||
// ServerSessionStartReq.
|
||||
// - If neither client or server specifies local identities, the S2A picks the
|
||||
// default one. In this case, this field will contain that identity.
|
||||
LocalIdentity *common_go_proto.Identity `protobuf:"bytes,5,opt,name=local_identity,json=localIdentity,proto3" json:"local_identity,omitempty"`
|
||||
// The SHA256 hash of the peer certificate used in the handshake.
|
||||
PeerCertFingerprint []byte `protobuf:"bytes,6,opt,name=peer_cert_fingerprint,json=peerCertFingerprint,proto3" json:"peer_cert_fingerprint,omitempty"`
|
||||
// The SHA256 hash of the local certificate used in the handshake.
|
||||
LocalCertFingerprint []byte `protobuf:"bytes,7,opt,name=local_cert_fingerprint,json=localCertFingerprint,proto3" json:"local_cert_fingerprint,omitempty"`
|
||||
// Set to true if a cached session was reused to resume the handshake.
|
||||
IsHandshakeResumed bool `protobuf:"varint,8,opt,name=is_handshake_resumed,json=isHandshakeResumed,proto3" json:"is_handshake_resumed,omitempty"`
|
||||
}
|
||||
|
||||
func (x *S2AContext) Reset() {
|
||||
*x = S2AContext{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_internal_proto_s2a_context_s2a_context_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *S2AContext) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*S2AContext) ProtoMessage() {}
|
||||
|
||||
func (x *S2AContext) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_internal_proto_s2a_context_s2a_context_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use S2AContext.ProtoReflect.Descriptor instead.
|
||||
func (*S2AContext) Descriptor() ([]byte, []int) {
|
||||
return file_internal_proto_s2a_context_s2a_context_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetApplicationProtocol() string {
|
||||
if x != nil {
|
||||
return x.ApplicationProtocol
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetTlsVersion() common_go_proto.TLSVersion {
|
||||
if x != nil {
|
||||
return x.TlsVersion
|
||||
}
|
||||
return common_go_proto.TLSVersion(0)
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetCiphersuite() common_go_proto.Ciphersuite {
|
||||
if x != nil {
|
||||
return x.Ciphersuite
|
||||
}
|
||||
return common_go_proto.Ciphersuite(0)
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetPeerIdentity() *common_go_proto.Identity {
|
||||
if x != nil {
|
||||
return x.PeerIdentity
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetLocalIdentity() *common_go_proto.Identity {
|
||||
if x != nil {
|
||||
return x.LocalIdentity
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetPeerCertFingerprint() []byte {
|
||||
if x != nil {
|
||||
return x.PeerCertFingerprint
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetLocalCertFingerprint() []byte {
|
||||
if x != nil {
|
||||
return x.LocalCertFingerprint
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetIsHandshakeResumed() bool {
|
||||
if x != nil {
|
||||
return x.IsHandshakeResumed
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var File_internal_proto_s2a_context_s2a_context_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_internal_proto_s2a_context_s2a_context_proto_rawDesc = []byte{
|
||||
0x0a, 0x2c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2f, 0x73, 0x32, 0x61, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x73, 0x32, 0x61,
|
||||
0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09,
|
||||
0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x72,
|
||||
0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||
0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc3, 0x03,
|
||||
0x0a, 0x0a, 0x53, 0x32, 0x41, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x31, 0x0a, 0x14,
|
||||
0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x61, 0x70, 0x70, 0x6c,
|
||||
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12,
|
||||
0x36, 0x0a, 0x0b, 0x74, 0x6c, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x54, 0x4c, 0x53, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x74, 0x6c, 0x73,
|
||||
0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x0b, 0x63, 0x69, 0x70, 0x68, 0x65,
|
||||
0x72, 0x73, 0x75, 0x69, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x73,
|
||||
0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x73,
|
||||
0x75, 0x69, 0x74, 0x65, 0x52, 0x0b, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x73, 0x75, 0x69, 0x74,
|
||||
0x65, 0x12, 0x38, 0x0a, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x32, 0x61, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0c, 0x70,
|
||||
0x65, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x3a, 0x0a, 0x0e, 0x6c,
|
||||
0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||
0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49,
|
||||
0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x65, 0x65, 0x72, 0x5f,
|
||||
0x63, 0x65, 0x72, 0x74, 0x5f, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74,
|
||||
0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x70, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74,
|
||||
0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x34, 0x0a, 0x16, 0x6c,
|
||||
0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72,
|
||||
0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x6c, 0x6f, 0x63,
|
||||
0x61, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e,
|
||||
0x74, 0x12, 0x30, 0x0a, 0x14, 0x69, 0x73, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b,
|
||||
0x65, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x12, 0x69, 0x73, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x75,
|
||||
0x6d, 0x65, 0x64, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x32, 0x61, 0x2f, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x32, 0x61, 0x5f,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x67, 0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_internal_proto_s2a_context_s2a_context_proto_rawDescOnce sync.Once
|
||||
file_internal_proto_s2a_context_s2a_context_proto_rawDescData = file_internal_proto_s2a_context_s2a_context_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_internal_proto_s2a_context_s2a_context_proto_rawDescGZIP() []byte {
|
||||
file_internal_proto_s2a_context_s2a_context_proto_rawDescOnce.Do(func() {
|
||||
file_internal_proto_s2a_context_s2a_context_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_proto_s2a_context_s2a_context_proto_rawDescData)
|
||||
})
|
||||
return file_internal_proto_s2a_context_s2a_context_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_internal_proto_s2a_context_s2a_context_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_internal_proto_s2a_context_s2a_context_proto_goTypes = []interface{}{
|
||||
(*S2AContext)(nil), // 0: s2a.proto.S2AContext
|
||||
(common_go_proto.TLSVersion)(0), // 1: s2a.proto.TLSVersion
|
||||
(common_go_proto.Ciphersuite)(0), // 2: s2a.proto.Ciphersuite
|
||||
(*common_go_proto.Identity)(nil), // 3: s2a.proto.Identity
|
||||
}
|
||||
var file_internal_proto_s2a_context_s2a_context_proto_depIdxs = []int32{
|
||||
1, // 0: s2a.proto.S2AContext.tls_version:type_name -> s2a.proto.TLSVersion
|
||||
2, // 1: s2a.proto.S2AContext.ciphersuite:type_name -> s2a.proto.Ciphersuite
|
||||
3, // 2: s2a.proto.S2AContext.peer_identity:type_name -> s2a.proto.Identity
|
||||
3, // 3: s2a.proto.S2AContext.local_identity:type_name -> s2a.proto.Identity
|
||||
4, // [4:4] is the sub-list for method output_type
|
||||
4, // [4:4] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_internal_proto_s2a_context_s2a_context_proto_init() }
|
||||
func file_internal_proto_s2a_context_s2a_context_proto_init() {
|
||||
if File_internal_proto_s2a_context_s2a_context_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_internal_proto_s2a_context_s2a_context_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*S2AContext); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_internal_proto_s2a_context_s2a_context_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_internal_proto_s2a_context_s2a_context_proto_goTypes,
|
||||
DependencyIndexes: file_internal_proto_s2a_context_s2a_context_proto_depIdxs,
|
||||
MessageInfos: file_internal_proto_s2a_context_s2a_context_proto_msgTypes,
|
||||
}.Build()
|
||||
File_internal_proto_s2a_context_s2a_context_proto = out.File
|
||||
file_internal_proto_s2a_context_s2a_context_proto_rawDesc = nil
|
||||
file_internal_proto_s2a_context_s2a_context_proto_goTypes = nil
|
||||
file_internal_proto_s2a_context_s2a_context_proto_depIdxs = nil
|
||||
}
|
||||
+1377
File diff suppressed because it is too large
Load Diff
+173
@@ -0,0 +1,173 @@
|
||||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc v3.21.12
|
||||
// source: internal/proto/s2a/s2a.proto
|
||||
|
||||
package s2a_go_proto
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
const (
|
||||
S2AService_SetUpSession_FullMethodName = "/s2a.proto.S2AService/SetUpSession"
|
||||
)
|
||||
|
||||
// S2AServiceClient is the client API for S2AService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type S2AServiceClient interface {
|
||||
// S2A service accepts a stream of session setup requests and returns a stream
|
||||
// of session setup responses. The client of this service is expected to send
|
||||
// exactly one client_start or server_start message followed by at least one
|
||||
// next message. Applications running TLS clients can send requests with
|
||||
// resumption_ticket messages only after the session is successfully set up.
|
||||
//
|
||||
// Every time S2A client sends a request, this service sends a response.
|
||||
// However, clients do not have to wait for service response before sending
|
||||
// the next request.
|
||||
SetUpSession(ctx context.Context, opts ...grpc.CallOption) (S2AService_SetUpSessionClient, error)
|
||||
}
|
||||
|
||||
type s2AServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewS2AServiceClient(cc grpc.ClientConnInterface) S2AServiceClient {
|
||||
return &s2AServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *s2AServiceClient) SetUpSession(ctx context.Context, opts ...grpc.CallOption) (S2AService_SetUpSessionClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &S2AService_ServiceDesc.Streams[0], S2AService_SetUpSession_FullMethodName, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &s2AServiceSetUpSessionClient{stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type S2AService_SetUpSessionClient interface {
|
||||
Send(*SessionReq) error
|
||||
Recv() (*SessionResp, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type s2AServiceSetUpSessionClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *s2AServiceSetUpSessionClient) Send(m *SessionReq) error {
|
||||
return x.ClientStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *s2AServiceSetUpSessionClient) Recv() (*SessionResp, error) {
|
||||
m := new(SessionResp)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// S2AServiceServer is the server API for S2AService service.
|
||||
// All implementations must embed UnimplementedS2AServiceServer
|
||||
// for forward compatibility
|
||||
type S2AServiceServer interface {
|
||||
// S2A service accepts a stream of session setup requests and returns a stream
|
||||
// of session setup responses. The client of this service is expected to send
|
||||
// exactly one client_start or server_start message followed by at least one
|
||||
// next message. Applications running TLS clients can send requests with
|
||||
// resumption_ticket messages only after the session is successfully set up.
|
||||
//
|
||||
// Every time S2A client sends a request, this service sends a response.
|
||||
// However, clients do not have to wait for service response before sending
|
||||
// the next request.
|
||||
SetUpSession(S2AService_SetUpSessionServer) error
|
||||
mustEmbedUnimplementedS2AServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedS2AServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedS2AServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedS2AServiceServer) SetUpSession(S2AService_SetUpSessionServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method SetUpSession not implemented")
|
||||
}
|
||||
func (UnimplementedS2AServiceServer) mustEmbedUnimplementedS2AServiceServer() {}
|
||||
|
||||
// UnsafeS2AServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to S2AServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeS2AServiceServer interface {
|
||||
mustEmbedUnimplementedS2AServiceServer()
|
||||
}
|
||||
|
||||
func RegisterS2AServiceServer(s grpc.ServiceRegistrar, srv S2AServiceServer) {
|
||||
s.RegisterService(&S2AService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _S2AService_SetUpSession_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(S2AServiceServer).SetUpSession(&s2AServiceSetUpSessionServer{stream})
|
||||
}
|
||||
|
||||
type S2AService_SetUpSessionServer interface {
|
||||
Send(*SessionResp) error
|
||||
Recv() (*SessionReq, error)
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type s2AServiceSetUpSessionServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *s2AServiceSetUpSessionServer) Send(m *SessionResp) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *s2AServiceSetUpSessionServer) Recv() (*SessionReq, error) {
|
||||
m := new(SessionReq)
|
||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// S2AService_ServiceDesc is the grpc.ServiceDesc for S2AService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var S2AService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "s2a.proto.S2AService",
|
||||
HandlerType: (*S2AServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "SetUpSession",
|
||||
Handler: _S2AService_SetUpSession_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "internal/proto/s2a/s2a.proto",
|
||||
}
|
||||
+367
@@ -0,0 +1,367 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: internal/proto/v2/common/common.proto
|
||||
|
||||
package common_go_proto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// The TLS 1.0-1.2 ciphersuites that the application can negotiate when using
|
||||
// S2A.
|
||||
type Ciphersuite int32
|
||||
|
||||
const (
|
||||
Ciphersuite_CIPHERSUITE_UNSPECIFIED Ciphersuite = 0
|
||||
Ciphersuite_CIPHERSUITE_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 Ciphersuite = 1
|
||||
Ciphersuite_CIPHERSUITE_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 Ciphersuite = 2
|
||||
Ciphersuite_CIPHERSUITE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 Ciphersuite = 3
|
||||
Ciphersuite_CIPHERSUITE_ECDHE_RSA_WITH_AES_128_GCM_SHA256 Ciphersuite = 4
|
||||
Ciphersuite_CIPHERSUITE_ECDHE_RSA_WITH_AES_256_GCM_SHA384 Ciphersuite = 5
|
||||
Ciphersuite_CIPHERSUITE_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 Ciphersuite = 6
|
||||
)
|
||||
|
||||
// Enum value maps for Ciphersuite.
|
||||
var (
|
||||
Ciphersuite_name = map[int32]string{
|
||||
0: "CIPHERSUITE_UNSPECIFIED",
|
||||
1: "CIPHERSUITE_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
2: "CIPHERSUITE_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
3: "CIPHERSUITE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||
4: "CIPHERSUITE_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
5: "CIPHERSUITE_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
6: "CIPHERSUITE_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||
}
|
||||
Ciphersuite_value = map[string]int32{
|
||||
"CIPHERSUITE_UNSPECIFIED": 0,
|
||||
"CIPHERSUITE_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": 1,
|
||||
"CIPHERSUITE_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": 2,
|
||||
"CIPHERSUITE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": 3,
|
||||
"CIPHERSUITE_ECDHE_RSA_WITH_AES_128_GCM_SHA256": 4,
|
||||
"CIPHERSUITE_ECDHE_RSA_WITH_AES_256_GCM_SHA384": 5,
|
||||
"CIPHERSUITE_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": 6,
|
||||
}
|
||||
)
|
||||
|
||||
func (x Ciphersuite) Enum() *Ciphersuite {
|
||||
p := new(Ciphersuite)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x Ciphersuite) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (Ciphersuite) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_internal_proto_v2_common_common_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (Ciphersuite) Type() protoreflect.EnumType {
|
||||
return &file_internal_proto_v2_common_common_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x Ciphersuite) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Ciphersuite.Descriptor instead.
|
||||
func (Ciphersuite) EnumDescriptor() ([]byte, []int) {
|
||||
return file_internal_proto_v2_common_common_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
// The TLS versions supported by S2A's handshaker module.
|
||||
type TLSVersion int32
|
||||
|
||||
const (
|
||||
TLSVersion_TLS_VERSION_UNSPECIFIED TLSVersion = 0
|
||||
TLSVersion_TLS_VERSION_1_0 TLSVersion = 1
|
||||
TLSVersion_TLS_VERSION_1_1 TLSVersion = 2
|
||||
TLSVersion_TLS_VERSION_1_2 TLSVersion = 3
|
||||
TLSVersion_TLS_VERSION_1_3 TLSVersion = 4
|
||||
)
|
||||
|
||||
// Enum value maps for TLSVersion.
|
||||
var (
|
||||
TLSVersion_name = map[int32]string{
|
||||
0: "TLS_VERSION_UNSPECIFIED",
|
||||
1: "TLS_VERSION_1_0",
|
||||
2: "TLS_VERSION_1_1",
|
||||
3: "TLS_VERSION_1_2",
|
||||
4: "TLS_VERSION_1_3",
|
||||
}
|
||||
TLSVersion_value = map[string]int32{
|
||||
"TLS_VERSION_UNSPECIFIED": 0,
|
||||
"TLS_VERSION_1_0": 1,
|
||||
"TLS_VERSION_1_1": 2,
|
||||
"TLS_VERSION_1_2": 3,
|
||||
"TLS_VERSION_1_3": 4,
|
||||
}
|
||||
)
|
||||
|
||||
func (x TLSVersion) Enum() *TLSVersion {
|
||||
p := new(TLSVersion)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x TLSVersion) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (TLSVersion) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_internal_proto_v2_common_common_proto_enumTypes[1].Descriptor()
|
||||
}
|
||||
|
||||
func (TLSVersion) Type() protoreflect.EnumType {
|
||||
return &file_internal_proto_v2_common_common_proto_enumTypes[1]
|
||||
}
|
||||
|
||||
func (x TLSVersion) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TLSVersion.Descriptor instead.
|
||||
func (TLSVersion) EnumDescriptor() ([]byte, []int) {
|
||||
return file_internal_proto_v2_common_common_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
// The side in the TLS connection.
|
||||
type ConnectionSide int32
|
||||
|
||||
const (
|
||||
ConnectionSide_CONNECTION_SIDE_UNSPECIFIED ConnectionSide = 0
|
||||
ConnectionSide_CONNECTION_SIDE_CLIENT ConnectionSide = 1
|
||||
ConnectionSide_CONNECTION_SIDE_SERVER ConnectionSide = 2
|
||||
)
|
||||
|
||||
// Enum value maps for ConnectionSide.
|
||||
var (
|
||||
ConnectionSide_name = map[int32]string{
|
||||
0: "CONNECTION_SIDE_UNSPECIFIED",
|
||||
1: "CONNECTION_SIDE_CLIENT",
|
||||
2: "CONNECTION_SIDE_SERVER",
|
||||
}
|
||||
ConnectionSide_value = map[string]int32{
|
||||
"CONNECTION_SIDE_UNSPECIFIED": 0,
|
||||
"CONNECTION_SIDE_CLIENT": 1,
|
||||
"CONNECTION_SIDE_SERVER": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x ConnectionSide) Enum() *ConnectionSide {
|
||||
p := new(ConnectionSide)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x ConnectionSide) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (ConnectionSide) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_internal_proto_v2_common_common_proto_enumTypes[2].Descriptor()
|
||||
}
|
||||
|
||||
func (ConnectionSide) Type() protoreflect.EnumType {
|
||||
return &file_internal_proto_v2_common_common_proto_enumTypes[2]
|
||||
}
|
||||
|
||||
func (x ConnectionSide) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ConnectionSide.Descriptor instead.
|
||||
func (ConnectionSide) EnumDescriptor() ([]byte, []int) {
|
||||
return file_internal_proto_v2_common_common_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
// The ALPN protocols that the application can negotiate during a TLS handshake.
|
||||
type AlpnProtocol int32
|
||||
|
||||
const (
|
||||
AlpnProtocol_ALPN_PROTOCOL_UNSPECIFIED AlpnProtocol = 0
|
||||
AlpnProtocol_ALPN_PROTOCOL_GRPC AlpnProtocol = 1
|
||||
AlpnProtocol_ALPN_PROTOCOL_HTTP2 AlpnProtocol = 2
|
||||
AlpnProtocol_ALPN_PROTOCOL_HTTP1_1 AlpnProtocol = 3
|
||||
)
|
||||
|
||||
// Enum value maps for AlpnProtocol.
|
||||
var (
|
||||
AlpnProtocol_name = map[int32]string{
|
||||
0: "ALPN_PROTOCOL_UNSPECIFIED",
|
||||
1: "ALPN_PROTOCOL_GRPC",
|
||||
2: "ALPN_PROTOCOL_HTTP2",
|
||||
3: "ALPN_PROTOCOL_HTTP1_1",
|
||||
}
|
||||
AlpnProtocol_value = map[string]int32{
|
||||
"ALPN_PROTOCOL_UNSPECIFIED": 0,
|
||||
"ALPN_PROTOCOL_GRPC": 1,
|
||||
"ALPN_PROTOCOL_HTTP2": 2,
|
||||
"ALPN_PROTOCOL_HTTP1_1": 3,
|
||||
}
|
||||
)
|
||||
|
||||
func (x AlpnProtocol) Enum() *AlpnProtocol {
|
||||
p := new(AlpnProtocol)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x AlpnProtocol) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (AlpnProtocol) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_internal_proto_v2_common_common_proto_enumTypes[3].Descriptor()
|
||||
}
|
||||
|
||||
func (AlpnProtocol) Type() protoreflect.EnumType {
|
||||
return &file_internal_proto_v2_common_common_proto_enumTypes[3]
|
||||
}
|
||||
|
||||
func (x AlpnProtocol) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AlpnProtocol.Descriptor instead.
|
||||
func (AlpnProtocol) EnumDescriptor() ([]byte, []int) {
|
||||
return file_internal_proto_v2_common_common_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
var File_internal_proto_v2_common_common_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_internal_proto_v2_common_common_proto_rawDesc = []byte{
|
||||
0x0a, 0x25, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
|
||||
0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x2e, 0x76, 0x32, 0x2a, 0xee, 0x02, 0x0a, 0x0b, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72,
|
||||
0x73, 0x75, 0x69, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x53,
|
||||
0x55, 0x49, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44,
|
||||
0x10, 0x00, 0x12, 0x33, 0x0a, 0x2f, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x53, 0x55, 0x49, 0x54,
|
||||
0x45, 0x5f, 0x45, 0x43, 0x44, 0x48, 0x45, 0x5f, 0x45, 0x43, 0x44, 0x53, 0x41, 0x5f, 0x57, 0x49,
|
||||
0x54, 0x48, 0x5f, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43, 0x4d, 0x5f, 0x53,
|
||||
0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x01, 0x12, 0x33, 0x0a, 0x2f, 0x43, 0x49, 0x50, 0x48, 0x45,
|
||||
0x52, 0x53, 0x55, 0x49, 0x54, 0x45, 0x5f, 0x45, 0x43, 0x44, 0x48, 0x45, 0x5f, 0x45, 0x43, 0x44,
|
||||
0x53, 0x41, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36, 0x5f,
|
||||
0x47, 0x43, 0x4d, 0x5f, 0x53, 0x48, 0x41, 0x33, 0x38, 0x34, 0x10, 0x02, 0x12, 0x39, 0x0a, 0x35,
|
||||
0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x53, 0x55, 0x49, 0x54, 0x45, 0x5f, 0x45, 0x43, 0x44, 0x48,
|
||||
0x45, 0x5f, 0x45, 0x43, 0x44, 0x53, 0x41, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x43, 0x48, 0x41,
|
||||
0x43, 0x48, 0x41, 0x32, 0x30, 0x5f, 0x50, 0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x5f, 0x53,
|
||||
0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x03, 0x12, 0x31, 0x0a, 0x2d, 0x43, 0x49, 0x50, 0x48, 0x45,
|
||||
0x52, 0x53, 0x55, 0x49, 0x54, 0x45, 0x5f, 0x45, 0x43, 0x44, 0x48, 0x45, 0x5f, 0x52, 0x53, 0x41,
|
||||
0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x41, 0x45, 0x53, 0x5f, 0x31, 0x32, 0x38, 0x5f, 0x47, 0x43,
|
||||
0x4d, 0x5f, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x04, 0x12, 0x31, 0x0a, 0x2d, 0x43, 0x49,
|
||||
0x50, 0x48, 0x45, 0x52, 0x53, 0x55, 0x49, 0x54, 0x45, 0x5f, 0x45, 0x43, 0x44, 0x48, 0x45, 0x5f,
|
||||
0x52, 0x53, 0x41, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x41, 0x45, 0x53, 0x5f, 0x32, 0x35, 0x36,
|
||||
0x5f, 0x47, 0x43, 0x4d, 0x5f, 0x53, 0x48, 0x41, 0x33, 0x38, 0x34, 0x10, 0x05, 0x12, 0x37, 0x0a,
|
||||
0x33, 0x43, 0x49, 0x50, 0x48, 0x45, 0x52, 0x53, 0x55, 0x49, 0x54, 0x45, 0x5f, 0x45, 0x43, 0x44,
|
||||
0x48, 0x45, 0x5f, 0x52, 0x53, 0x41, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x43, 0x48, 0x41, 0x43,
|
||||
0x48, 0x41, 0x32, 0x30, 0x5f, 0x50, 0x4f, 0x4c, 0x59, 0x31, 0x33, 0x30, 0x35, 0x5f, 0x53, 0x48,
|
||||
0x41, 0x32, 0x35, 0x36, 0x10, 0x06, 0x2a, 0x7d, 0x0a, 0x0a, 0x54, 0x4c, 0x53, 0x56, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x17, 0x54, 0x4c, 0x53, 0x5f, 0x56, 0x45, 0x52, 0x53,
|
||||
0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
|
||||
0x00, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x4c, 0x53, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e,
|
||||
0x5f, 0x31, 0x5f, 0x30, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x4c, 0x53, 0x5f, 0x56, 0x45,
|
||||
0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x31, 0x5f, 0x31, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x54,
|
||||
0x4c, 0x53, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x31, 0x5f, 0x32, 0x10, 0x03,
|
||||
0x12, 0x13, 0x0a, 0x0f, 0x54, 0x4c, 0x53, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f,
|
||||
0x31, 0x5f, 0x33, 0x10, 0x04, 0x2a, 0x69, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x53, 0x69, 0x64, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x43, 0x4f, 0x4e, 0x4e, 0x45,
|
||||
0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x49, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45,
|
||||
0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x4e,
|
||||
0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x49, 0x44, 0x45, 0x5f, 0x43, 0x4c, 0x49, 0x45,
|
||||
0x4e, 0x54, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49,
|
||||
0x4f, 0x4e, 0x5f, 0x53, 0x49, 0x44, 0x45, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x10, 0x02,
|
||||
0x2a, 0x79, 0x0a, 0x0c, 0x41, 0x6c, 0x70, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
|
||||
0x12, 0x1d, 0x0a, 0x19, 0x41, 0x4c, 0x50, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f,
|
||||
0x4c, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12,
|
||||
0x16, 0x0a, 0x12, 0x41, 0x4c, 0x50, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c,
|
||||
0x5f, 0x47, 0x52, 0x50, 0x43, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x4c, 0x50, 0x4e, 0x5f,
|
||||
0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x48, 0x54, 0x54, 0x50, 0x32, 0x10, 0x02,
|
||||
0x12, 0x19, 0x0a, 0x15, 0x41, 0x4c, 0x50, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f,
|
||||
0x4c, 0x5f, 0x48, 0x54, 0x54, 0x50, 0x31, 0x5f, 0x31, 0x10, 0x03, 0x42, 0x39, 0x5a, 0x37, 0x67,
|
||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x2f, 0x73, 0x32, 0x61, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x67, 0x6f,
|
||||
0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_internal_proto_v2_common_common_proto_rawDescOnce sync.Once
|
||||
file_internal_proto_v2_common_common_proto_rawDescData = file_internal_proto_v2_common_common_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_internal_proto_v2_common_common_proto_rawDescGZIP() []byte {
|
||||
file_internal_proto_v2_common_common_proto_rawDescOnce.Do(func() {
|
||||
file_internal_proto_v2_common_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_proto_v2_common_common_proto_rawDescData)
|
||||
})
|
||||
return file_internal_proto_v2_common_common_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_internal_proto_v2_common_common_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
|
||||
var file_internal_proto_v2_common_common_proto_goTypes = []interface{}{
|
||||
(Ciphersuite)(0), // 0: s2a.proto.v2.Ciphersuite
|
||||
(TLSVersion)(0), // 1: s2a.proto.v2.TLSVersion
|
||||
(ConnectionSide)(0), // 2: s2a.proto.v2.ConnectionSide
|
||||
(AlpnProtocol)(0), // 3: s2a.proto.v2.AlpnProtocol
|
||||
}
|
||||
var file_internal_proto_v2_common_common_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_internal_proto_v2_common_common_proto_init() }
|
||||
func file_internal_proto_v2_common_common_proto_init() {
|
||||
if File_internal_proto_v2_common_common_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_internal_proto_v2_common_common_proto_rawDesc,
|
||||
NumEnums: 4,
|
||||
NumMessages: 0,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_internal_proto_v2_common_common_proto_goTypes,
|
||||
DependencyIndexes: file_internal_proto_v2_common_common_proto_depIdxs,
|
||||
EnumInfos: file_internal_proto_v2_common_common_proto_enumTypes,
|
||||
}.Build()
|
||||
File_internal_proto_v2_common_common_proto = out.File
|
||||
file_internal_proto_v2_common_common_proto_rawDesc = nil
|
||||
file_internal_proto_v2_common_common_proto_goTypes = nil
|
||||
file_internal_proto_v2_common_common_proto_depIdxs = nil
|
||||
}
|
||||
Generated
Vendored
+248
@@ -0,0 +1,248 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: internal/proto/v2/s2a_context/s2a_context.proto
|
||||
|
||||
package s2a_context_go_proto
|
||||
|
||||
import (
|
||||
common_go_proto "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type S2AContext struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// The SPIFFE ID from the peer leaf certificate, if present.
|
||||
//
|
||||
// This field is only populated if the leaf certificate is a valid SPIFFE
|
||||
// SVID; in particular, there is a unique URI SAN and this URI SAN is a valid
|
||||
// SPIFFE ID.
|
||||
LeafCertSpiffeId string `protobuf:"bytes,1,opt,name=leaf_cert_spiffe_id,json=leafCertSpiffeId,proto3" json:"leaf_cert_spiffe_id,omitempty"`
|
||||
// The URIs that are present in the SubjectAltName extension of the peer leaf
|
||||
// certificate.
|
||||
//
|
||||
// Note that the extracted URIs are not validated and may not be properly
|
||||
// formatted.
|
||||
LeafCertUris []string `protobuf:"bytes,2,rep,name=leaf_cert_uris,json=leafCertUris,proto3" json:"leaf_cert_uris,omitempty"`
|
||||
// The DNSNames that are present in the SubjectAltName extension of the peer
|
||||
// leaf certificate.
|
||||
LeafCertDnsnames []string `protobuf:"bytes,3,rep,name=leaf_cert_dnsnames,json=leafCertDnsnames,proto3" json:"leaf_cert_dnsnames,omitempty"`
|
||||
// The (ordered) list of fingerprints in the certificate chain used to verify
|
||||
// the given leaf certificate. The order MUST be from leaf certificate
|
||||
// fingerprint to root certificate fingerprint.
|
||||
//
|
||||
// A fingerprint is the base-64 encoding of the SHA256 hash of the
|
||||
// DER-encoding of a certificate. The list MAY be populated even if the peer
|
||||
// certificate chain was NOT validated successfully.
|
||||
PeerCertificateChainFingerprints []string `protobuf:"bytes,4,rep,name=peer_certificate_chain_fingerprints,json=peerCertificateChainFingerprints,proto3" json:"peer_certificate_chain_fingerprints,omitempty"`
|
||||
// The local identity used during session setup.
|
||||
LocalIdentity *common_go_proto.Identity `protobuf:"bytes,5,opt,name=local_identity,json=localIdentity,proto3" json:"local_identity,omitempty"`
|
||||
// The SHA256 hash of the DER-encoding of the local leaf certificate used in
|
||||
// the handshake.
|
||||
LocalLeafCertFingerprint []byte `protobuf:"bytes,6,opt,name=local_leaf_cert_fingerprint,json=localLeafCertFingerprint,proto3" json:"local_leaf_cert_fingerprint,omitempty"`
|
||||
}
|
||||
|
||||
func (x *S2AContext) Reset() {
|
||||
*x = S2AContext{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_internal_proto_v2_s2a_context_s2a_context_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *S2AContext) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*S2AContext) ProtoMessage() {}
|
||||
|
||||
func (x *S2AContext) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_internal_proto_v2_s2a_context_s2a_context_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use S2AContext.ProtoReflect.Descriptor instead.
|
||||
func (*S2AContext) Descriptor() ([]byte, []int) {
|
||||
return file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetLeafCertSpiffeId() string {
|
||||
if x != nil {
|
||||
return x.LeafCertSpiffeId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetLeafCertUris() []string {
|
||||
if x != nil {
|
||||
return x.LeafCertUris
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetLeafCertDnsnames() []string {
|
||||
if x != nil {
|
||||
return x.LeafCertDnsnames
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetPeerCertificateChainFingerprints() []string {
|
||||
if x != nil {
|
||||
return x.PeerCertificateChainFingerprints
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetLocalIdentity() *common_go_proto.Identity {
|
||||
if x != nil {
|
||||
return x.LocalIdentity
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *S2AContext) GetLocalLeafCertFingerprint() []byte {
|
||||
if x != nil {
|
||||
return x.LocalLeafCertFingerprint
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_internal_proto_v2_s2a_context_s2a_context_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_internal_proto_v2_s2a_context_s2a_context_proto_rawDesc = []byte{
|
||||
0x0a, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2f, 0x76, 0x32, 0x2f, 0x73, 0x32, 0x61, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2f,
|
||||
0x73, 0x32, 0x61, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x12, 0x0c, 0x73, 0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x32, 0x1a,
|
||||
0x22, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x22, 0xd9, 0x02, 0x0a, 0x0a, 0x53, 0x32, 0x41, 0x43, 0x6f, 0x6e, 0x74, 0x65,
|
||||
0x78, 0x74, 0x12, 0x2d, 0x0a, 0x13, 0x6c, 0x65, 0x61, 0x66, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f,
|
||||
0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x10, 0x6c, 0x65, 0x61, 0x66, 0x43, 0x65, 0x72, 0x74, 0x53, 0x70, 0x69, 0x66, 0x66, 0x65, 0x49,
|
||||
0x64, 0x12, 0x24, 0x0a, 0x0e, 0x6c, 0x65, 0x61, 0x66, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x75,
|
||||
0x72, 0x69, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x65, 0x61, 0x66, 0x43,
|
||||
0x65, 0x72, 0x74, 0x55, 0x72, 0x69, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6c, 0x65, 0x61, 0x66, 0x5f,
|
||||
0x63, 0x65, 0x72, 0x74, 0x5f, 0x64, 0x6e, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20,
|
||||
0x03, 0x28, 0x09, 0x52, 0x10, 0x6c, 0x65, 0x61, 0x66, 0x43, 0x65, 0x72, 0x74, 0x44, 0x6e, 0x73,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x4d, 0x0a, 0x23, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x63, 0x65,
|
||||
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f,
|
||||
0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x20, 0x70, 0x65, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
|
||||
0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72,
|
||||
0x69, 0x6e, 0x74, 0x73, 0x12, 0x3a, 0x0a, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x69, 0x64,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73,
|
||||
0x32, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
|
||||
0x79, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79,
|
||||
0x12, 0x3d, 0x0a, 0x1b, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x6c, 0x65, 0x61, 0x66, 0x5f, 0x63,
|
||||
0x65, 0x72, 0x74, 0x5f, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x18,
|
||||
0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x18, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x4c, 0x65, 0x61, 0x66,
|
||||
0x43, 0x65, 0x72, 0x74, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x42,
|
||||
0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x32, 0x61, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
|
||||
0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x32, 0x61, 0x5f, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x67, 0x6f, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescOnce sync.Once
|
||||
file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescData = file_internal_proto_v2_s2a_context_s2a_context_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescGZIP() []byte {
|
||||
file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescOnce.Do(func() {
|
||||
file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescData)
|
||||
})
|
||||
return file_internal_proto_v2_s2a_context_s2a_context_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_internal_proto_v2_s2a_context_s2a_context_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_internal_proto_v2_s2a_context_s2a_context_proto_goTypes = []interface{}{
|
||||
(*S2AContext)(nil), // 0: s2a.proto.v2.S2AContext
|
||||
(*common_go_proto.Identity)(nil), // 1: s2a.proto.Identity
|
||||
}
|
||||
var file_internal_proto_v2_s2a_context_s2a_context_proto_depIdxs = []int32{
|
||||
1, // 0: s2a.proto.v2.S2AContext.local_identity:type_name -> s2a.proto.Identity
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_internal_proto_v2_s2a_context_s2a_context_proto_init() }
|
||||
func file_internal_proto_v2_s2a_context_s2a_context_proto_init() {
|
||||
if File_internal_proto_v2_s2a_context_s2a_context_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_internal_proto_v2_s2a_context_s2a_context_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*S2AContext); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_internal_proto_v2_s2a_context_s2a_context_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_internal_proto_v2_s2a_context_s2a_context_proto_goTypes,
|
||||
DependencyIndexes: file_internal_proto_v2_s2a_context_s2a_context_proto_depIdxs,
|
||||
MessageInfos: file_internal_proto_v2_s2a_context_s2a_context_proto_msgTypes,
|
||||
}.Build()
|
||||
File_internal_proto_v2_s2a_context_s2a_context_proto = out.File
|
||||
file_internal_proto_v2_s2a_context_s2a_context_proto_rawDesc = nil
|
||||
file_internal_proto_v2_s2a_context_s2a_context_proto_goTypes = nil
|
||||
file_internal_proto_v2_s2a_context_s2a_context_proto_depIdxs = nil
|
||||
}
|
||||
+2480
File diff suppressed because it is too large
Load Diff
+159
@@ -0,0 +1,159 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc v3.21.12
|
||||
// source: internal/proto/v2/s2a/s2a.proto
|
||||
|
||||
package s2a_go_proto
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
const (
|
||||
S2AService_SetUpSession_FullMethodName = "/s2a.proto.v2.S2AService/SetUpSession"
|
||||
)
|
||||
|
||||
// S2AServiceClient is the client API for S2AService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type S2AServiceClient interface {
|
||||
// SetUpSession is a bidirectional stream used by applications to offload
|
||||
// operations from the TLS handshake.
|
||||
SetUpSession(ctx context.Context, opts ...grpc.CallOption) (S2AService_SetUpSessionClient, error)
|
||||
}
|
||||
|
||||
type s2AServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewS2AServiceClient(cc grpc.ClientConnInterface) S2AServiceClient {
|
||||
return &s2AServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *s2AServiceClient) SetUpSession(ctx context.Context, opts ...grpc.CallOption) (S2AService_SetUpSessionClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &S2AService_ServiceDesc.Streams[0], S2AService_SetUpSession_FullMethodName, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &s2AServiceSetUpSessionClient{stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type S2AService_SetUpSessionClient interface {
|
||||
Send(*SessionReq) error
|
||||
Recv() (*SessionResp, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type s2AServiceSetUpSessionClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *s2AServiceSetUpSessionClient) Send(m *SessionReq) error {
|
||||
return x.ClientStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *s2AServiceSetUpSessionClient) Recv() (*SessionResp, error) {
|
||||
m := new(SessionResp)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// S2AServiceServer is the server API for S2AService service.
|
||||
// All implementations must embed UnimplementedS2AServiceServer
|
||||
// for forward compatibility
|
||||
type S2AServiceServer interface {
|
||||
// SetUpSession is a bidirectional stream used by applications to offload
|
||||
// operations from the TLS handshake.
|
||||
SetUpSession(S2AService_SetUpSessionServer) error
|
||||
mustEmbedUnimplementedS2AServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedS2AServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedS2AServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedS2AServiceServer) SetUpSession(S2AService_SetUpSessionServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method SetUpSession not implemented")
|
||||
}
|
||||
func (UnimplementedS2AServiceServer) mustEmbedUnimplementedS2AServiceServer() {}
|
||||
|
||||
// UnsafeS2AServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to S2AServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeS2AServiceServer interface {
|
||||
mustEmbedUnimplementedS2AServiceServer()
|
||||
}
|
||||
|
||||
func RegisterS2AServiceServer(s grpc.ServiceRegistrar, srv S2AServiceServer) {
|
||||
s.RegisterService(&S2AService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _S2AService_SetUpSession_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(S2AServiceServer).SetUpSession(&s2AServiceSetUpSessionServer{stream})
|
||||
}
|
||||
|
||||
type S2AService_SetUpSessionServer interface {
|
||||
Send(*SessionResp) error
|
||||
Recv() (*SessionReq, error)
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type s2AServiceSetUpSessionServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *s2AServiceSetUpSessionServer) Send(m *SessionResp) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *s2AServiceSetUpSessionServer) Recv() (*SessionReq, error) {
|
||||
m := new(SessionReq)
|
||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// S2AService_ServiceDesc is the grpc.ServiceDesc for S2AService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var S2AService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "s2a.proto.v2.S2AService",
|
||||
HandlerType: (*S2AServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "SetUpSession",
|
||||
Handler: _S2AService_SetUpSession_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "internal/proto/v2/s2a/s2a.proto",
|
||||
}
|
||||
Generated
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package aeadcrypter provides the interface for AEAD cipher implementations
|
||||
// used by S2A's record protocol.
|
||||
package aeadcrypter
|
||||
|
||||
// S2AAEADCrypter is the interface for an AEAD cipher used by the S2A record
|
||||
// protocol.
|
||||
type S2AAEADCrypter interface {
|
||||
// Encrypt encrypts the plaintext and computes the tag of dst and plaintext.
|
||||
// dst and plaintext may fully overlap or not at all.
|
||||
Encrypt(dst, plaintext, nonce, aad []byte) ([]byte, error)
|
||||
// Decrypt decrypts ciphertext and verifies the tag. dst and ciphertext may
|
||||
// fully overlap or not at all.
|
||||
Decrypt(dst, ciphertext, nonce, aad []byte) ([]byte, error)
|
||||
// TagSize returns the tag size in bytes.
|
||||
TagSize() int
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package aeadcrypter
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Supported key sizes in bytes.
|
||||
const (
|
||||
AES128GCMKeySize = 16
|
||||
AES256GCMKeySize = 32
|
||||
)
|
||||
|
||||
// aesgcm is the struct that holds an AES-GCM cipher for the S2A AEAD crypter.
|
||||
type aesgcm struct {
|
||||
aead cipher.AEAD
|
||||
}
|
||||
|
||||
// NewAESGCM creates an AES-GCM crypter instance. Note that the key must be
|
||||
// either 128 bits or 256 bits.
|
||||
func NewAESGCM(key []byte) (S2AAEADCrypter, error) {
|
||||
if len(key) != AES128GCMKeySize && len(key) != AES256GCMKeySize {
|
||||
return nil, fmt.Errorf("%d or %d bytes, given: %d", AES128GCMKeySize, AES256GCMKeySize, len(key))
|
||||
}
|
||||
c, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a, err := cipher.NewGCM(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &aesgcm{aead: a}, nil
|
||||
}
|
||||
|
||||
// Encrypt is the encryption function. dst can contain bytes at the beginning of
|
||||
// the ciphertext that will not be encrypted but will be authenticated. If dst
|
||||
// has enough capacity to hold these bytes, the ciphertext and the tag, no
|
||||
// allocation and copy operations will be performed. dst and plaintext may
|
||||
// fully overlap or not at all.
|
||||
func (s *aesgcm) Encrypt(dst, plaintext, nonce, aad []byte) ([]byte, error) {
|
||||
return encrypt(s.aead, dst, plaintext, nonce, aad)
|
||||
}
|
||||
|
||||
func (s *aesgcm) Decrypt(dst, ciphertext, nonce, aad []byte) ([]byte, error) {
|
||||
return decrypt(s.aead, dst, ciphertext, nonce, aad)
|
||||
}
|
||||
|
||||
func (s *aesgcm) TagSize() int {
|
||||
return TagSize
|
||||
}
|
||||
Generated
Vendored
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package aeadcrypter
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
)
|
||||
|
||||
// Supported key size in bytes.
|
||||
const (
|
||||
Chacha20Poly1305KeySize = 32
|
||||
)
|
||||
|
||||
// chachapoly is the struct that holds a CHACHA-POLY cipher for the S2A AEAD
|
||||
// crypter.
|
||||
type chachapoly struct {
|
||||
aead cipher.AEAD
|
||||
}
|
||||
|
||||
// NewChachaPoly creates a Chacha-Poly crypter instance. Note that the key must
|
||||
// be Chacha20Poly1305KeySize bytes in length.
|
||||
func NewChachaPoly(key []byte) (S2AAEADCrypter, error) {
|
||||
if len(key) != Chacha20Poly1305KeySize {
|
||||
return nil, fmt.Errorf("%d bytes, given: %d", Chacha20Poly1305KeySize, len(key))
|
||||
}
|
||||
c, err := chacha20poly1305.New(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &chachapoly{aead: c}, nil
|
||||
}
|
||||
|
||||
// Encrypt is the encryption function. dst can contain bytes at the beginning of
|
||||
// the ciphertext that will not be encrypted but will be authenticated. If dst
|
||||
// has enough capacity to hold these bytes, the ciphertext and the tag, no
|
||||
// allocation and copy operations will be performed. dst and plaintext may
|
||||
// fully overlap or not at all.
|
||||
func (s *chachapoly) Encrypt(dst, plaintext, nonce, aad []byte) ([]byte, error) {
|
||||
return encrypt(s.aead, dst, plaintext, nonce, aad)
|
||||
}
|
||||
|
||||
func (s *chachapoly) Decrypt(dst, ciphertext, nonce, aad []byte) ([]byte, error) {
|
||||
return decrypt(s.aead, dst, ciphertext, nonce, aad)
|
||||
}
|
||||
|
||||
func (s *chachapoly) TagSize() int {
|
||||
return TagSize
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package aeadcrypter
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
// TagSize is the tag size in bytes for AES-128-GCM-SHA256,
|
||||
// AES-256-GCM-SHA384, and CHACHA20-POLY1305-SHA256.
|
||||
TagSize = 16
|
||||
// NonceSize is the size of the nonce in number of bytes for
|
||||
// AES-128-GCM-SHA256, AES-256-GCM-SHA384, and CHACHA20-POLY1305-SHA256.
|
||||
NonceSize = 12
|
||||
// SHA256DigestSize is the digest size of sha256 in bytes.
|
||||
SHA256DigestSize = 32
|
||||
// SHA384DigestSize is the digest size of sha384 in bytes.
|
||||
SHA384DigestSize = 48
|
||||
)
|
||||
|
||||
// sliceForAppend takes a slice and a requested number of bytes. It returns a
|
||||
// slice with the contents of the given slice followed by that many bytes and a
|
||||
// second slice that aliases into it and contains only the extra bytes. If the
|
||||
// original slice has sufficient capacity then no allocation is performed.
|
||||
func sliceForAppend(in []byte, n int) (head, tail []byte) {
|
||||
if total := len(in) + n; cap(in) >= total {
|
||||
head = in[:total]
|
||||
} else {
|
||||
head = make([]byte, total)
|
||||
copy(head, in)
|
||||
}
|
||||
tail = head[len(in):]
|
||||
return head, tail
|
||||
}
|
||||
|
||||
// encrypt is the encryption function for an AEAD crypter. aead determines
|
||||
// the type of AEAD crypter. dst can contain bytes at the beginning of the
|
||||
// ciphertext that will not be encrypted but will be authenticated. If dst has
|
||||
// enough capacity to hold these bytes, the ciphertext and the tag, no
|
||||
// allocation and copy operations will be performed. dst and plaintext may
|
||||
// fully overlap or not at all.
|
||||
func encrypt(aead cipher.AEAD, dst, plaintext, nonce, aad []byte) ([]byte, error) {
|
||||
if len(nonce) != NonceSize {
|
||||
return nil, fmt.Errorf("nonce size must be %d bytes. received: %d", NonceSize, len(nonce))
|
||||
}
|
||||
// If we need to allocate an output buffer, we want to include space for
|
||||
// the tag to avoid forcing the caller to reallocate as well.
|
||||
dlen := len(dst)
|
||||
dst, out := sliceForAppend(dst, len(plaintext)+TagSize)
|
||||
data := out[:len(plaintext)]
|
||||
copy(data, plaintext) // data may fully overlap plaintext
|
||||
|
||||
// Seal appends the ciphertext and the tag to its first argument and
|
||||
// returns the updated slice. However, sliceForAppend above ensures that
|
||||
// dst has enough capacity to avoid a reallocation and copy due to the
|
||||
// append.
|
||||
dst = aead.Seal(dst[:dlen], nonce, data, aad)
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// decrypt is the decryption function for an AEAD crypter, where aead determines
|
||||
// the type of AEAD crypter, and dst the destination bytes for the decrypted
|
||||
// ciphertext. The dst buffer may fully overlap with plaintext or not at all.
|
||||
func decrypt(aead cipher.AEAD, dst, ciphertext, nonce, aad []byte) ([]byte, error) {
|
||||
if len(nonce) != NonceSize {
|
||||
return nil, fmt.Errorf("nonce size must be %d bytes. received: %d", NonceSize, len(nonce))
|
||||
}
|
||||
// If dst is equal to ciphertext[:0], ciphertext storage is reused.
|
||||
plaintext, err := aead.Open(dst, nonce, ciphertext, aad)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("message auth failed: %v", err)
|
||||
}
|
||||
return plaintext, nil
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package halfconn
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"fmt"
|
||||
"hash"
|
||||
|
||||
s2apb "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
"github.com/google/s2a-go/internal/record/internal/aeadcrypter"
|
||||
)
|
||||
|
||||
// ciphersuite is the interface for retrieving ciphersuite-specific information
|
||||
// and utilities.
|
||||
type ciphersuite interface {
|
||||
// keySize returns the key size in bytes. This refers to the key used by
|
||||
// the AEAD crypter. This is derived by calling HKDF expand on the traffic
|
||||
// secret.
|
||||
keySize() int
|
||||
// nonceSize returns the nonce size in bytes.
|
||||
nonceSize() int
|
||||
// trafficSecretSize returns the traffic secret size in bytes. This refers
|
||||
// to the secret used to derive the traffic key and nonce, as specified in
|
||||
// https://tools.ietf.org/html/rfc8446#section-7.
|
||||
trafficSecretSize() int
|
||||
// hashFunction returns the hash function for the ciphersuite.
|
||||
hashFunction() func() hash.Hash
|
||||
// aeadCrypter takes a key and creates an AEAD crypter for the ciphersuite
|
||||
// using that key.
|
||||
aeadCrypter(key []byte) (aeadcrypter.S2AAEADCrypter, error)
|
||||
}
|
||||
|
||||
func newCiphersuite(ciphersuite s2apb.Ciphersuite) (ciphersuite, error) {
|
||||
switch ciphersuite {
|
||||
case s2apb.Ciphersuite_AES_128_GCM_SHA256:
|
||||
return &aesgcm128sha256{}, nil
|
||||
case s2apb.Ciphersuite_AES_256_GCM_SHA384:
|
||||
return &aesgcm256sha384{}, nil
|
||||
case s2apb.Ciphersuite_CHACHA20_POLY1305_SHA256:
|
||||
return &chachapolysha256{}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unrecognized ciphersuite: %v", ciphersuite)
|
||||
}
|
||||
}
|
||||
|
||||
// aesgcm128sha256 is the AES-128-GCM-SHA256 implementation of the ciphersuite
|
||||
// interface.
|
||||
type aesgcm128sha256 struct{}
|
||||
|
||||
func (aesgcm128sha256) keySize() int { return aeadcrypter.AES128GCMKeySize }
|
||||
func (aesgcm128sha256) nonceSize() int { return aeadcrypter.NonceSize }
|
||||
func (aesgcm128sha256) trafficSecretSize() int { return aeadcrypter.SHA256DigestSize }
|
||||
func (aesgcm128sha256) hashFunction() func() hash.Hash { return sha256.New }
|
||||
func (aesgcm128sha256) aeadCrypter(key []byte) (aeadcrypter.S2AAEADCrypter, error) {
|
||||
return aeadcrypter.NewAESGCM(key)
|
||||
}
|
||||
|
||||
// aesgcm256sha384 is the AES-256-GCM-SHA384 implementation of the ciphersuite
|
||||
// interface.
|
||||
type aesgcm256sha384 struct{}
|
||||
|
||||
func (aesgcm256sha384) keySize() int { return aeadcrypter.AES256GCMKeySize }
|
||||
func (aesgcm256sha384) nonceSize() int { return aeadcrypter.NonceSize }
|
||||
func (aesgcm256sha384) trafficSecretSize() int { return aeadcrypter.SHA384DigestSize }
|
||||
func (aesgcm256sha384) hashFunction() func() hash.Hash { return sha512.New384 }
|
||||
func (aesgcm256sha384) aeadCrypter(key []byte) (aeadcrypter.S2AAEADCrypter, error) {
|
||||
return aeadcrypter.NewAESGCM(key)
|
||||
}
|
||||
|
||||
// chachapolysha256 is the ChaChaPoly-SHA256 implementation of the ciphersuite
|
||||
// interface.
|
||||
type chachapolysha256 struct{}
|
||||
|
||||
func (chachapolysha256) keySize() int { return aeadcrypter.Chacha20Poly1305KeySize }
|
||||
func (chachapolysha256) nonceSize() int { return aeadcrypter.NonceSize }
|
||||
func (chachapolysha256) trafficSecretSize() int { return aeadcrypter.SHA256DigestSize }
|
||||
func (chachapolysha256) hashFunction() func() hash.Hash { return sha256.New }
|
||||
func (chachapolysha256) aeadCrypter(key []byte) (aeadcrypter.S2AAEADCrypter, error) {
|
||||
return aeadcrypter.NewChachaPoly(key)
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package halfconn
|
||||
|
||||
import "errors"
|
||||
|
||||
// counter is a 64-bit counter.
|
||||
type counter struct {
|
||||
val uint64
|
||||
hasOverflowed bool
|
||||
}
|
||||
|
||||
// newCounter creates a new counter with the initial value set to val.
|
||||
func newCounter(val uint64) counter {
|
||||
return counter{val: val}
|
||||
}
|
||||
|
||||
// value returns the current value of the counter.
|
||||
func (c *counter) value() (uint64, error) {
|
||||
if c.hasOverflowed {
|
||||
return 0, errors.New("counter has overflowed")
|
||||
}
|
||||
return c.val, nil
|
||||
}
|
||||
|
||||
// increment increments the counter and checks for overflow.
|
||||
func (c *counter) increment() {
|
||||
// If the counter is already invalid due to overflow, there is no need to
|
||||
// increase it. We check for the hasOverflowed flag in the call to value().
|
||||
if c.hasOverflowed {
|
||||
return
|
||||
}
|
||||
c.val++
|
||||
if c.val == 0 {
|
||||
c.hasOverflowed = true
|
||||
}
|
||||
}
|
||||
|
||||
// reset sets the counter value to zero and sets the hasOverflowed flag to
|
||||
// false.
|
||||
func (c *counter) reset() {
|
||||
c.val = 0
|
||||
c.hasOverflowed = false
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package halfconn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash"
|
||||
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
|
||||
// hkdfExpander is the interface for the HKDF expansion function; see
|
||||
// https://tools.ietf.org/html/rfc5869 for details. its use in TLS 1.3 is
|
||||
// specified in https://tools.ietf.org/html/rfc8446#section-7.2
|
||||
type hkdfExpander interface {
|
||||
// expand takes a secret, a label, and the output length in bytes, and
|
||||
// returns the resulting expanded key.
|
||||
expand(secret, label []byte, length int) ([]byte, error)
|
||||
}
|
||||
|
||||
// defaultHKDFExpander is the default HKDF expander which uses Go's crypto/hkdf
|
||||
// for HKDF expansion.
|
||||
type defaultHKDFExpander struct {
|
||||
h func() hash.Hash
|
||||
}
|
||||
|
||||
// newDefaultHKDFExpander creates an instance of the default HKDF expander
|
||||
// using the given hash function.
|
||||
func newDefaultHKDFExpander(h func() hash.Hash) hkdfExpander {
|
||||
return &defaultHKDFExpander{h: h}
|
||||
}
|
||||
|
||||
func (d *defaultHKDFExpander) expand(secret, label []byte, length int) ([]byte, error) {
|
||||
outBuf := make([]byte, length)
|
||||
n, err := hkdf.Expand(d.h, secret, label).Read(outBuf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("hkdf.Expand.Read failed with error: %v", err)
|
||||
}
|
||||
if n < length {
|
||||
return nil, fmt.Errorf("hkdf.Expand.Read returned unexpected length, got %d, want %d", n, length)
|
||||
}
|
||||
return outBuf, nil
|
||||
}
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package halfconn manages the inbound or outbound traffic of a TLS 1.3
|
||||
// connection.
|
||||
package halfconn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
s2apb "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
"github.com/google/s2a-go/internal/record/internal/aeadcrypter"
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
)
|
||||
|
||||
// The constants below were taken from Section 7.2 and 7.3 in
|
||||
// https://tools.ietf.org/html/rfc8446#section-7. They are used as the label
|
||||
// in HKDF-Expand-Label.
|
||||
const (
|
||||
tls13Key = "tls13 key"
|
||||
tls13Nonce = "tls13 iv"
|
||||
tls13Update = "tls13 traffic upd"
|
||||
)
|
||||
|
||||
// S2AHalfConnection stores the state of the TLS 1.3 connection in the
|
||||
// inbound or outbound direction.
|
||||
type S2AHalfConnection struct {
|
||||
cs ciphersuite
|
||||
expander hkdfExpander
|
||||
// mutex guards sequence, aeadCrypter, trafficSecret, and nonce.
|
||||
mutex sync.Mutex
|
||||
aeadCrypter aeadcrypter.S2AAEADCrypter
|
||||
sequence counter
|
||||
trafficSecret []byte
|
||||
nonce []byte
|
||||
}
|
||||
|
||||
// New creates a new instance of S2AHalfConnection given a ciphersuite and a
|
||||
// traffic secret.
|
||||
func New(ciphersuite s2apb.Ciphersuite, trafficSecret []byte, sequence uint64) (*S2AHalfConnection, error) {
|
||||
cs, err := newCiphersuite(ciphersuite)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create new ciphersuite: %v", ciphersuite)
|
||||
}
|
||||
if cs.trafficSecretSize() != len(trafficSecret) {
|
||||
return nil, fmt.Errorf("supplied traffic secret must be %v bytes, given: %v bytes", cs.trafficSecretSize(), len(trafficSecret))
|
||||
}
|
||||
|
||||
hc := &S2AHalfConnection{cs: cs, expander: newDefaultHKDFExpander(cs.hashFunction()), sequence: newCounter(sequence), trafficSecret: trafficSecret}
|
||||
if err = hc.updateCrypterAndNonce(hc.trafficSecret); err != nil {
|
||||
return nil, fmt.Errorf("failed to create half connection using traffic secret: %v", err)
|
||||
}
|
||||
|
||||
return hc, nil
|
||||
}
|
||||
|
||||
// Encrypt encrypts the plaintext and computes the tag of dst and plaintext.
|
||||
// dst and plaintext may fully overlap or not at all. Note that the sequence
|
||||
// number will still be incremented on failure, unless the sequence has
|
||||
// overflowed.
|
||||
func (hc *S2AHalfConnection) Encrypt(dst, plaintext, aad []byte) ([]byte, error) {
|
||||
hc.mutex.Lock()
|
||||
sequence, err := hc.getAndIncrementSequence()
|
||||
if err != nil {
|
||||
hc.mutex.Unlock()
|
||||
return nil, err
|
||||
}
|
||||
nonce := hc.maskedNonce(sequence)
|
||||
crypter := hc.aeadCrypter
|
||||
hc.mutex.Unlock()
|
||||
return crypter.Encrypt(dst, plaintext, nonce, aad)
|
||||
}
|
||||
|
||||
// Decrypt decrypts ciphertext and verifies the tag. dst and ciphertext may
|
||||
// fully overlap or not at all. Note that the sequence number will still be
|
||||
// incremented on failure, unless the sequence has overflowed.
|
||||
func (hc *S2AHalfConnection) Decrypt(dst, ciphertext, aad []byte) ([]byte, error) {
|
||||
hc.mutex.Lock()
|
||||
sequence, err := hc.getAndIncrementSequence()
|
||||
if err != nil {
|
||||
hc.mutex.Unlock()
|
||||
return nil, err
|
||||
}
|
||||
nonce := hc.maskedNonce(sequence)
|
||||
crypter := hc.aeadCrypter
|
||||
hc.mutex.Unlock()
|
||||
return crypter.Decrypt(dst, ciphertext, nonce, aad)
|
||||
}
|
||||
|
||||
// UpdateKey advances the traffic secret key, as specified in
|
||||
// https://tools.ietf.org/html/rfc8446#section-7.2. In addition, it derives
|
||||
// a new key and nonce, and resets the sequence number.
|
||||
func (hc *S2AHalfConnection) UpdateKey() error {
|
||||
hc.mutex.Lock()
|
||||
defer hc.mutex.Unlock()
|
||||
|
||||
var err error
|
||||
hc.trafficSecret, err = hc.deriveSecret(hc.trafficSecret, []byte(tls13Update), hc.cs.trafficSecretSize())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to derive traffic secret: %v", err)
|
||||
}
|
||||
|
||||
if err = hc.updateCrypterAndNonce(hc.trafficSecret); err != nil {
|
||||
return fmt.Errorf("failed to update half connection: %v", err)
|
||||
}
|
||||
|
||||
hc.sequence.reset()
|
||||
return nil
|
||||
}
|
||||
|
||||
// TagSize returns the tag size in bytes of the underlying AEAD crypter.
|
||||
func (hc *S2AHalfConnection) TagSize() int {
|
||||
return hc.aeadCrypter.TagSize()
|
||||
}
|
||||
|
||||
// updateCrypterAndNonce takes a new traffic secret and updates the crypter
|
||||
// and nonce. Note that the mutex must be held while calling this function.
|
||||
func (hc *S2AHalfConnection) updateCrypterAndNonce(newTrafficSecret []byte) error {
|
||||
key, err := hc.deriveSecret(newTrafficSecret, []byte(tls13Key), hc.cs.keySize())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update key: %v", err)
|
||||
}
|
||||
|
||||
hc.nonce, err = hc.deriveSecret(newTrafficSecret, []byte(tls13Nonce), hc.cs.nonceSize())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update nonce: %v", err)
|
||||
}
|
||||
|
||||
hc.aeadCrypter, err = hc.cs.aeadCrypter(key)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update AEAD crypter: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getAndIncrement returns the current sequence number and increments it. Note
|
||||
// that the mutex must be held while calling this function.
|
||||
func (hc *S2AHalfConnection) getAndIncrementSequence() (uint64, error) {
|
||||
sequence, err := hc.sequence.value()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
hc.sequence.increment()
|
||||
return sequence, nil
|
||||
}
|
||||
|
||||
// maskedNonce creates a copy of the nonce that is masked with the sequence
|
||||
// number. Note that the mutex must be held while calling this function.
|
||||
func (hc *S2AHalfConnection) maskedNonce(sequence uint64) []byte {
|
||||
const uint64Size = 8
|
||||
nonce := make([]byte, len(hc.nonce))
|
||||
copy(nonce, hc.nonce)
|
||||
for i := 0; i < uint64Size; i++ {
|
||||
nonce[aeadcrypter.NonceSize-uint64Size+i] ^= byte(sequence >> uint64(56-uint64Size*i))
|
||||
}
|
||||
return nonce
|
||||
}
|
||||
|
||||
// deriveSecret implements the Derive-Secret function, as specified in
|
||||
// https://tools.ietf.org/html/rfc8446#section-7.1.
|
||||
func (hc *S2AHalfConnection) deriveSecret(secret, label []byte, length int) ([]byte, error) {
|
||||
var hkdfLabel cryptobyte.Builder
|
||||
hkdfLabel.AddUint16(uint16(length))
|
||||
hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(label)
|
||||
})
|
||||
// Append an empty `Context` field to the label, as specified in the RFC.
|
||||
// The half connection does not use the `Context` field.
|
||||
hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes([]byte(""))
|
||||
})
|
||||
hkdfLabelBytes, err := hkdfLabel.Bytes()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("deriveSecret failed: %v", err)
|
||||
}
|
||||
return hc.expander.expand(secret, hkdfLabelBytes, length)
|
||||
}
|
||||
+757
@@ -0,0 +1,757 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package record implements the TLS 1.3 record protocol used by the S2A
|
||||
// transport credentials.
|
||||
package record
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
commonpb "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
"github.com/google/s2a-go/internal/record/internal/halfconn"
|
||||
"github.com/google/s2a-go/internal/tokenmanager"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
// recordType is the `ContentType` as described in
|
||||
// https://tools.ietf.org/html/rfc8446#section-5.1.
|
||||
type recordType byte
|
||||
|
||||
const (
|
||||
alert recordType = 21
|
||||
handshake recordType = 22
|
||||
applicationData recordType = 23
|
||||
)
|
||||
|
||||
// keyUpdateRequest is the `KeyUpdateRequest` as described in
|
||||
// https://tools.ietf.org/html/rfc8446#section-4.6.3.
|
||||
type keyUpdateRequest byte
|
||||
|
||||
const (
|
||||
updateNotRequested keyUpdateRequest = 0
|
||||
updateRequested keyUpdateRequest = 1
|
||||
)
|
||||
|
||||
// alertDescription is the `AlertDescription` as described in
|
||||
// https://tools.ietf.org/html/rfc8446#section-6.
|
||||
type alertDescription byte
|
||||
|
||||
const (
|
||||
closeNotify alertDescription = 0
|
||||
)
|
||||
|
||||
// sessionTicketState is used to determine whether session tickets have not yet
|
||||
// been received, are in the process of being received, or have finished
|
||||
// receiving.
|
||||
type sessionTicketState byte
|
||||
|
||||
const (
|
||||
ticketsNotYetReceived sessionTicketState = 0
|
||||
receivingTickets sessionTicketState = 1
|
||||
notReceivingTickets sessionTicketState = 2
|
||||
)
|
||||
|
||||
const (
|
||||
// The TLS 1.3-specific constants below (tlsRecordMaxPlaintextSize,
|
||||
// tlsRecordHeaderSize, tlsRecordTypeSize) were taken from
|
||||
// https://tools.ietf.org/html/rfc8446#section-5.1.
|
||||
|
||||
// tlsRecordMaxPlaintextSize is the maximum size in bytes of the plaintext
|
||||
// in a single TLS 1.3 record.
|
||||
tlsRecordMaxPlaintextSize = 16384 // 2^14
|
||||
// tlsRecordTypeSize is the size in bytes of the TLS 1.3 record type.
|
||||
tlsRecordTypeSize = 1
|
||||
// tlsTagSize is the size in bytes of the tag of the following three
|
||||
// ciphersuites: AES-128-GCM-SHA256, AES-256-GCM-SHA384,
|
||||
// CHACHA20-POLY1305-SHA256.
|
||||
tlsTagSize = 16
|
||||
// tlsRecordMaxPayloadSize is the maximum size in bytes of the payload in a
|
||||
// single TLS 1.3 record. This is the maximum size of the plaintext plus the
|
||||
// record type byte and 16 bytes of the tag.
|
||||
tlsRecordMaxPayloadSize = tlsRecordMaxPlaintextSize + tlsRecordTypeSize + tlsTagSize
|
||||
// tlsRecordHeaderTypeSize is the size in bytes of the TLS 1.3 record
|
||||
// header type.
|
||||
tlsRecordHeaderTypeSize = 1
|
||||
// tlsRecordHeaderLegacyRecordVersionSize is the size in bytes of the TLS
|
||||
// 1.3 record header legacy record version.
|
||||
tlsRecordHeaderLegacyRecordVersionSize = 2
|
||||
// tlsRecordHeaderPayloadLengthSize is the size in bytes of the TLS 1.3
|
||||
// record header payload length.
|
||||
tlsRecordHeaderPayloadLengthSize = 2
|
||||
// tlsRecordHeaderSize is the size in bytes of the TLS 1.3 record header.
|
||||
tlsRecordHeaderSize = tlsRecordHeaderTypeSize + tlsRecordHeaderLegacyRecordVersionSize + tlsRecordHeaderPayloadLengthSize
|
||||
// tlsRecordMaxSize
|
||||
tlsRecordMaxSize = tlsRecordMaxPayloadSize + tlsRecordHeaderSize
|
||||
// tlsApplicationData is the application data type of the TLS 1.3 record
|
||||
// header.
|
||||
tlsApplicationData = 23
|
||||
// tlsLegacyRecordVersion is the legacy record version of the TLS record.
|
||||
tlsLegacyRecordVersion = 3
|
||||
// tlsAlertSize is the size in bytes of an alert of TLS 1.3.
|
||||
tlsAlertSize = 2
|
||||
)
|
||||
|
||||
const (
|
||||
// These are TLS 1.3 handshake-specific constants.
|
||||
|
||||
// tlsHandshakeNewSessionTicketType is the prefix of a handshake new session
|
||||
// ticket message of TLS 1.3.
|
||||
tlsHandshakeNewSessionTicketType = 4
|
||||
// tlsHandshakeKeyUpdateType is the prefix of a handshake key update message
|
||||
// of TLS 1.3.
|
||||
tlsHandshakeKeyUpdateType = 24
|
||||
// tlsHandshakeMsgTypeSize is the size in bytes of the TLS 1.3 handshake
|
||||
// message type field.
|
||||
tlsHandshakeMsgTypeSize = 1
|
||||
// tlsHandshakeLengthSize is the size in bytes of the TLS 1.3 handshake
|
||||
// message length field.
|
||||
tlsHandshakeLengthSize = 3
|
||||
// tlsHandshakeKeyUpdateMsgSize is the size in bytes of the TLS 1.3
|
||||
// handshake key update message.
|
||||
tlsHandshakeKeyUpdateMsgSize = 1
|
||||
// tlsHandshakePrefixSize is the size in bytes of the prefix of the TLS 1.3
|
||||
// handshake message.
|
||||
tlsHandshakePrefixSize = 4
|
||||
// tlsMaxSessionTicketSize is the maximum size of a NewSessionTicket message
|
||||
// in TLS 1.3. This is the sum of the max sizes of all the fields in the
|
||||
// NewSessionTicket struct specified in
|
||||
// https://tools.ietf.org/html/rfc8446#section-4.6.1.
|
||||
tlsMaxSessionTicketSize = 131338
|
||||
)
|
||||
|
||||
const (
|
||||
// outBufMaxRecords is the maximum number of records that can fit in the
|
||||
// ourRecordsBuf buffer.
|
||||
outBufMaxRecords = 16
|
||||
// outBufMaxSize is the maximum size (in bytes) of the outRecordsBuf buffer.
|
||||
outBufMaxSize = outBufMaxRecords * tlsRecordMaxSize
|
||||
// maxAllowedTickets is the maximum number of session tickets that are
|
||||
// allowed. The number of tickets are limited to ensure that the size of the
|
||||
// ticket queue does not grow indefinitely. S2A also keeps a limit on the
|
||||
// number of tickets that it caches.
|
||||
maxAllowedTickets = 5
|
||||
)
|
||||
|
||||
// preConstructedKeyUpdateMsg holds the key update message. This is needed as an
|
||||
// optimization so that the same message does not need to be constructed every
|
||||
// time a key update message is sent.
|
||||
var preConstructedKeyUpdateMsg = buildKeyUpdateRequest()
|
||||
|
||||
// conn represents a secured TLS connection. It implements the net.Conn
|
||||
// interface.
|
||||
type conn struct {
|
||||
net.Conn
|
||||
// inConn is the half connection responsible for decrypting incoming bytes.
|
||||
inConn *halfconn.S2AHalfConnection
|
||||
// outConn is the half connection responsible for encrypting outgoing bytes.
|
||||
outConn *halfconn.S2AHalfConnection
|
||||
// pendingApplicationData holds data that has been read from the connection
|
||||
// and decrypted, but has not yet been returned by Read.
|
||||
pendingApplicationData []byte
|
||||
// unusedBuf holds data read from the network that has not yet been
|
||||
// decrypted. This data might not consist of a complete record. It may
|
||||
// consist of several records, the last of which could be incomplete.
|
||||
unusedBuf []byte
|
||||
// outRecordsBuf is a buffer used to store outgoing TLS records before
|
||||
// they are written to the network.
|
||||
outRecordsBuf []byte
|
||||
// nextRecord stores the next record info in the unusedBuf buffer.
|
||||
nextRecord []byte
|
||||
// overheadSize is the overhead size in bytes of each TLS 1.3 record, which
|
||||
// is computed as overheadSize = header size + record type byte + tag size.
|
||||
// Note that there is no padding by zeros in the overhead calculation.
|
||||
overheadSize int
|
||||
// readMutex guards against concurrent calls to Read. This is required since
|
||||
// Close may be called during a Read.
|
||||
readMutex sync.Mutex
|
||||
// writeMutex guards against concurrent calls to Write. This is required
|
||||
// since Close may be called during a Write, and also because a key update
|
||||
// message may be written during a Read.
|
||||
writeMutex sync.Mutex
|
||||
// handshakeBuf holds handshake messages while they are being processed.
|
||||
handshakeBuf []byte
|
||||
// ticketState is the current processing state of the session tickets.
|
||||
ticketState sessionTicketState
|
||||
// sessionTickets holds the completed session tickets until they are sent to
|
||||
// the handshaker service for processing.
|
||||
sessionTickets [][]byte
|
||||
// ticketSender sends session tickets to the S2A handshaker service.
|
||||
ticketSender s2aTicketSender
|
||||
// callComplete is a channel that blocks closing the record protocol until a
|
||||
// pending call to the S2A completes.
|
||||
callComplete chan bool
|
||||
}
|
||||
|
||||
// ConnParameters holds the parameters used for creating a new conn object.
|
||||
type ConnParameters struct {
|
||||
// NetConn is the TCP connection to the peer. This parameter is required.
|
||||
NetConn net.Conn
|
||||
// Ciphersuite is the TLS ciphersuite negotiated by the S2A handshaker
|
||||
// service. This parameter is required.
|
||||
Ciphersuite commonpb.Ciphersuite
|
||||
// TLSVersion is the TLS version number negotiated by the S2A handshaker
|
||||
// service. This parameter is required.
|
||||
TLSVersion commonpb.TLSVersion
|
||||
// InTrafficSecret is the traffic secret used to derive the session key for
|
||||
// the inbound direction. This parameter is required.
|
||||
InTrafficSecret []byte
|
||||
// OutTrafficSecret is the traffic secret used to derive the session key
|
||||
// for the outbound direction. This parameter is required.
|
||||
OutTrafficSecret []byte
|
||||
// UnusedBuf is the data read from the network that has not yet been
|
||||
// decrypted. This parameter is optional. If not provided, then no
|
||||
// application data was sent in the same flight of messages as the final
|
||||
// handshake message.
|
||||
UnusedBuf []byte
|
||||
// InSequence is the sequence number of the next, incoming, TLS record.
|
||||
// This parameter is required.
|
||||
InSequence uint64
|
||||
// OutSequence is the sequence number of the next, outgoing, TLS record.
|
||||
// This parameter is required.
|
||||
OutSequence uint64
|
||||
// HSAddr stores the address of the S2A handshaker service. This parameter
|
||||
// is optional. If not provided, then TLS resumption is disabled.
|
||||
HSAddr string
|
||||
// ConnectionId is the connection identifier that was created and sent by
|
||||
// S2A at the end of a handshake.
|
||||
ConnectionID uint64
|
||||
// LocalIdentity is the local identity that was used by S2A during session
|
||||
// setup and included in the session result.
|
||||
LocalIdentity *commonpb.Identity
|
||||
// EnsureProcessSessionTickets allows users to wait and ensure that all
|
||||
// available session tickets are sent to S2A before a process completes.
|
||||
EnsureProcessSessionTickets *sync.WaitGroup
|
||||
}
|
||||
|
||||
// NewConn creates a TLS record protocol that wraps the TCP connection.
|
||||
func NewConn(o *ConnParameters) (net.Conn, error) {
|
||||
if o == nil {
|
||||
return nil, errors.New("conn options must not be nil")
|
||||
}
|
||||
if o.TLSVersion != commonpb.TLSVersion_TLS1_3 {
|
||||
return nil, errors.New("TLS version must be TLS 1.3")
|
||||
}
|
||||
|
||||
inConn, err := halfconn.New(o.Ciphersuite, o.InTrafficSecret, o.InSequence)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create inbound half connection: %v", err)
|
||||
}
|
||||
outConn, err := halfconn.New(o.Ciphersuite, o.OutTrafficSecret, o.OutSequence)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create outbound half connection: %v", err)
|
||||
}
|
||||
|
||||
// The tag size for the in/out connections should be the same.
|
||||
overheadSize := tlsRecordHeaderSize + tlsRecordTypeSize + inConn.TagSize()
|
||||
var unusedBuf []byte
|
||||
if o.UnusedBuf == nil {
|
||||
// We pre-allocate unusedBuf to be of size
|
||||
// 2*tlsRecordMaxSize-1 during initialization. We only read from the
|
||||
// network into unusedBuf when unusedBuf does not contain a complete
|
||||
// record and the incomplete record is at most tlsRecordMaxSize-1
|
||||
// (bytes). And we read at most tlsRecordMaxSize bytes of data from the
|
||||
// network into unusedBuf at one time. Therefore, 2*tlsRecordMaxSize-1
|
||||
// is large enough to buffer data read from the network.
|
||||
unusedBuf = make([]byte, 0, 2*tlsRecordMaxSize-1)
|
||||
} else {
|
||||
unusedBuf = make([]byte, len(o.UnusedBuf))
|
||||
copy(unusedBuf, o.UnusedBuf)
|
||||
}
|
||||
|
||||
tokenManager, err := tokenmanager.NewSingleTokenAccessTokenManager()
|
||||
if err != nil {
|
||||
grpclog.Infof("failed to create single token access token manager: %v", err)
|
||||
}
|
||||
|
||||
s2aConn := &conn{
|
||||
Conn: o.NetConn,
|
||||
inConn: inConn,
|
||||
outConn: outConn,
|
||||
unusedBuf: unusedBuf,
|
||||
outRecordsBuf: make([]byte, tlsRecordMaxSize),
|
||||
nextRecord: unusedBuf,
|
||||
overheadSize: overheadSize,
|
||||
ticketState: ticketsNotYetReceived,
|
||||
// Pre-allocate the buffer for one session ticket message and the max
|
||||
// plaintext size. This is the largest size that handshakeBuf will need
|
||||
// to hold. The largest incomplete handshake message is the
|
||||
// [handshake header size] + [max session ticket size] - 1.
|
||||
// Then, tlsRecordMaxPlaintextSize is the maximum size that will be
|
||||
// appended to the handshakeBuf before the handshake message is
|
||||
// completed. Therefore, the buffer size below should be large enough to
|
||||
// buffer any handshake messages.
|
||||
handshakeBuf: make([]byte, 0, tlsHandshakePrefixSize+tlsMaxSessionTicketSize+tlsRecordMaxPlaintextSize-1),
|
||||
ticketSender: &ticketSender{
|
||||
hsAddr: o.HSAddr,
|
||||
connectionID: o.ConnectionID,
|
||||
localIdentity: o.LocalIdentity,
|
||||
tokenManager: tokenManager,
|
||||
ensureProcessSessionTickets: o.EnsureProcessSessionTickets,
|
||||
},
|
||||
callComplete: make(chan bool),
|
||||
}
|
||||
return s2aConn, nil
|
||||
}
|
||||
|
||||
// Read reads and decrypts a TLS 1.3 record from the underlying connection, and
|
||||
// copies any application data received from the peer into b. If the size of the
|
||||
// payload is greater than len(b), Read retains the remaining bytes in an
|
||||
// internal buffer, and subsequent calls to Read will read from this buffer
|
||||
// until it is exhausted. At most 1 TLS record worth of application data is
|
||||
// written to b for each call to Read.
|
||||
//
|
||||
// Note that for the user to efficiently call this method, the user should
|
||||
// ensure that the buffer b is allocated such that the buffer does not have any
|
||||
// unused segments. This can be done by calling Read via io.ReadFull, which
|
||||
// continually calls Read until the specified buffer has been filled. Also note
|
||||
// that the user should close the connection via Close() if an error is thrown
|
||||
// by a call to Read.
|
||||
func (p *conn) Read(b []byte) (n int, err error) {
|
||||
p.readMutex.Lock()
|
||||
defer p.readMutex.Unlock()
|
||||
// Check if p.pendingApplication data has leftover application data from
|
||||
// the previous call to Read.
|
||||
if len(p.pendingApplicationData) == 0 {
|
||||
// Read a full record from the wire.
|
||||
record, err := p.readFullRecord()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// Now we have a complete record, so split the header and validate it
|
||||
// The TLS record is split into 2 pieces: the record header and the
|
||||
// payload. The payload has the following form:
|
||||
// [payload] = [ciphertext of application data]
|
||||
// + [ciphertext of record type byte]
|
||||
// + [(optionally) ciphertext of padding by zeros]
|
||||
// + [tag]
|
||||
header, payload, err := splitAndValidateHeader(record)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// Decrypt the ciphertext.
|
||||
p.pendingApplicationData, err = p.inConn.Decrypt(payload[:0], payload, header)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// Remove the padding by zeros and the record type byte from the
|
||||
// p.pendingApplicationData buffer.
|
||||
msgType, err := p.stripPaddingAndType()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// Check that the length of the plaintext after stripping the padding
|
||||
// and record type byte is under the maximum plaintext size.
|
||||
if len(p.pendingApplicationData) > tlsRecordMaxPlaintextSize {
|
||||
return 0, errors.New("plaintext size larger than maximum")
|
||||
}
|
||||
// The expected message types are application data, alert, and
|
||||
// handshake. For application data, the bytes are directly copied into
|
||||
// b. For an alert, the type of the alert is checked and the connection
|
||||
// is closed on a close notify alert. For a handshake message, the
|
||||
// handshake message type is checked. The handshake message type can be
|
||||
// a key update type, for which we advance the traffic secret, and a
|
||||
// new session ticket type, for which we send the received ticket to S2A
|
||||
// for processing.
|
||||
switch msgType {
|
||||
case applicationData:
|
||||
if len(p.handshakeBuf) > 0 {
|
||||
return 0, errors.New("application data received while processing fragmented handshake messages")
|
||||
}
|
||||
if p.ticketState == receivingTickets {
|
||||
p.ticketState = notReceivingTickets
|
||||
grpclog.Infof("Sending session tickets to S2A.")
|
||||
p.ticketSender.sendTicketsToS2A(p.sessionTickets, p.callComplete)
|
||||
}
|
||||
case alert:
|
||||
return 0, p.handleAlertMessage()
|
||||
case handshake:
|
||||
if err = p.handleHandshakeMessage(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 0, nil
|
||||
default:
|
||||
return 0, errors.New("unknown record type")
|
||||
}
|
||||
}
|
||||
// Write as much application data as possible to b, the output buffer.
|
||||
n = copy(b, p.pendingApplicationData)
|
||||
p.pendingApplicationData = p.pendingApplicationData[n:]
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Write divides b into segments of size tlsRecordMaxPlaintextSize, builds a
|
||||
// TLS 1.3 record (of type "application data") from each segment, and sends
|
||||
// the record to the peer. It returns the number of plaintext bytes that were
|
||||
// successfully sent to the peer.
|
||||
func (p *conn) Write(b []byte) (n int, err error) {
|
||||
p.writeMutex.Lock()
|
||||
defer p.writeMutex.Unlock()
|
||||
return p.writeTLSRecord(b, tlsApplicationData)
|
||||
}
|
||||
|
||||
// writeTLSRecord divides b into segments of size maxPlaintextBytesPerRecord,
|
||||
// builds a TLS 1.3 record (of type recordType) from each segment, and sends
|
||||
// the record to the peer. It returns the number of plaintext bytes that were
|
||||
// successfully sent to the peer.
|
||||
func (p *conn) writeTLSRecord(b []byte, recordType byte) (n int, err error) {
|
||||
// Create a record of only header, record type, and tag if given empty
|
||||
// byte array.
|
||||
if len(b) == 0 {
|
||||
recordEndIndex, _, err := p.buildRecord(b, recordType, 0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Write the bytes stored in outRecordsBuf to p.Conn. Since we return
|
||||
// the number of plaintext bytes written without overhead, we will
|
||||
// always return 0 while p.Conn.Write returns the entire record length.
|
||||
_, err = p.Conn.Write(p.outRecordsBuf[:recordEndIndex])
|
||||
return 0, err
|
||||
}
|
||||
|
||||
numRecords := int(math.Ceil(float64(len(b)) / float64(tlsRecordMaxPlaintextSize)))
|
||||
totalRecordsSize := len(b) + numRecords*p.overheadSize
|
||||
partialBSize := len(b)
|
||||
if totalRecordsSize > outBufMaxSize {
|
||||
totalRecordsSize = outBufMaxSize
|
||||
partialBSize = outBufMaxRecords * tlsRecordMaxPlaintextSize
|
||||
}
|
||||
if len(p.outRecordsBuf) < totalRecordsSize {
|
||||
p.outRecordsBuf = make([]byte, totalRecordsSize)
|
||||
}
|
||||
for bStart := 0; bStart < len(b); bStart += partialBSize {
|
||||
bEnd := bStart + partialBSize
|
||||
if bEnd > len(b) {
|
||||
bEnd = len(b)
|
||||
}
|
||||
partialB := b[bStart:bEnd]
|
||||
recordEndIndex := 0
|
||||
for len(partialB) > 0 {
|
||||
recordEndIndex, partialB, err = p.buildRecord(partialB, recordType, recordEndIndex)
|
||||
if err != nil {
|
||||
// Return the amount of bytes written prior to the error.
|
||||
return bStart, err
|
||||
}
|
||||
}
|
||||
// Write the bytes stored in outRecordsBuf to p.Conn. If there is an
|
||||
// error, calculate the total number of plaintext bytes of complete
|
||||
// records successfully written to the peer and return it.
|
||||
nn, err := p.Conn.Write(p.outRecordsBuf[:recordEndIndex])
|
||||
if err != nil {
|
||||
numberOfCompletedRecords := int(math.Floor(float64(nn) / float64(tlsRecordMaxSize)))
|
||||
return bStart + numberOfCompletedRecords*tlsRecordMaxPlaintextSize, err
|
||||
}
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
// buildRecord builds a TLS 1.3 record of type recordType from plaintext,
|
||||
// and writes the record to outRecordsBuf at recordStartIndex. The record will
|
||||
// have at most tlsRecordMaxPlaintextSize bytes of payload. It returns the
|
||||
// index of outRecordsBuf where the current record ends, as well as any
|
||||
// remaining plaintext bytes.
|
||||
func (p *conn) buildRecord(plaintext []byte, recordType byte, recordStartIndex int) (n int, remainingPlaintext []byte, err error) {
|
||||
// Construct the payload, which consists of application data and record type.
|
||||
dataLen := len(plaintext)
|
||||
if dataLen > tlsRecordMaxPlaintextSize {
|
||||
dataLen = tlsRecordMaxPlaintextSize
|
||||
}
|
||||
remainingPlaintext = plaintext[dataLen:]
|
||||
newRecordBuf := p.outRecordsBuf[recordStartIndex:]
|
||||
|
||||
copy(newRecordBuf[tlsRecordHeaderSize:], plaintext[:dataLen])
|
||||
newRecordBuf[tlsRecordHeaderSize+dataLen] = recordType
|
||||
payload := newRecordBuf[tlsRecordHeaderSize : tlsRecordHeaderSize+dataLen+1] // 1 is for the recordType.
|
||||
// Construct the header.
|
||||
newRecordBuf[0] = tlsApplicationData
|
||||
newRecordBuf[1] = tlsLegacyRecordVersion
|
||||
newRecordBuf[2] = tlsLegacyRecordVersion
|
||||
binary.BigEndian.PutUint16(newRecordBuf[3:], uint16(len(payload)+tlsTagSize))
|
||||
header := newRecordBuf[:tlsRecordHeaderSize]
|
||||
|
||||
// Encrypt the payload using header as aad.
|
||||
encryptedPayload, err := p.outConn.Encrypt(newRecordBuf[tlsRecordHeaderSize:][:0], payload, header)
|
||||
if err != nil {
|
||||
return 0, plaintext, err
|
||||
}
|
||||
recordStartIndex += len(header) + len(encryptedPayload)
|
||||
return recordStartIndex, remainingPlaintext, nil
|
||||
}
|
||||
|
||||
func (p *conn) Close() error {
|
||||
p.readMutex.Lock()
|
||||
defer p.readMutex.Unlock()
|
||||
p.writeMutex.Lock()
|
||||
defer p.writeMutex.Unlock()
|
||||
// If p.ticketState is equal to notReceivingTickets, then S2A has
|
||||
// been sent a flight of session tickets, and we must wait for the
|
||||
// call to S2A to complete before closing the record protocol.
|
||||
if p.ticketState == notReceivingTickets {
|
||||
<-p.callComplete
|
||||
grpclog.Infof("Safe to close the connection because sending tickets to S2A is (already) complete.")
|
||||
}
|
||||
return p.Conn.Close()
|
||||
}
|
||||
|
||||
// stripPaddingAndType strips the padding by zeros and record type from
|
||||
// p.pendingApplicationData and returns the record type. Note that
|
||||
// p.pendingApplicationData should be of the form:
|
||||
// [application data] + [record type byte] + [trailing zeros]
|
||||
func (p *conn) stripPaddingAndType() (recordType, error) {
|
||||
if len(p.pendingApplicationData) == 0 {
|
||||
return 0, errors.New("application data had length 0")
|
||||
}
|
||||
i := len(p.pendingApplicationData) - 1
|
||||
// Search for the index of the record type byte.
|
||||
for i > 0 {
|
||||
if p.pendingApplicationData[i] != 0 {
|
||||
break
|
||||
}
|
||||
i--
|
||||
}
|
||||
rt := recordType(p.pendingApplicationData[i])
|
||||
p.pendingApplicationData = p.pendingApplicationData[:i]
|
||||
return rt, nil
|
||||
}
|
||||
|
||||
// readFullRecord reads from the wire until a record is completed and returns
|
||||
// the full record.
|
||||
func (p *conn) readFullRecord() (fullRecord []byte, err error) {
|
||||
fullRecord, p.nextRecord, err = parseReadBuffer(p.nextRecord, tlsRecordMaxPayloadSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Check whether the next record to be decrypted has been completely
|
||||
// received.
|
||||
if len(fullRecord) == 0 {
|
||||
copy(p.unusedBuf, p.nextRecord)
|
||||
p.unusedBuf = p.unusedBuf[:len(p.nextRecord)]
|
||||
// Always copy next incomplete record to the beginning of the
|
||||
// unusedBuf buffer and reset nextRecord to it.
|
||||
p.nextRecord = p.unusedBuf
|
||||
}
|
||||
// Keep reading from the wire until we have a complete record.
|
||||
for len(fullRecord) == 0 {
|
||||
if len(p.unusedBuf) == cap(p.unusedBuf) {
|
||||
tmp := make([]byte, len(p.unusedBuf), cap(p.unusedBuf)+tlsRecordMaxSize)
|
||||
copy(tmp, p.unusedBuf)
|
||||
p.unusedBuf = tmp
|
||||
}
|
||||
n, err := p.Conn.Read(p.unusedBuf[len(p.unusedBuf):min(cap(p.unusedBuf), len(p.unusedBuf)+tlsRecordMaxSize)])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.unusedBuf = p.unusedBuf[:len(p.unusedBuf)+n]
|
||||
fullRecord, p.nextRecord, err = parseReadBuffer(p.unusedBuf, tlsRecordMaxPayloadSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return fullRecord, nil
|
||||
}
|
||||
|
||||
// parseReadBuffer parses the provided buffer and returns a full record and any
|
||||
// remaining bytes in that buffer. If the record is incomplete, nil is returned
|
||||
// for the first return value and the given byte buffer is returned for the
|
||||
// second return value. The length of the payload specified by the header should
|
||||
// not be greater than maxLen, otherwise an error is returned. Note that this
|
||||
// function does not allocate or copy any buffers.
|
||||
func parseReadBuffer(b []byte, maxLen uint16) (fullRecord, remaining []byte, err error) {
|
||||
// If the header is not complete, return the provided buffer as remaining
|
||||
// buffer.
|
||||
if len(b) < tlsRecordHeaderSize {
|
||||
return nil, b, nil
|
||||
}
|
||||
msgLenField := b[tlsRecordHeaderTypeSize+tlsRecordHeaderLegacyRecordVersionSize : tlsRecordHeaderSize]
|
||||
length := binary.BigEndian.Uint16(msgLenField)
|
||||
if length > maxLen {
|
||||
return nil, nil, fmt.Errorf("record length larger than the limit %d", maxLen)
|
||||
}
|
||||
if len(b) < int(length)+tlsRecordHeaderSize {
|
||||
// Record is not complete yet.
|
||||
return nil, b, nil
|
||||
}
|
||||
return b[:tlsRecordHeaderSize+length], b[tlsRecordHeaderSize+length:], nil
|
||||
}
|
||||
|
||||
// splitAndValidateHeader splits the header from the payload in the TLS 1.3
|
||||
// record and returns them. Note that the header is checked for validity, and an
|
||||
// error is returned when an invalid header is parsed. Also note that this
|
||||
// function does not allocate or copy any buffers.
|
||||
func splitAndValidateHeader(record []byte) (header, payload []byte, err error) {
|
||||
if len(record) < tlsRecordHeaderSize {
|
||||
return nil, nil, fmt.Errorf("record was smaller than the header size")
|
||||
}
|
||||
header = record[:tlsRecordHeaderSize]
|
||||
payload = record[tlsRecordHeaderSize:]
|
||||
if header[0] != tlsApplicationData {
|
||||
return nil, nil, fmt.Errorf("incorrect type in the header")
|
||||
}
|
||||
// Check the legacy record version, which should be 0x03, 0x03.
|
||||
if header[1] != 0x03 || header[2] != 0x03 {
|
||||
return nil, nil, fmt.Errorf("incorrect legacy record version in the header")
|
||||
}
|
||||
return header, payload, nil
|
||||
}
|
||||
|
||||
// handleAlertMessage handles an alert message.
|
||||
func (p *conn) handleAlertMessage() error {
|
||||
if len(p.pendingApplicationData) != tlsAlertSize {
|
||||
return errors.New("invalid alert message size")
|
||||
}
|
||||
alertType := p.pendingApplicationData[1]
|
||||
// Clear the body of the alert message.
|
||||
p.pendingApplicationData = p.pendingApplicationData[:0]
|
||||
if alertType == byte(closeNotify) {
|
||||
return errors.New("received a close notify alert")
|
||||
}
|
||||
// TODO(matthewstevenson88): Add support for more alert types.
|
||||
return fmt.Errorf("received an unrecognized alert type: %v", alertType)
|
||||
}
|
||||
|
||||
// parseHandshakeHeader parses a handshake message from the handshake buffer.
|
||||
// It returns the message type, the message length, the message, the raw message
|
||||
// that includes the type and length bytes and a flag indicating whether the
|
||||
// handshake message has been fully parsed. i.e. whether the entire handshake
|
||||
// message was in the handshake buffer.
|
||||
func (p *conn) parseHandshakeMsg() (msgType byte, msgLen uint32, msg []byte, rawMsg []byte, ok bool) {
|
||||
// Handle the case where the 4 byte handshake header is fragmented.
|
||||
if len(p.handshakeBuf) < tlsHandshakePrefixSize {
|
||||
return 0, 0, nil, nil, false
|
||||
}
|
||||
msgType = p.handshakeBuf[0]
|
||||
msgLen = bigEndianInt24(p.handshakeBuf[tlsHandshakeMsgTypeSize : tlsHandshakeMsgTypeSize+tlsHandshakeLengthSize])
|
||||
if msgLen > uint32(len(p.handshakeBuf)-tlsHandshakePrefixSize) {
|
||||
return 0, 0, nil, nil, false
|
||||
}
|
||||
msg = p.handshakeBuf[tlsHandshakePrefixSize : tlsHandshakePrefixSize+msgLen]
|
||||
rawMsg = p.handshakeBuf[:tlsHandshakeMsgTypeSize+tlsHandshakeLengthSize+msgLen]
|
||||
p.handshakeBuf = p.handshakeBuf[tlsHandshakePrefixSize+msgLen:]
|
||||
return msgType, msgLen, msg, rawMsg, true
|
||||
}
|
||||
|
||||
// handleHandshakeMessage handles a handshake message. Note that the first
|
||||
// complete handshake message from the handshake buffer is removed, if it
|
||||
// exists.
|
||||
func (p *conn) handleHandshakeMessage() error {
|
||||
// Copy the pending application data to the handshake buffer. At this point,
|
||||
// we are guaranteed that the pending application data contains only parts
|
||||
// of a handshake message.
|
||||
p.handshakeBuf = append(p.handshakeBuf, p.pendingApplicationData...)
|
||||
p.pendingApplicationData = p.pendingApplicationData[:0]
|
||||
// Several handshake messages may be coalesced into a single record.
|
||||
// Continue reading them until the handshake buffer is empty.
|
||||
for len(p.handshakeBuf) > 0 {
|
||||
handshakeMsgType, msgLen, msg, rawMsg, ok := p.parseHandshakeMsg()
|
||||
if !ok {
|
||||
// The handshake could not be fully parsed, so read in another
|
||||
// record and try again later.
|
||||
break
|
||||
}
|
||||
switch handshakeMsgType {
|
||||
case tlsHandshakeKeyUpdateType:
|
||||
if msgLen != tlsHandshakeKeyUpdateMsgSize {
|
||||
return errors.New("invalid handshake key update message length")
|
||||
}
|
||||
if len(p.handshakeBuf) != 0 {
|
||||
return errors.New("key update message must be the last message of a handshake record")
|
||||
}
|
||||
if err := p.handleKeyUpdateMsg(msg); err != nil {
|
||||
return err
|
||||
}
|
||||
case tlsHandshakeNewSessionTicketType:
|
||||
// Ignore tickets that are received after a batch of tickets has
|
||||
// been sent to S2A.
|
||||
if p.ticketState == notReceivingTickets {
|
||||
continue
|
||||
}
|
||||
if p.ticketState == ticketsNotYetReceived {
|
||||
p.ticketState = receivingTickets
|
||||
}
|
||||
p.sessionTickets = append(p.sessionTickets, rawMsg)
|
||||
if len(p.sessionTickets) == maxAllowedTickets {
|
||||
p.ticketState = notReceivingTickets
|
||||
grpclog.Infof("Sending session tickets to S2A.")
|
||||
p.ticketSender.sendTicketsToS2A(p.sessionTickets, p.callComplete)
|
||||
}
|
||||
default:
|
||||
return errors.New("unknown handshake message type")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildKeyUpdateRequest() []byte {
|
||||
b := make([]byte, tlsHandshakePrefixSize+tlsHandshakeKeyUpdateMsgSize)
|
||||
b[0] = tlsHandshakeKeyUpdateType
|
||||
b[1] = 0
|
||||
b[2] = 0
|
||||
b[3] = tlsHandshakeKeyUpdateMsgSize
|
||||
b[4] = byte(updateNotRequested)
|
||||
return b
|
||||
}
|
||||
|
||||
// handleKeyUpdateMsg handles a key update message.
|
||||
func (p *conn) handleKeyUpdateMsg(msg []byte) error {
|
||||
keyUpdateRequest := msg[0]
|
||||
if keyUpdateRequest != byte(updateNotRequested) &&
|
||||
keyUpdateRequest != byte(updateRequested) {
|
||||
return errors.New("invalid handshake key update message")
|
||||
}
|
||||
if err := p.inConn.UpdateKey(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Send a key update message back to the peer if requested.
|
||||
if keyUpdateRequest == byte(updateRequested) {
|
||||
p.writeMutex.Lock()
|
||||
defer p.writeMutex.Unlock()
|
||||
n, err := p.writeTLSRecord(preConstructedKeyUpdateMsg, byte(handshake))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != tlsHandshakePrefixSize+tlsHandshakeKeyUpdateMsgSize {
|
||||
return errors.New("key update request message wrote less bytes than expected")
|
||||
}
|
||||
if err = p.outConn.UpdateKey(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// bidEndianInt24 converts the given byte buffer of at least size 3 and
|
||||
// outputs the resulting 24 bit integer as a uint32. This is needed because
|
||||
// TLS 1.3 requires 3 byte integers, and the binary.BigEndian package does
|
||||
// not provide a way to transform a byte buffer into a 3 byte integer.
|
||||
func bigEndianInt24(b []byte) uint32 {
|
||||
_ = b[2] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint32(b[2]) | uint32(b[1])<<8 | uint32(b[0])<<16
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package record
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/s2a-go/internal/handshaker/service"
|
||||
commonpb "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
s2apb "github.com/google/s2a-go/internal/proto/s2a_go_proto"
|
||||
"github.com/google/s2a-go/internal/tokenmanager"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
// sessionTimeout is the timeout for creating a session with the S2A handshaker
|
||||
// service.
|
||||
const sessionTimeout = time.Second * 5
|
||||
|
||||
// s2aTicketSender sends session tickets to the S2A handshaker service.
|
||||
type s2aTicketSender interface {
|
||||
// sendTicketsToS2A sends the given session tickets to the S2A handshaker
|
||||
// service.
|
||||
sendTicketsToS2A(sessionTickets [][]byte, callComplete chan bool)
|
||||
}
|
||||
|
||||
// ticketStream is the stream used to send and receive session information.
|
||||
type ticketStream interface {
|
||||
Send(*s2apb.SessionReq) error
|
||||
Recv() (*s2apb.SessionResp, error)
|
||||
}
|
||||
|
||||
type ticketSender struct {
|
||||
// hsAddr stores the address of the S2A handshaker service.
|
||||
hsAddr string
|
||||
// connectionID is the connection identifier that was created and sent by
|
||||
// S2A at the end of a handshake.
|
||||
connectionID uint64
|
||||
// localIdentity is the local identity that was used by S2A during session
|
||||
// setup and included in the session result.
|
||||
localIdentity *commonpb.Identity
|
||||
// tokenManager manages access tokens for authenticating to S2A.
|
||||
tokenManager tokenmanager.AccessTokenManager
|
||||
// ensureProcessSessionTickets allows users to wait and ensure that all
|
||||
// available session tickets are sent to S2A before a process completes.
|
||||
ensureProcessSessionTickets *sync.WaitGroup
|
||||
}
|
||||
|
||||
// sendTicketsToS2A sends the given sessionTickets to the S2A handshaker
|
||||
// service. This is done asynchronously and writes to the error logs if an error
|
||||
// occurs.
|
||||
func (t *ticketSender) sendTicketsToS2A(sessionTickets [][]byte, callComplete chan bool) {
|
||||
// Note that the goroutine is in the function rather than at the caller
|
||||
// because the fake ticket sender used for testing must run synchronously
|
||||
// so that the session tickets can be accessed from it after the tests have
|
||||
// been run.
|
||||
if t.ensureProcessSessionTickets != nil {
|
||||
t.ensureProcessSessionTickets.Add(1)
|
||||
}
|
||||
go func() {
|
||||
if err := func() error {
|
||||
defer func() {
|
||||
if t.ensureProcessSessionTickets != nil {
|
||||
t.ensureProcessSessionTickets.Done()
|
||||
}
|
||||
}()
|
||||
hsConn, err := service.Dial(t.hsAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := s2apb.NewS2AServiceClient(hsConn)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), sessionTimeout)
|
||||
defer cancel()
|
||||
session, err := client.SetUpSession(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := session.CloseSend(); err != nil {
|
||||
grpclog.Error(err)
|
||||
}
|
||||
}()
|
||||
return t.writeTicketsToStream(session, sessionTickets)
|
||||
}(); err != nil {
|
||||
grpclog.Errorf("failed to send resumption tickets to S2A with identity: %v, %v",
|
||||
t.localIdentity, err)
|
||||
}
|
||||
callComplete <- true
|
||||
close(callComplete)
|
||||
}()
|
||||
}
|
||||
|
||||
// writeTicketsToStream writes the given session tickets to the given stream.
|
||||
func (t *ticketSender) writeTicketsToStream(stream ticketStream, sessionTickets [][]byte) error {
|
||||
if err := stream.Send(
|
||||
&s2apb.SessionReq{
|
||||
ReqOneof: &s2apb.SessionReq_ResumptionTicket{
|
||||
ResumptionTicket: &s2apb.ResumptionTicketReq{
|
||||
InBytes: sessionTickets,
|
||||
ConnectionId: t.connectionID,
|
||||
LocalIdentity: t.localIdentity,
|
||||
},
|
||||
},
|
||||
AuthMechanisms: t.getAuthMechanisms(),
|
||||
},
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
sessionResp, err := stream.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sessionResp.GetStatus().GetCode() != uint32(codes.OK) {
|
||||
return fmt.Errorf("s2a session ticket response had error status: %v, %v",
|
||||
sessionResp.GetStatus().GetCode(), sessionResp.GetStatus().GetDetails())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *ticketSender) getAuthMechanisms() []*s2apb.AuthenticationMechanism {
|
||||
if t.tokenManager == nil {
|
||||
return nil
|
||||
}
|
||||
// First handle the special case when no local identity has been provided
|
||||
// by the application. In this case, an AuthenticationMechanism with no local
|
||||
// identity will be sent.
|
||||
if t.localIdentity == nil {
|
||||
token, err := t.tokenManager.DefaultToken()
|
||||
if err != nil {
|
||||
grpclog.Infof("unable to get token for empty local identity: %v", err)
|
||||
return nil
|
||||
}
|
||||
return []*s2apb.AuthenticationMechanism{
|
||||
{
|
||||
MechanismOneof: &s2apb.AuthenticationMechanism_Token{
|
||||
Token: token,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Next, handle the case where the application (or the S2A) has specified
|
||||
// a local identity.
|
||||
token, err := t.tokenManager.Token(t.localIdentity)
|
||||
if err != nil {
|
||||
grpclog.Infof("unable to get token for local identity %v: %v", t.localIdentity, err)
|
||||
return nil
|
||||
}
|
||||
return []*s2apb.AuthenticationMechanism{
|
||||
{
|
||||
Identity: t.localIdentity,
|
||||
MechanismOneof: &s2apb.AuthenticationMechanism_Token{
|
||||
Token: token,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package tokenmanager provides tokens for authenticating to S2A.
|
||||
package tokenmanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
commonpb "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
)
|
||||
|
||||
const (
|
||||
s2aAccessTokenEnvironmentVariable = "S2A_ACCESS_TOKEN"
|
||||
)
|
||||
|
||||
// AccessTokenManager manages tokens for authenticating to S2A.
|
||||
type AccessTokenManager interface {
|
||||
// DefaultToken returns a token that an application with no specified local
|
||||
// identity must use to authenticate to S2A.
|
||||
DefaultToken() (token string, err error)
|
||||
// Token returns a token that an application with local identity equal to
|
||||
// identity must use to authenticate to S2A.
|
||||
Token(identity *commonpb.Identity) (token string, err error)
|
||||
}
|
||||
|
||||
type singleTokenAccessTokenManager struct {
|
||||
token string
|
||||
}
|
||||
|
||||
// NewSingleTokenAccessTokenManager returns a new AccessTokenManager instance
|
||||
// that will always manage the same token.
|
||||
//
|
||||
// The token to be managed is read from the s2aAccessTokenEnvironmentVariable
|
||||
// environment variable. If this environment variable is not set, then this
|
||||
// function returns an error.
|
||||
func NewSingleTokenAccessTokenManager() (AccessTokenManager, error) {
|
||||
token, variableExists := os.LookupEnv(s2aAccessTokenEnvironmentVariable)
|
||||
if !variableExists {
|
||||
return nil, fmt.Errorf("%s environment variable is not set", s2aAccessTokenEnvironmentVariable)
|
||||
}
|
||||
return &singleTokenAccessTokenManager{token: token}, nil
|
||||
}
|
||||
|
||||
// DefaultToken always returns the token managed by the
|
||||
// singleTokenAccessTokenManager.
|
||||
func (m *singleTokenAccessTokenManager) DefaultToken() (string, error) {
|
||||
return m.token, nil
|
||||
}
|
||||
|
||||
// Token always returns the token managed by the singleTokenAccessTokenManager.
|
||||
func (m *singleTokenAccessTokenManager) Token(*commonpb.Identity) (string, error) {
|
||||
return m.token, nil
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
**This directory has the implementation of the S2Av2's gRPC-Go client libraries**
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package certverifier offloads verifications to S2Av2.
|
||||
package certverifier
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
|
||||
s2av2pb "github.com/google/s2a-go/internal/proto/v2/s2a_go_proto"
|
||||
)
|
||||
|
||||
// VerifyClientCertificateChain builds a SessionReq, sends it to S2Av2 and
|
||||
// receives a SessionResp.
|
||||
func VerifyClientCertificateChain(verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode, cstream s2av2pb.S2AService_SetUpSessionClient) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
// Offload verification to S2Av2.
|
||||
if grpclog.V(1) {
|
||||
grpclog.Infof("Sending request to S2Av2 for client peer cert chain validation.")
|
||||
}
|
||||
if err := cstream.Send(&s2av2pb.SessionReq{
|
||||
ReqOneof: &s2av2pb.SessionReq_ValidatePeerCertificateChainReq{
|
||||
ValidatePeerCertificateChainReq: &s2av2pb.ValidatePeerCertificateChainReq{
|
||||
Mode: verificationMode,
|
||||
PeerOneof: &s2av2pb.ValidatePeerCertificateChainReq_ClientPeer_{
|
||||
ClientPeer: &s2av2pb.ValidatePeerCertificateChainReq_ClientPeer{
|
||||
CertificateChain: rawCerts,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}); err != nil {
|
||||
grpclog.Infof("Failed to send request to S2Av2 for client peer cert chain validation.")
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the response from S2Av2.
|
||||
resp, err := cstream.Recv()
|
||||
if err != nil {
|
||||
grpclog.Infof("Failed to receive client peer cert chain validation response from S2Av2.")
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse the response.
|
||||
if (resp.GetStatus() != nil) && (resp.GetStatus().Code != uint32(codes.OK)) {
|
||||
return fmt.Errorf("failed to offload client cert verification to S2A: %d, %v", resp.GetStatus().Code, resp.GetStatus().Details)
|
||||
|
||||
}
|
||||
|
||||
if resp.GetValidatePeerCertificateChainResp().ValidationResult != s2av2pb.ValidatePeerCertificateChainResp_SUCCESS {
|
||||
return fmt.Errorf("client cert verification failed: %v", resp.GetValidatePeerCertificateChainResp().ValidationDetails)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// VerifyServerCertificateChain builds a SessionReq, sends it to S2Av2 and
|
||||
// receives a SessionResp.
|
||||
func VerifyServerCertificateChain(hostname string, verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode, cstream s2av2pb.S2AService_SetUpSessionClient) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
// Offload verification to S2Av2.
|
||||
if grpclog.V(1) {
|
||||
grpclog.Infof("Sending request to S2Av2 for server peer cert chain validation.")
|
||||
}
|
||||
if err := cstream.Send(&s2av2pb.SessionReq{
|
||||
ReqOneof: &s2av2pb.SessionReq_ValidatePeerCertificateChainReq{
|
||||
ValidatePeerCertificateChainReq: &s2av2pb.ValidatePeerCertificateChainReq{
|
||||
Mode: verificationMode,
|
||||
PeerOneof: &s2av2pb.ValidatePeerCertificateChainReq_ServerPeer_{
|
||||
ServerPeer: &s2av2pb.ValidatePeerCertificateChainReq_ServerPeer{
|
||||
CertificateChain: rawCerts,
|
||||
ServerHostname: hostname,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}); err != nil {
|
||||
grpclog.Infof("Failed to send request to S2Av2 for server peer cert chain validation.")
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the response from S2Av2.
|
||||
resp, err := cstream.Recv()
|
||||
if err != nil {
|
||||
grpclog.Infof("Failed to receive server peer cert chain validation response from S2Av2.")
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse the response.
|
||||
if (resp.GetStatus() != nil) && (resp.GetStatus().Code != uint32(codes.OK)) {
|
||||
return fmt.Errorf("failed to offload server cert verification to S2A: %d, %v", resp.GetStatus().Code, resp.GetStatus().Details)
|
||||
}
|
||||
|
||||
if resp.GetValidatePeerCertificateChainResp().ValidationResult != s2av2pb.ValidatePeerCertificateChainResp_SUCCESS {
|
||||
return fmt.Errorf("server cert verification failed: %v", resp.GetValidatePeerCertificateChainResp().ValidationDetails)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
+185
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package remotesigner offloads private key operations to S2Av2.
|
||||
package remotesigner
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
|
||||
s2av2pb "github.com/google/s2a-go/internal/proto/v2/s2a_go_proto"
|
||||
)
|
||||
|
||||
// remoteSigner implementes the crypto.Signer interface.
|
||||
type remoteSigner struct {
|
||||
leafCert *x509.Certificate
|
||||
cstream s2av2pb.S2AService_SetUpSessionClient
|
||||
}
|
||||
|
||||
// New returns an instance of RemoteSigner, an implementation of the
|
||||
// crypto.Signer interface.
|
||||
func New(leafCert *x509.Certificate, cstream s2av2pb.S2AService_SetUpSessionClient) crypto.Signer {
|
||||
return &remoteSigner{leafCert, cstream}
|
||||
}
|
||||
|
||||
func (s *remoteSigner) Public() crypto.PublicKey {
|
||||
return s.leafCert.PublicKey
|
||||
}
|
||||
|
||||
func (s *remoteSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {
|
||||
signatureAlgorithm, err := getSignatureAlgorithm(opts, s.leafCert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := getSignReq(signatureAlgorithm, digest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if grpclog.V(1) {
|
||||
grpclog.Infof("Sending request to S2Av2 for signing operation.")
|
||||
}
|
||||
if err := s.cstream.Send(&s2av2pb.SessionReq{
|
||||
ReqOneof: &s2av2pb.SessionReq_OffloadPrivateKeyOperationReq{
|
||||
OffloadPrivateKeyOperationReq: req,
|
||||
},
|
||||
}); err != nil {
|
||||
grpclog.Infof("Failed to send request to S2Av2 for signing operation.")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := s.cstream.Recv()
|
||||
if err != nil {
|
||||
grpclog.Infof("Failed to receive signing operation response from S2Av2.")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if (resp.GetStatus() != nil) && (resp.GetStatus().Code != uint32(codes.OK)) {
|
||||
return nil, fmt.Errorf("failed to offload signing with private key to S2A: %d, %v", resp.GetStatus().Code, resp.GetStatus().Details)
|
||||
}
|
||||
|
||||
return resp.GetOffloadPrivateKeyOperationResp().GetOutBytes(), nil
|
||||
}
|
||||
|
||||
// getCert returns the leafCert field in s.
|
||||
func (s *remoteSigner) getCert() *x509.Certificate {
|
||||
return s.leafCert
|
||||
}
|
||||
|
||||
// getStream returns the cstream field in s.
|
||||
func (s *remoteSigner) getStream() s2av2pb.S2AService_SetUpSessionClient {
|
||||
return s.cstream
|
||||
}
|
||||
|
||||
func getSignReq(signatureAlgorithm s2av2pb.SignatureAlgorithm, digest []byte) (*s2av2pb.OffloadPrivateKeyOperationReq, error) {
|
||||
if (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA256) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ECDSA_SECP256R1_SHA256) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PSS_RSAE_SHA256) {
|
||||
return &s2av2pb.OffloadPrivateKeyOperationReq{
|
||||
Operation: s2av2pb.OffloadPrivateKeyOperationReq_SIGN,
|
||||
SignatureAlgorithm: signatureAlgorithm,
|
||||
InBytes: &s2av2pb.OffloadPrivateKeyOperationReq_Sha256Digest{
|
||||
Sha256Digest: digest,
|
||||
},
|
||||
}, nil
|
||||
} else if (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA384) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ECDSA_SECP384R1_SHA384) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PSS_RSAE_SHA384) {
|
||||
return &s2av2pb.OffloadPrivateKeyOperationReq{
|
||||
Operation: s2av2pb.OffloadPrivateKeyOperationReq_SIGN,
|
||||
SignatureAlgorithm: signatureAlgorithm,
|
||||
InBytes: &s2av2pb.OffloadPrivateKeyOperationReq_Sha384Digest{
|
||||
Sha384Digest: digest,
|
||||
},
|
||||
}, nil
|
||||
} else if (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA512) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ECDSA_SECP521R1_SHA512) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PSS_RSAE_SHA512) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ED25519) {
|
||||
return &s2av2pb.OffloadPrivateKeyOperationReq{
|
||||
Operation: s2av2pb.OffloadPrivateKeyOperationReq_SIGN,
|
||||
SignatureAlgorithm: signatureAlgorithm,
|
||||
InBytes: &s2av2pb.OffloadPrivateKeyOperationReq_Sha512Digest{
|
||||
Sha512Digest: digest,
|
||||
},
|
||||
}, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("unknown signature algorithm: %v", signatureAlgorithm)
|
||||
}
|
||||
}
|
||||
|
||||
// getSignatureAlgorithm returns the signature algorithm that S2A must use when
|
||||
// performing a signing operation that has been offloaded by an application
|
||||
// using the crypto/tls libraries.
|
||||
func getSignatureAlgorithm(opts crypto.SignerOpts, leafCert *x509.Certificate) (s2av2pb.SignatureAlgorithm, error) {
|
||||
if opts == nil || leafCert == nil {
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_UNSPECIFIED, fmt.Errorf("unknown signature algorithm")
|
||||
}
|
||||
switch leafCert.PublicKeyAlgorithm {
|
||||
case x509.RSA:
|
||||
if rsaPSSOpts, ok := opts.(*rsa.PSSOptions); ok {
|
||||
return rsaPSSAlgorithm(rsaPSSOpts)
|
||||
}
|
||||
return rsaPPKCS1Algorithm(opts)
|
||||
case x509.ECDSA:
|
||||
return ecdsaAlgorithm(opts)
|
||||
case x509.Ed25519:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ED25519, nil
|
||||
default:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_UNSPECIFIED, fmt.Errorf("unknown signature algorithm: %q", leafCert.PublicKeyAlgorithm)
|
||||
}
|
||||
}
|
||||
|
||||
func rsaPSSAlgorithm(opts *rsa.PSSOptions) (s2av2pb.SignatureAlgorithm, error) {
|
||||
switch opts.HashFunc() {
|
||||
case crypto.SHA256:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PSS_RSAE_SHA256, nil
|
||||
case crypto.SHA384:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PSS_RSAE_SHA384, nil
|
||||
case crypto.SHA512:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PSS_RSAE_SHA512, nil
|
||||
default:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_UNSPECIFIED, fmt.Errorf("unknown signature algorithm")
|
||||
}
|
||||
}
|
||||
|
||||
func rsaPPKCS1Algorithm(opts crypto.SignerOpts) (s2av2pb.SignatureAlgorithm, error) {
|
||||
switch opts.HashFunc() {
|
||||
case crypto.SHA256:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA256, nil
|
||||
case crypto.SHA384:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA384, nil
|
||||
case crypto.SHA512:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA512, nil
|
||||
default:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_UNSPECIFIED, fmt.Errorf("unknown signature algorithm")
|
||||
}
|
||||
}
|
||||
|
||||
func ecdsaAlgorithm(opts crypto.SignerOpts) (s2av2pb.SignatureAlgorithm, error) {
|
||||
switch opts.HashFunc() {
|
||||
case crypto.SHA256:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ECDSA_SECP256R1_SHA256, nil
|
||||
case crypto.SHA384:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ECDSA_SECP384R1_SHA384, nil
|
||||
case crypto.SHA512:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ECDSA_SECP521R1_SHA512, nil
|
||||
default:
|
||||
return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_UNSPECIFIED, fmt.Errorf("unknown signature algorithm")
|
||||
}
|
||||
}
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID8TCCAtmgAwIBAgIUKXNlBRVe6UepjQUijIFPZBd/4qYwDQYJKoZIhvcNAQEL
|
||||
BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2
|
||||
YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE
|
||||
AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN
|
||||
MjIwNTMxMjAwMzE1WhcNNDIwNTI2MjAwMzE1WjCBhzELMAkGA1UEBhMCVVMxCzAJ
|
||||
BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx
|
||||
ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ
|
||||
KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBAOOFuIucH7XXfohGxKd3uR/ihUA/LdduR9I8kfpUEbq5BOt8xZe5/Yn9
|
||||
a1ozEHVW6cOAbHbnwAR8tkSgZ/t42QIA2k77HWU1Jh2xiEIsJivo3imm4/kZWuR0
|
||||
OqPh7MhzxpR/hvNwpI5mJsAVBWFMa5KtecFZLnyZtwHylrRN1QXzuLrOxuKFufK3
|
||||
RKbTABScn5RbZL976H/jgfSeXrbt242NrIoBnVe6fRbekbq2DQ6zFArbQMUgHjHK
|
||||
P0UqBgdr1QmHfi9KytFyx9BTP3gXWnWIu+bY7/v7qKJMHFwGETo+dCLWYevJL316
|
||||
HnLfhApDMfP8U+Yv/y1N/YvgaSOSlEcCAwEAAaNTMFEwHQYDVR0OBBYEFKhAU4nu
|
||||
0h/lrnggbIGvx4ej0WklMB8GA1UdIwQYMBaAFKhAU4nu0h/lrnggbIGvx4ej0Wkl
|
||||
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAE/6NghzQ5fu6yR6
|
||||
EHKbj/YMrFdT7aGn5n2sAf7wJ33LIhiFHkpWBsVlm7rDtZtwhe891ZK/P60anlg9
|
||||
/P0Ua53tSRVRmCvTnEbXWOVMN4is6MsR7BlmzUxl4AtIn7jbeifEwRL7B4xDYmdA
|
||||
QrQnsqoz45dLgS5xK4WDqXATP09Q91xQDuhud/b+A4jrvgwFASmL7rMIZbp4f1JQ
|
||||
nlnl/9VoTBQBvJiWkDUtQDMpRLtauddEkv4AGz75p5IspXWD6cOemuh2iQec11xD
|
||||
X20rs2WZbAcAiUa3nmy8OKYw435vmpj8gp39WYbX/Yx9TymrFFbVY92wYn+quTco
|
||||
pKklVz0=
|
||||
-----END CERTIFICATE-----
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEA44W4i5wftdd+iEbEp3e5H+KFQD8t125H0jyR+lQRurkE63zF
|
||||
l7n9if1rWjMQdVbpw4BsdufABHy2RKBn+3jZAgDaTvsdZTUmHbGIQiwmK+jeKabj
|
||||
+Rla5HQ6o+HsyHPGlH+G83CkjmYmwBUFYUxrkq15wVkufJm3AfKWtE3VBfO4us7G
|
||||
4oW58rdEptMAFJyflFtkv3vof+OB9J5etu3bjY2sigGdV7p9Ft6RurYNDrMUCttA
|
||||
xSAeMco/RSoGB2vVCYd+L0rK0XLH0FM/eBdadYi75tjv+/uookwcXAYROj50ItZh
|
||||
68kvfXoect+ECkMx8/xT5i//LU39i+BpI5KURwIDAQABAoIBABgyjo/6iLzUMFbZ
|
||||
/+w3pW6orrdIgN2akvTfED9pVYFgUA+jc3hRhY95bkNnjuaL2cy7Cc4Tk65mfRQL
|
||||
Y0OxdJLr+EvSFSxAXM9npDA1ddHRsF8JqtFBSxNk8R+g1Yf0GDiO35Fgd3/ViWWA
|
||||
VtQkRoSRApP3oiQKTRZd8H04keFR+PvmDk/Lq11l3Kc24A1PevKIPX1oI990ggw9
|
||||
9i4uSV+cnuMxmcI9xxJtgwdDFdjr39l2arLOHr4s6LGoV2IOdXHNlv5xRqWUZ0FH
|
||||
MDHowkLgwDrdSTnNeaVNkce14Gqx+bd4hNaLCdKXMpedBTEmrut3f3hdV1kKjaKt
|
||||
aqRYr8ECgYEA/YDGZY2jvFoHHBywlqmEMFrrCvQGH51m5R1Ntpkzr+Rh3YCmrpvq
|
||||
xgwJXING0PUw3dz+xrH5lJICrfNE5Kt3fPu1rAEy+13mYsNowghtUq2Rtu0Hsjjx
|
||||
2E3Bf8vEB6RNBMmGkUpTTIAroGF5tpJoRvfnWax+k4pFdrKYFtyZdNcCgYEA5cNv
|
||||
EPltvOobjTXlUmtVP3n27KZN2aXexTcagLzRxE9CV4cYySENl3KuOMmccaZpIl6z
|
||||
aHk6BT4X+M0LqElNUczrInfVqI+SGAFLGy7W6CJaqSr6cpyFUP/fosKpm6wKGgLq
|
||||
udHfpvz5rckhKd8kJxFLvhGOK9yN5qpzih0gfhECgYAJfwRvk3G5wYmYpP58dlcs
|
||||
VIuPenqsPoI3PPTHTU/hW+XKnWIhElgmGRdUrto9Q6IT/Y5RtSMLTLjq+Tzwb/fm
|
||||
56rziYv2XJsfwgAvnI8z1Kqrto9ePsHYf3krJ1/thVsZPc9bq/QY3ohD1sLvcuaT
|
||||
GgBBnLOVJU3a12/ZE2RwOwKBgF0csWMAoj8/5IB6if+3ral2xOGsl7oPZVMo/J2V
|
||||
Z7EVqb4M6rd/pKFugTpUQgkwtkSOekhpcGD1hAN5HTNK2YG/+L5UMAsKe9sskwJm
|
||||
HgOfAHy0BSDzW3ey6i9skg2bT9Cww+0gJ3Hl7U1HSCBO5LjMYpSZSrNtwzfqdb5Q
|
||||
BX3xAoGARZdR28Ej3+/+0+fz47Yu2h4z0EI/EbrudLOWY936jIeAVwHckI3+BuqH
|
||||
qR4poj1gfbnMxNuI9UzIXzjEmGewx9kDZ7IYnvloZKqoVQODO5GlKF2ja6IcMNlh
|
||||
GCNdD6PSAS6HcmalmWo9sj+1YMkrl+GJikKZqVBHrHNwMGAG67w=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID8TCCAtmgAwIBAgIUKCoDuLtiZXvhsBY2RoDm0ugizJ8wDQYJKoZIhvcNAQEL
|
||||
BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2
|
||||
YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE
|
||||
AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN
|
||||
MjIwNTMxMjAwODI1WhcNNDIwNTI2MjAwODI1WjCBhzELMAkGA1UEBhMCVVMxCzAJ
|
||||
BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx
|
||||
ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ
|
||||
KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBAKK1++PXQ+M3hjYH/v0K4UEYl5ljzpNM1i52eQM+gFooojT87PDSaphT
|
||||
fs0PXy/PTAjHBEvPhWpOpmQXfJNYzjwcCvg66hbqkv++/VTZiFLAsHagzkEz+FRJ
|
||||
qT5Eq7G5FLyw1izX1uxyPN7tAEWEEg7eqsiaXD3Cq8+TYN9cjirPeF7RZF8yFCYE
|
||||
xqvbo+Yc6RL6xw19iXVTfctRgQe581KQuIY5/LXo3dWDEilFdsADAe8XAEcO64es
|
||||
Ow0g1UvXLnpXSE151kXBFb3sKH/ZjCecDYMCIMEb4sWLSblkSxJ5sNSmXIG4wtr2
|
||||
Qnii7CXZgnVYraQE/Jyh+NMQANuoSdMCAwEAAaNTMFEwHQYDVR0OBBYEFAyQQQuM
|
||||
ab+YUQqjK8dVVOoHVFmXMB8GA1UdIwQYMBaAFAyQQQuMab+YUQqjK8dVVOoHVFmX
|
||||
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADj0vQ6ykWhicoqR
|
||||
e6VZMwlEJV7/DSvWWKBd9MUjfKye0A4565ya5lmnzP3DiD3nqGe3miqmLsXKDs+X
|
||||
POqlPXTWIamP7D4MJ32XtSLwZB4ru+I+Ao/P/VngPepoRPQoBnzHe7jww0rokqxl
|
||||
AZERjlbTUwUAy/BPWPSzSJZ2j0tcs6ZLDNyYzpK4ao8R9/1VmQ92Tcp3feJs1QTg
|
||||
odRQc3om/AkWOwsll+oyX0UbJeHkFHiLanUPXbdh+/BkSvZJ8ynL+feSDdaurPe+
|
||||
PSfnqLtQft9/neecGRdEaQzzzSFVQUVQzTdK1Q7hA7b55b2HvIa3ktDiks+sJsYN
|
||||
Dhm6uZM=
|
||||
-----END CERTIFICATE-----
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAorX749dD4zeGNgf+/QrhQRiXmWPOk0zWLnZ5Az6AWiiiNPzs
|
||||
8NJqmFN+zQ9fL89MCMcES8+Fak6mZBd8k1jOPBwK+DrqFuqS/779VNmIUsCwdqDO
|
||||
QTP4VEmpPkSrsbkUvLDWLNfW7HI83u0ARYQSDt6qyJpcPcKrz5Ng31yOKs94XtFk
|
||||
XzIUJgTGq9uj5hzpEvrHDX2JdVN9y1GBB7nzUpC4hjn8tejd1YMSKUV2wAMB7xcA
|
||||
Rw7rh6w7DSDVS9cueldITXnWRcEVvewof9mMJ5wNgwIgwRvixYtJuWRLEnmw1KZc
|
||||
gbjC2vZCeKLsJdmCdVitpAT8nKH40xAA26hJ0wIDAQABAoIBACaNR+lsD8G+XiZf
|
||||
LqN1+HkcAo9tfnyYMAdCOtnx7SdviT9Uzi8hK/B7mAeuJLeHPlS2EuaDfPD7QaFl
|
||||
jza6S+MiIdc+3kgfvESsVAnOoOY6kZUJ9NSuI6CU82y1iJjLaYZrv9NQMLRFPPb0
|
||||
4KOX709mosB1EnXvshW0rbc+jtDFhrm1SxMt+k9TuzmMxjbOeW4LOLXPgU8X1T3Q
|
||||
Xy0hMZZtcgBs9wFIo8yCtmOixax9pnFE8rRltgDxTodn9LLdz1FieyntNgDksZ0P
|
||||
nt4kV7Mqly7ELaea+Foaj244mKsesic2e3GhAlMRLun/VSunSf7mOCxfpITB8dp1
|
||||
drDhOYECgYEA19151dVxRcviuovN6Dar+QszMTnU8pDJ8BjLFjXjP/hNBBwMTHDE
|
||||
duMuWk2qnwZqMooI/shxrF/ufmTgS0CFrh2+ANBZu27vWConJNXcyNtdigI4wt50
|
||||
L0Y2qcZn2mg67qFXHwoR3QNwrwnPwEjRXA09at9CSRZzcwDQ0ETXhYsCgYEAwPaG
|
||||
06QdK8Zyly7TTzZJwxzv9uGiqzodmGtX6NEKjgij2JaCxHpukqZBJoqa0jKeK1cm
|
||||
eNVkOvT5ff9TMzarSHQLr3pZen2/oVLb5gaFkbcJt/klv9Fd+ZRilHY3i6QwS6pD
|
||||
uMiPOWS4DrLHDRVoVlAZTDjT1RVwwTs+P2NhJdkCgYEAsriXysbxBYyMp05gqEW7
|
||||
lHIFbFgpSrs9th+Q5U6wW6JEgYaHWDJ1NslY80MiZI93FWjbkbZ7BvBWESeL3EIL
|
||||
a+EMErht0pVCbIhZ6FF4foPAqia0wAJVx14mm+G80kNBp5jE/NnleEsE3KcO7nBb
|
||||
hg8gLn+x7bk81JZ0TDrzBYkCgYEAuQKluv47SeF3tSScTfKLPpvcKCWmxe1uutkQ
|
||||
7JShPhVioyOMNb39jnYBOWbjkm4d4QgqRuiytSR0oi3QI+Ziy5EYMyNn713qAk9j
|
||||
r2TJZDDPDKnBW+zt4YI4EohWMXk3JRUW4XDKggjjwJQA7bZ812TtHHvP/xoThfG7
|
||||
eSNb3eECgYBw6ssgCtMrdvQiEmjKVX/9yI38mvC2kSGyzbrQnGUfgqRGomRpeZuD
|
||||
B5E3kysA4td5pT5lvcLgSW0TbOz+YbiriXjwOihPIelCvc9gE2eOUI71/byUWPFz
|
||||
7u5F/xQ4NaGr5suLF+lBC6h7pSbM4El9lIHQAQadpuEdzHqrw+hs3g==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+309
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package v2 provides the S2Av2 transport credentials used by a gRPC
|
||||
// application.
|
||||
package v2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"flag"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/google/s2a-go/fallback"
|
||||
"github.com/google/s2a-go/internal/handshaker/service"
|
||||
"github.com/google/s2a-go/internal/tokenmanager"
|
||||
"github.com/google/s2a-go/internal/v2/tlsconfigstore"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
|
||||
commonpbv1 "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
s2av2pb "github.com/google/s2a-go/internal/proto/v2/s2a_go_proto"
|
||||
)
|
||||
|
||||
const (
|
||||
s2aSecurityProtocol = "tls"
|
||||
)
|
||||
|
||||
var S2ATimeout = flag.Duration("s2a_timeout", 3*time.Second, "Timeout enforced on the connection to the S2A service for handshake.")
|
||||
|
||||
type s2av2TransportCreds struct {
|
||||
info *credentials.ProtocolInfo
|
||||
isClient bool
|
||||
serverName string
|
||||
s2av2Address string
|
||||
tokenManager *tokenmanager.AccessTokenManager
|
||||
// localIdentity should only be used by the client.
|
||||
localIdentity *commonpbv1.Identity
|
||||
// localIdentities should only be used by the server.
|
||||
localIdentities []*commonpbv1.Identity
|
||||
verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode
|
||||
fallbackClientHandshake fallback.ClientHandshake
|
||||
}
|
||||
|
||||
// NewClientCreds returns a client-side transport credentials object that uses
|
||||
// the S2Av2 to establish a secure connection with a server.
|
||||
func NewClientCreds(s2av2Address string, localIdentity *commonpbv1.Identity, verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode, fallbackClientHandshakeFunc fallback.ClientHandshake) (credentials.TransportCredentials, error) {
|
||||
// Create an AccessTokenManager instance to use to authenticate to S2Av2.
|
||||
accessTokenManager, err := tokenmanager.NewSingleTokenAccessTokenManager()
|
||||
|
||||
creds := &s2av2TransportCreds{
|
||||
info: &credentials.ProtocolInfo{
|
||||
SecurityProtocol: s2aSecurityProtocol,
|
||||
},
|
||||
isClient: true,
|
||||
serverName: "",
|
||||
s2av2Address: s2av2Address,
|
||||
localIdentity: localIdentity,
|
||||
verificationMode: verificationMode,
|
||||
fallbackClientHandshake: fallbackClientHandshakeFunc,
|
||||
}
|
||||
if err != nil {
|
||||
creds.tokenManager = nil
|
||||
} else {
|
||||
creds.tokenManager = &accessTokenManager
|
||||
}
|
||||
if grpclog.V(1) {
|
||||
grpclog.Info("Created client S2Av2 transport credentials.")
|
||||
}
|
||||
return creds, nil
|
||||
}
|
||||
|
||||
// NewServerCreds returns a server-side transport credentials object that uses
|
||||
// the S2Av2 to establish a secure connection with a client.
|
||||
func NewServerCreds(s2av2Address string, localIdentities []*commonpbv1.Identity, verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode) (credentials.TransportCredentials, error) {
|
||||
// Create an AccessTokenManager instance to use to authenticate to S2Av2.
|
||||
accessTokenManager, err := tokenmanager.NewSingleTokenAccessTokenManager()
|
||||
creds := &s2av2TransportCreds{
|
||||
info: &credentials.ProtocolInfo{
|
||||
SecurityProtocol: s2aSecurityProtocol,
|
||||
},
|
||||
isClient: false,
|
||||
s2av2Address: s2av2Address,
|
||||
localIdentities: localIdentities,
|
||||
verificationMode: verificationMode,
|
||||
}
|
||||
if err != nil {
|
||||
creds.tokenManager = nil
|
||||
} else {
|
||||
creds.tokenManager = &accessTokenManager
|
||||
}
|
||||
if grpclog.V(1) {
|
||||
grpclog.Info("Created server S2Av2 transport credentials.")
|
||||
}
|
||||
return creds, nil
|
||||
}
|
||||
|
||||
// ClientHandshake performs a client-side mTLS handshake using the S2Av2.
|
||||
func (c *s2av2TransportCreds) ClientHandshake(ctx context.Context, serverAuthority string, rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
|
||||
if !c.isClient {
|
||||
return nil, nil, errors.New("client handshake called using server transport credentials")
|
||||
}
|
||||
// Remove the port from serverAuthority.
|
||||
serverName := removeServerNamePort(serverAuthority)
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, *S2ATimeout)
|
||||
defer cancel()
|
||||
cstream, err := createStream(timeoutCtx, c.s2av2Address)
|
||||
if err != nil {
|
||||
grpclog.Infof("Failed to connect to S2Av2: %v", err)
|
||||
if c.fallbackClientHandshake != nil {
|
||||
return c.fallbackClientHandshake(ctx, serverAuthority, rawConn, err)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
if grpclog.V(1) {
|
||||
grpclog.Infof("Connected to S2Av2.")
|
||||
}
|
||||
var config *tls.Config
|
||||
|
||||
var tokenManager tokenmanager.AccessTokenManager
|
||||
if c.tokenManager == nil {
|
||||
tokenManager = nil
|
||||
} else {
|
||||
tokenManager = *c.tokenManager
|
||||
}
|
||||
|
||||
if c.serverName == "" {
|
||||
config, err = tlsconfigstore.GetTLSConfigurationForClient(serverName, cstream, tokenManager, c.localIdentity, c.verificationMode)
|
||||
if err != nil {
|
||||
grpclog.Info("Failed to get client TLS config from S2Av2: %v", err)
|
||||
if c.fallbackClientHandshake != nil {
|
||||
return c.fallbackClientHandshake(ctx, serverAuthority, rawConn, err)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
} else {
|
||||
config, err = tlsconfigstore.GetTLSConfigurationForClient(c.serverName, cstream, tokenManager, c.localIdentity, c.verificationMode)
|
||||
if err != nil {
|
||||
grpclog.Info("Failed to get client TLS config from S2Av2: %v", err)
|
||||
if c.fallbackClientHandshake != nil {
|
||||
return c.fallbackClientHandshake(ctx, serverAuthority, rawConn, err)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
if grpclog.V(1) {
|
||||
grpclog.Infof("Got client TLS config from S2Av2.")
|
||||
}
|
||||
creds := credentials.NewTLS(config)
|
||||
|
||||
conn, authInfo, err := creds.ClientHandshake(ctx, serverName, rawConn)
|
||||
if err != nil {
|
||||
grpclog.Infof("Failed to do client handshake using S2Av2: %v", err)
|
||||
if c.fallbackClientHandshake != nil {
|
||||
return c.fallbackClientHandshake(ctx, serverAuthority, rawConn, err)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
grpclog.Infof("Successfully done client handshake using S2Av2 to: %s", serverName)
|
||||
|
||||
return conn, authInfo, err
|
||||
}
|
||||
|
||||
// ServerHandshake performs a server-side mTLS handshake using the S2Av2.
|
||||
func (c *s2av2TransportCreds) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
|
||||
if c.isClient {
|
||||
return nil, nil, errors.New("server handshake called using client transport credentials")
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), *S2ATimeout)
|
||||
defer cancel()
|
||||
cstream, err := createStream(ctx, c.s2av2Address)
|
||||
if err != nil {
|
||||
grpclog.Infof("Failed to connect to S2Av2: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
if grpclog.V(1) {
|
||||
grpclog.Infof("Connected to S2Av2.")
|
||||
}
|
||||
|
||||
var tokenManager tokenmanager.AccessTokenManager
|
||||
if c.tokenManager == nil {
|
||||
tokenManager = nil
|
||||
} else {
|
||||
tokenManager = *c.tokenManager
|
||||
}
|
||||
|
||||
config, err := tlsconfigstore.GetTLSConfigurationForServer(cstream, tokenManager, c.localIdentities, c.verificationMode)
|
||||
if err != nil {
|
||||
grpclog.Infof("Failed to get server TLS config from S2Av2: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
if grpclog.V(1) {
|
||||
grpclog.Infof("Got server TLS config from S2Av2.")
|
||||
}
|
||||
creds := credentials.NewTLS(config)
|
||||
return creds.ServerHandshake(rawConn)
|
||||
}
|
||||
|
||||
// Info returns protocol info of s2av2TransportCreds.
|
||||
func (c *s2av2TransportCreds) Info() credentials.ProtocolInfo {
|
||||
return *c.info
|
||||
}
|
||||
|
||||
// Clone makes a deep copy of s2av2TransportCreds.
|
||||
func (c *s2av2TransportCreds) Clone() credentials.TransportCredentials {
|
||||
info := *c.info
|
||||
serverName := c.serverName
|
||||
fallbackClientHandshake := c.fallbackClientHandshake
|
||||
|
||||
s2av2Address := c.s2av2Address
|
||||
var tokenManager tokenmanager.AccessTokenManager
|
||||
if c.tokenManager == nil {
|
||||
tokenManager = nil
|
||||
} else {
|
||||
tokenManager = *c.tokenManager
|
||||
}
|
||||
verificationMode := c.verificationMode
|
||||
var localIdentity *commonpbv1.Identity
|
||||
if c.localIdentity != nil {
|
||||
localIdentity = proto.Clone(c.localIdentity).(*commonpbv1.Identity)
|
||||
}
|
||||
var localIdentities []*commonpbv1.Identity
|
||||
if c.localIdentities != nil {
|
||||
localIdentities = make([]*commonpbv1.Identity, len(c.localIdentities))
|
||||
for i, localIdentity := range c.localIdentities {
|
||||
localIdentities[i] = proto.Clone(localIdentity).(*commonpbv1.Identity)
|
||||
}
|
||||
}
|
||||
creds := &s2av2TransportCreds{
|
||||
info: &info,
|
||||
isClient: c.isClient,
|
||||
serverName: serverName,
|
||||
fallbackClientHandshake: fallbackClientHandshake,
|
||||
s2av2Address: s2av2Address,
|
||||
localIdentity: localIdentity,
|
||||
localIdentities: localIdentities,
|
||||
verificationMode: verificationMode,
|
||||
}
|
||||
if c.tokenManager == nil {
|
||||
creds.tokenManager = nil
|
||||
} else {
|
||||
creds.tokenManager = &tokenManager
|
||||
}
|
||||
return creds
|
||||
}
|
||||
|
||||
// NewClientTLSConfig returns a tls.Config instance that uses S2Av2 to establish a TLS connection as
|
||||
// a client. The tls.Config MUST only be used to establish a single TLS connection.
|
||||
func NewClientTLSConfig(
|
||||
ctx context.Context,
|
||||
s2av2Address string,
|
||||
tokenManager tokenmanager.AccessTokenManager,
|
||||
verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode,
|
||||
serverName string) (*tls.Config, error) {
|
||||
cstream, err := createStream(ctx, s2av2Address)
|
||||
if err != nil {
|
||||
grpclog.Infof("Failed to connect to S2Av2: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tlsconfigstore.GetTLSConfigurationForClient(removeServerNamePort(serverName), cstream, tokenManager, nil, verificationMode)
|
||||
}
|
||||
|
||||
// OverrideServerName sets the ServerName in the s2av2TransportCreds protocol
|
||||
// info. The ServerName MUST be a hostname.
|
||||
func (c *s2av2TransportCreds) OverrideServerName(serverNameOverride string) error {
|
||||
serverName := removeServerNamePort(serverNameOverride)
|
||||
c.info.ServerName = serverName
|
||||
c.serverName = serverName
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove the trailing port from server name.
|
||||
func removeServerNamePort(serverName string) string {
|
||||
name, _, err := net.SplitHostPort(serverName)
|
||||
if err != nil {
|
||||
name = serverName
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func createStream(ctx context.Context, s2av2Address string) (s2av2pb.S2AService_SetUpSessionClient, error) {
|
||||
// TODO(rmehta19): Consider whether to close the connection to S2Av2.
|
||||
conn, err := service.Dial(s2av2Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client := s2av2pb.NewS2AServiceClient(conn)
|
||||
return client.SetUpSession(ctx, []grpc.CallOption{}...)
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID8TCCAtmgAwIBAgIUKXNlBRVe6UepjQUijIFPZBd/4qYwDQYJKoZIhvcNAQEL
|
||||
BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2
|
||||
YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE
|
||||
AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN
|
||||
MjIwNTMxMjAwMzE1WhcNNDIwNTI2MjAwMzE1WjCBhzELMAkGA1UEBhMCVVMxCzAJ
|
||||
BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx
|
||||
ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ
|
||||
KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBAOOFuIucH7XXfohGxKd3uR/ihUA/LdduR9I8kfpUEbq5BOt8xZe5/Yn9
|
||||
a1ozEHVW6cOAbHbnwAR8tkSgZ/t42QIA2k77HWU1Jh2xiEIsJivo3imm4/kZWuR0
|
||||
OqPh7MhzxpR/hvNwpI5mJsAVBWFMa5KtecFZLnyZtwHylrRN1QXzuLrOxuKFufK3
|
||||
RKbTABScn5RbZL976H/jgfSeXrbt242NrIoBnVe6fRbekbq2DQ6zFArbQMUgHjHK
|
||||
P0UqBgdr1QmHfi9KytFyx9BTP3gXWnWIu+bY7/v7qKJMHFwGETo+dCLWYevJL316
|
||||
HnLfhApDMfP8U+Yv/y1N/YvgaSOSlEcCAwEAAaNTMFEwHQYDVR0OBBYEFKhAU4nu
|
||||
0h/lrnggbIGvx4ej0WklMB8GA1UdIwQYMBaAFKhAU4nu0h/lrnggbIGvx4ej0Wkl
|
||||
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAE/6NghzQ5fu6yR6
|
||||
EHKbj/YMrFdT7aGn5n2sAf7wJ33LIhiFHkpWBsVlm7rDtZtwhe891ZK/P60anlg9
|
||||
/P0Ua53tSRVRmCvTnEbXWOVMN4is6MsR7BlmzUxl4AtIn7jbeifEwRL7B4xDYmdA
|
||||
QrQnsqoz45dLgS5xK4WDqXATP09Q91xQDuhud/b+A4jrvgwFASmL7rMIZbp4f1JQ
|
||||
nlnl/9VoTBQBvJiWkDUtQDMpRLtauddEkv4AGz75p5IspXWD6cOemuh2iQec11xD
|
||||
X20rs2WZbAcAiUa3nmy8OKYw435vmpj8gp39WYbX/Yx9TymrFFbVY92wYn+quTco
|
||||
pKklVz0=
|
||||
-----END CERTIFICATE-----
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEA44W4i5wftdd+iEbEp3e5H+KFQD8t125H0jyR+lQRurkE63zF
|
||||
l7n9if1rWjMQdVbpw4BsdufABHy2RKBn+3jZAgDaTvsdZTUmHbGIQiwmK+jeKabj
|
||||
+Rla5HQ6o+HsyHPGlH+G83CkjmYmwBUFYUxrkq15wVkufJm3AfKWtE3VBfO4us7G
|
||||
4oW58rdEptMAFJyflFtkv3vof+OB9J5etu3bjY2sigGdV7p9Ft6RurYNDrMUCttA
|
||||
xSAeMco/RSoGB2vVCYd+L0rK0XLH0FM/eBdadYi75tjv+/uookwcXAYROj50ItZh
|
||||
68kvfXoect+ECkMx8/xT5i//LU39i+BpI5KURwIDAQABAoIBABgyjo/6iLzUMFbZ
|
||||
/+w3pW6orrdIgN2akvTfED9pVYFgUA+jc3hRhY95bkNnjuaL2cy7Cc4Tk65mfRQL
|
||||
Y0OxdJLr+EvSFSxAXM9npDA1ddHRsF8JqtFBSxNk8R+g1Yf0GDiO35Fgd3/ViWWA
|
||||
VtQkRoSRApP3oiQKTRZd8H04keFR+PvmDk/Lq11l3Kc24A1PevKIPX1oI990ggw9
|
||||
9i4uSV+cnuMxmcI9xxJtgwdDFdjr39l2arLOHr4s6LGoV2IOdXHNlv5xRqWUZ0FH
|
||||
MDHowkLgwDrdSTnNeaVNkce14Gqx+bd4hNaLCdKXMpedBTEmrut3f3hdV1kKjaKt
|
||||
aqRYr8ECgYEA/YDGZY2jvFoHHBywlqmEMFrrCvQGH51m5R1Ntpkzr+Rh3YCmrpvq
|
||||
xgwJXING0PUw3dz+xrH5lJICrfNE5Kt3fPu1rAEy+13mYsNowghtUq2Rtu0Hsjjx
|
||||
2E3Bf8vEB6RNBMmGkUpTTIAroGF5tpJoRvfnWax+k4pFdrKYFtyZdNcCgYEA5cNv
|
||||
EPltvOobjTXlUmtVP3n27KZN2aXexTcagLzRxE9CV4cYySENl3KuOMmccaZpIl6z
|
||||
aHk6BT4X+M0LqElNUczrInfVqI+SGAFLGy7W6CJaqSr6cpyFUP/fosKpm6wKGgLq
|
||||
udHfpvz5rckhKd8kJxFLvhGOK9yN5qpzih0gfhECgYAJfwRvk3G5wYmYpP58dlcs
|
||||
VIuPenqsPoI3PPTHTU/hW+XKnWIhElgmGRdUrto9Q6IT/Y5RtSMLTLjq+Tzwb/fm
|
||||
56rziYv2XJsfwgAvnI8z1Kqrto9ePsHYf3krJ1/thVsZPc9bq/QY3ohD1sLvcuaT
|
||||
GgBBnLOVJU3a12/ZE2RwOwKBgF0csWMAoj8/5IB6if+3ral2xOGsl7oPZVMo/J2V
|
||||
Z7EVqb4M6rd/pKFugTpUQgkwtkSOekhpcGD1hAN5HTNK2YG/+L5UMAsKe9sskwJm
|
||||
HgOfAHy0BSDzW3ey6i9skg2bT9Cww+0gJ3Hl7U1HSCBO5LjMYpSZSrNtwzfqdb5Q
|
||||
BX3xAoGARZdR28Ej3+/+0+fz47Yu2h4z0EI/EbrudLOWY936jIeAVwHckI3+BuqH
|
||||
qR4poj1gfbnMxNuI9UzIXzjEmGewx9kDZ7IYnvloZKqoVQODO5GlKF2ja6IcMNlh
|
||||
GCNdD6PSAS6HcmalmWo9sj+1YMkrl+GJikKZqVBHrHNwMGAG67w=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID8TCCAtmgAwIBAgIUKCoDuLtiZXvhsBY2RoDm0ugizJ8wDQYJKoZIhvcNAQEL
|
||||
BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2
|
||||
YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE
|
||||
AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN
|
||||
MjIwNTMxMjAwODI1WhcNNDIwNTI2MjAwODI1WjCBhzELMAkGA1UEBhMCVVMxCzAJ
|
||||
BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx
|
||||
ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ
|
||||
KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBAKK1++PXQ+M3hjYH/v0K4UEYl5ljzpNM1i52eQM+gFooojT87PDSaphT
|
||||
fs0PXy/PTAjHBEvPhWpOpmQXfJNYzjwcCvg66hbqkv++/VTZiFLAsHagzkEz+FRJ
|
||||
qT5Eq7G5FLyw1izX1uxyPN7tAEWEEg7eqsiaXD3Cq8+TYN9cjirPeF7RZF8yFCYE
|
||||
xqvbo+Yc6RL6xw19iXVTfctRgQe581KQuIY5/LXo3dWDEilFdsADAe8XAEcO64es
|
||||
Ow0g1UvXLnpXSE151kXBFb3sKH/ZjCecDYMCIMEb4sWLSblkSxJ5sNSmXIG4wtr2
|
||||
Qnii7CXZgnVYraQE/Jyh+NMQANuoSdMCAwEAAaNTMFEwHQYDVR0OBBYEFAyQQQuM
|
||||
ab+YUQqjK8dVVOoHVFmXMB8GA1UdIwQYMBaAFAyQQQuMab+YUQqjK8dVVOoHVFmX
|
||||
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADj0vQ6ykWhicoqR
|
||||
e6VZMwlEJV7/DSvWWKBd9MUjfKye0A4565ya5lmnzP3DiD3nqGe3miqmLsXKDs+X
|
||||
POqlPXTWIamP7D4MJ32XtSLwZB4ru+I+Ao/P/VngPepoRPQoBnzHe7jww0rokqxl
|
||||
AZERjlbTUwUAy/BPWPSzSJZ2j0tcs6ZLDNyYzpK4ao8R9/1VmQ92Tcp3feJs1QTg
|
||||
odRQc3om/AkWOwsll+oyX0UbJeHkFHiLanUPXbdh+/BkSvZJ8ynL+feSDdaurPe+
|
||||
PSfnqLtQft9/neecGRdEaQzzzSFVQUVQzTdK1Q7hA7b55b2HvIa3ktDiks+sJsYN
|
||||
Dhm6uZM=
|
||||
-----END CERTIFICATE-----
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAorX749dD4zeGNgf+/QrhQRiXmWPOk0zWLnZ5Az6AWiiiNPzs
|
||||
8NJqmFN+zQ9fL89MCMcES8+Fak6mZBd8k1jOPBwK+DrqFuqS/779VNmIUsCwdqDO
|
||||
QTP4VEmpPkSrsbkUvLDWLNfW7HI83u0ARYQSDt6qyJpcPcKrz5Ng31yOKs94XtFk
|
||||
XzIUJgTGq9uj5hzpEvrHDX2JdVN9y1GBB7nzUpC4hjn8tejd1YMSKUV2wAMB7xcA
|
||||
Rw7rh6w7DSDVS9cueldITXnWRcEVvewof9mMJ5wNgwIgwRvixYtJuWRLEnmw1KZc
|
||||
gbjC2vZCeKLsJdmCdVitpAT8nKH40xAA26hJ0wIDAQABAoIBACaNR+lsD8G+XiZf
|
||||
LqN1+HkcAo9tfnyYMAdCOtnx7SdviT9Uzi8hK/B7mAeuJLeHPlS2EuaDfPD7QaFl
|
||||
jza6S+MiIdc+3kgfvESsVAnOoOY6kZUJ9NSuI6CU82y1iJjLaYZrv9NQMLRFPPb0
|
||||
4KOX709mosB1EnXvshW0rbc+jtDFhrm1SxMt+k9TuzmMxjbOeW4LOLXPgU8X1T3Q
|
||||
Xy0hMZZtcgBs9wFIo8yCtmOixax9pnFE8rRltgDxTodn9LLdz1FieyntNgDksZ0P
|
||||
nt4kV7Mqly7ELaea+Foaj244mKsesic2e3GhAlMRLun/VSunSf7mOCxfpITB8dp1
|
||||
drDhOYECgYEA19151dVxRcviuovN6Dar+QszMTnU8pDJ8BjLFjXjP/hNBBwMTHDE
|
||||
duMuWk2qnwZqMooI/shxrF/ufmTgS0CFrh2+ANBZu27vWConJNXcyNtdigI4wt50
|
||||
L0Y2qcZn2mg67qFXHwoR3QNwrwnPwEjRXA09at9CSRZzcwDQ0ETXhYsCgYEAwPaG
|
||||
06QdK8Zyly7TTzZJwxzv9uGiqzodmGtX6NEKjgij2JaCxHpukqZBJoqa0jKeK1cm
|
||||
eNVkOvT5ff9TMzarSHQLr3pZen2/oVLb5gaFkbcJt/klv9Fd+ZRilHY3i6QwS6pD
|
||||
uMiPOWS4DrLHDRVoVlAZTDjT1RVwwTs+P2NhJdkCgYEAsriXysbxBYyMp05gqEW7
|
||||
lHIFbFgpSrs9th+Q5U6wW6JEgYaHWDJ1NslY80MiZI93FWjbkbZ7BvBWESeL3EIL
|
||||
a+EMErht0pVCbIhZ6FF4foPAqia0wAJVx14mm+G80kNBp5jE/NnleEsE3KcO7nBb
|
||||
hg8gLn+x7bk81JZ0TDrzBYkCgYEAuQKluv47SeF3tSScTfKLPpvcKCWmxe1uutkQ
|
||||
7JShPhVioyOMNb39jnYBOWbjkm4d4QgqRuiytSR0oi3QI+Ziy5EYMyNn713qAk9j
|
||||
r2TJZDDPDKnBW+zt4YI4EohWMXk3JRUW4XDKggjjwJQA7bZ812TtHHvP/xoThfG7
|
||||
eSNb3eECgYBw6ssgCtMrdvQiEmjKVX/9yI38mvC2kSGyzbrQnGUfgqRGomRpeZuD
|
||||
B5E3kysA4td5pT5lvcLgSW0TbOz+YbiriXjwOihPIelCvc9gE2eOUI71/byUWPFz
|
||||
7u5F/xQ4NaGr5suLF+lBC6h7pSbM4El9lIHQAQadpuEdzHqrw+hs3g==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
Generated
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID8TCCAtmgAwIBAgIUKXNlBRVe6UepjQUijIFPZBd/4qYwDQYJKoZIhvcNAQEL
|
||||
BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2
|
||||
YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE
|
||||
AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN
|
||||
MjIwNTMxMjAwMzE1WhcNNDIwNTI2MjAwMzE1WjCBhzELMAkGA1UEBhMCVVMxCzAJ
|
||||
BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx
|
||||
ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ
|
||||
KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBAOOFuIucH7XXfohGxKd3uR/ihUA/LdduR9I8kfpUEbq5BOt8xZe5/Yn9
|
||||
a1ozEHVW6cOAbHbnwAR8tkSgZ/t42QIA2k77HWU1Jh2xiEIsJivo3imm4/kZWuR0
|
||||
OqPh7MhzxpR/hvNwpI5mJsAVBWFMa5KtecFZLnyZtwHylrRN1QXzuLrOxuKFufK3
|
||||
RKbTABScn5RbZL976H/jgfSeXrbt242NrIoBnVe6fRbekbq2DQ6zFArbQMUgHjHK
|
||||
P0UqBgdr1QmHfi9KytFyx9BTP3gXWnWIu+bY7/v7qKJMHFwGETo+dCLWYevJL316
|
||||
HnLfhApDMfP8U+Yv/y1N/YvgaSOSlEcCAwEAAaNTMFEwHQYDVR0OBBYEFKhAU4nu
|
||||
0h/lrnggbIGvx4ej0WklMB8GA1UdIwQYMBaAFKhAU4nu0h/lrnggbIGvx4ej0Wkl
|
||||
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAE/6NghzQ5fu6yR6
|
||||
EHKbj/YMrFdT7aGn5n2sAf7wJ33LIhiFHkpWBsVlm7rDtZtwhe891ZK/P60anlg9
|
||||
/P0Ua53tSRVRmCvTnEbXWOVMN4is6MsR7BlmzUxl4AtIn7jbeifEwRL7B4xDYmdA
|
||||
QrQnsqoz45dLgS5xK4WDqXATP09Q91xQDuhud/b+A4jrvgwFASmL7rMIZbp4f1JQ
|
||||
nlnl/9VoTBQBvJiWkDUtQDMpRLtauddEkv4AGz75p5IspXWD6cOemuh2iQec11xD
|
||||
X20rs2WZbAcAiUa3nmy8OKYw435vmpj8gp39WYbX/Yx9TymrFFbVY92wYn+quTco
|
||||
pKklVz0=
|
||||
-----END CERTIFICATE-----
|
||||
Generated
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEA44W4i5wftdd+iEbEp3e5H+KFQD8t125H0jyR+lQRurkE63zF
|
||||
l7n9if1rWjMQdVbpw4BsdufABHy2RKBn+3jZAgDaTvsdZTUmHbGIQiwmK+jeKabj
|
||||
+Rla5HQ6o+HsyHPGlH+G83CkjmYmwBUFYUxrkq15wVkufJm3AfKWtE3VBfO4us7G
|
||||
4oW58rdEptMAFJyflFtkv3vof+OB9J5etu3bjY2sigGdV7p9Ft6RurYNDrMUCttA
|
||||
xSAeMco/RSoGB2vVCYd+L0rK0XLH0FM/eBdadYi75tjv+/uookwcXAYROj50ItZh
|
||||
68kvfXoect+ECkMx8/xT5i//LU39i+BpI5KURwIDAQABAoIBABgyjo/6iLzUMFbZ
|
||||
/+w3pW6orrdIgN2akvTfED9pVYFgUA+jc3hRhY95bkNnjuaL2cy7Cc4Tk65mfRQL
|
||||
Y0OxdJLr+EvSFSxAXM9npDA1ddHRsF8JqtFBSxNk8R+g1Yf0GDiO35Fgd3/ViWWA
|
||||
VtQkRoSRApP3oiQKTRZd8H04keFR+PvmDk/Lq11l3Kc24A1PevKIPX1oI990ggw9
|
||||
9i4uSV+cnuMxmcI9xxJtgwdDFdjr39l2arLOHr4s6LGoV2IOdXHNlv5xRqWUZ0FH
|
||||
MDHowkLgwDrdSTnNeaVNkce14Gqx+bd4hNaLCdKXMpedBTEmrut3f3hdV1kKjaKt
|
||||
aqRYr8ECgYEA/YDGZY2jvFoHHBywlqmEMFrrCvQGH51m5R1Ntpkzr+Rh3YCmrpvq
|
||||
xgwJXING0PUw3dz+xrH5lJICrfNE5Kt3fPu1rAEy+13mYsNowghtUq2Rtu0Hsjjx
|
||||
2E3Bf8vEB6RNBMmGkUpTTIAroGF5tpJoRvfnWax+k4pFdrKYFtyZdNcCgYEA5cNv
|
||||
EPltvOobjTXlUmtVP3n27KZN2aXexTcagLzRxE9CV4cYySENl3KuOMmccaZpIl6z
|
||||
aHk6BT4X+M0LqElNUczrInfVqI+SGAFLGy7W6CJaqSr6cpyFUP/fosKpm6wKGgLq
|
||||
udHfpvz5rckhKd8kJxFLvhGOK9yN5qpzih0gfhECgYAJfwRvk3G5wYmYpP58dlcs
|
||||
VIuPenqsPoI3PPTHTU/hW+XKnWIhElgmGRdUrto9Q6IT/Y5RtSMLTLjq+Tzwb/fm
|
||||
56rziYv2XJsfwgAvnI8z1Kqrto9ePsHYf3krJ1/thVsZPc9bq/QY3ohD1sLvcuaT
|
||||
GgBBnLOVJU3a12/ZE2RwOwKBgF0csWMAoj8/5IB6if+3ral2xOGsl7oPZVMo/J2V
|
||||
Z7EVqb4M6rd/pKFugTpUQgkwtkSOekhpcGD1hAN5HTNK2YG/+L5UMAsKe9sskwJm
|
||||
HgOfAHy0BSDzW3ey6i9skg2bT9Cww+0gJ3Hl7U1HSCBO5LjMYpSZSrNtwzfqdb5Q
|
||||
BX3xAoGARZdR28Ej3+/+0+fz47Yu2h4z0EI/EbrudLOWY936jIeAVwHckI3+BuqH
|
||||
qR4poj1gfbnMxNuI9UzIXzjEmGewx9kDZ7IYnvloZKqoVQODO5GlKF2ja6IcMNlh
|
||||
GCNdD6PSAS6HcmalmWo9sj+1YMkrl+GJikKZqVBHrHNwMGAG67w=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
Generated
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID8TCCAtmgAwIBAgIUKCoDuLtiZXvhsBY2RoDm0ugizJ8wDQYJKoZIhvcNAQEL
|
||||
BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2
|
||||
YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE
|
||||
AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN
|
||||
MjIwNTMxMjAwODI1WhcNNDIwNTI2MjAwODI1WjCBhzELMAkGA1UEBhMCVVMxCzAJ
|
||||
BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx
|
||||
ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ
|
||||
KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBAKK1++PXQ+M3hjYH/v0K4UEYl5ljzpNM1i52eQM+gFooojT87PDSaphT
|
||||
fs0PXy/PTAjHBEvPhWpOpmQXfJNYzjwcCvg66hbqkv++/VTZiFLAsHagzkEz+FRJ
|
||||
qT5Eq7G5FLyw1izX1uxyPN7tAEWEEg7eqsiaXD3Cq8+TYN9cjirPeF7RZF8yFCYE
|
||||
xqvbo+Yc6RL6xw19iXVTfctRgQe581KQuIY5/LXo3dWDEilFdsADAe8XAEcO64es
|
||||
Ow0g1UvXLnpXSE151kXBFb3sKH/ZjCecDYMCIMEb4sWLSblkSxJ5sNSmXIG4wtr2
|
||||
Qnii7CXZgnVYraQE/Jyh+NMQANuoSdMCAwEAAaNTMFEwHQYDVR0OBBYEFAyQQQuM
|
||||
ab+YUQqjK8dVVOoHVFmXMB8GA1UdIwQYMBaAFAyQQQuMab+YUQqjK8dVVOoHVFmX
|
||||
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADj0vQ6ykWhicoqR
|
||||
e6VZMwlEJV7/DSvWWKBd9MUjfKye0A4565ya5lmnzP3DiD3nqGe3miqmLsXKDs+X
|
||||
POqlPXTWIamP7D4MJ32XtSLwZB4ru+I+Ao/P/VngPepoRPQoBnzHe7jww0rokqxl
|
||||
AZERjlbTUwUAy/BPWPSzSJZ2j0tcs6ZLDNyYzpK4ao8R9/1VmQ92Tcp3feJs1QTg
|
||||
odRQc3om/AkWOwsll+oyX0UbJeHkFHiLanUPXbdh+/BkSvZJ8ynL+feSDdaurPe+
|
||||
PSfnqLtQft9/neecGRdEaQzzzSFVQUVQzTdK1Q7hA7b55b2HvIa3ktDiks+sJsYN
|
||||
Dhm6uZM=
|
||||
-----END CERTIFICATE-----
|
||||
Generated
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAorX749dD4zeGNgf+/QrhQRiXmWPOk0zWLnZ5Az6AWiiiNPzs
|
||||
8NJqmFN+zQ9fL89MCMcES8+Fak6mZBd8k1jOPBwK+DrqFuqS/779VNmIUsCwdqDO
|
||||
QTP4VEmpPkSrsbkUvLDWLNfW7HI83u0ARYQSDt6qyJpcPcKrz5Ng31yOKs94XtFk
|
||||
XzIUJgTGq9uj5hzpEvrHDX2JdVN9y1GBB7nzUpC4hjn8tejd1YMSKUV2wAMB7xcA
|
||||
Rw7rh6w7DSDVS9cueldITXnWRcEVvewof9mMJ5wNgwIgwRvixYtJuWRLEnmw1KZc
|
||||
gbjC2vZCeKLsJdmCdVitpAT8nKH40xAA26hJ0wIDAQABAoIBACaNR+lsD8G+XiZf
|
||||
LqN1+HkcAo9tfnyYMAdCOtnx7SdviT9Uzi8hK/B7mAeuJLeHPlS2EuaDfPD7QaFl
|
||||
jza6S+MiIdc+3kgfvESsVAnOoOY6kZUJ9NSuI6CU82y1iJjLaYZrv9NQMLRFPPb0
|
||||
4KOX709mosB1EnXvshW0rbc+jtDFhrm1SxMt+k9TuzmMxjbOeW4LOLXPgU8X1T3Q
|
||||
Xy0hMZZtcgBs9wFIo8yCtmOixax9pnFE8rRltgDxTodn9LLdz1FieyntNgDksZ0P
|
||||
nt4kV7Mqly7ELaea+Foaj244mKsesic2e3GhAlMRLun/VSunSf7mOCxfpITB8dp1
|
||||
drDhOYECgYEA19151dVxRcviuovN6Dar+QszMTnU8pDJ8BjLFjXjP/hNBBwMTHDE
|
||||
duMuWk2qnwZqMooI/shxrF/ufmTgS0CFrh2+ANBZu27vWConJNXcyNtdigI4wt50
|
||||
L0Y2qcZn2mg67qFXHwoR3QNwrwnPwEjRXA09at9CSRZzcwDQ0ETXhYsCgYEAwPaG
|
||||
06QdK8Zyly7TTzZJwxzv9uGiqzodmGtX6NEKjgij2JaCxHpukqZBJoqa0jKeK1cm
|
||||
eNVkOvT5ff9TMzarSHQLr3pZen2/oVLb5gaFkbcJt/klv9Fd+ZRilHY3i6QwS6pD
|
||||
uMiPOWS4DrLHDRVoVlAZTDjT1RVwwTs+P2NhJdkCgYEAsriXysbxBYyMp05gqEW7
|
||||
lHIFbFgpSrs9th+Q5U6wW6JEgYaHWDJ1NslY80MiZI93FWjbkbZ7BvBWESeL3EIL
|
||||
a+EMErht0pVCbIhZ6FF4foPAqia0wAJVx14mm+G80kNBp5jE/NnleEsE3KcO7nBb
|
||||
hg8gLn+x7bk81JZ0TDrzBYkCgYEAuQKluv47SeF3tSScTfKLPpvcKCWmxe1uutkQ
|
||||
7JShPhVioyOMNb39jnYBOWbjkm4d4QgqRuiytSR0oi3QI+Ziy5EYMyNn713qAk9j
|
||||
r2TJZDDPDKnBW+zt4YI4EohWMXk3JRUW4XDKggjjwJQA7bZ812TtHHvP/xoThfG7
|
||||
eSNb3eECgYBw6ssgCtMrdvQiEmjKVX/9yI38mvC2kSGyzbrQnGUfgqRGomRpeZuD
|
||||
B5E3kysA4td5pT5lvcLgSW0TbOz+YbiriXjwOihPIelCvc9gE2eOUI71/byUWPFz
|
||||
7u5F/xQ4NaGr5suLF+lBC6h7pSbM4El9lIHQAQadpuEdzHqrw+hs3g==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+403
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package tlsconfigstore offloads operations to S2Av2.
|
||||
package tlsconfigstore
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/s2a-go/internal/tokenmanager"
|
||||
"github.com/google/s2a-go/internal/v2/certverifier"
|
||||
"github.com/google/s2a-go/internal/v2/remotesigner"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
|
||||
commonpbv1 "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
commonpb "github.com/google/s2a-go/internal/proto/v2/common_go_proto"
|
||||
s2av2pb "github.com/google/s2a-go/internal/proto/v2/s2a_go_proto"
|
||||
)
|
||||
|
||||
const (
|
||||
// HTTP/2
|
||||
h2 = "h2"
|
||||
)
|
||||
|
||||
// GetTLSConfigurationForClient returns a tls.Config instance for use by a client application.
|
||||
func GetTLSConfigurationForClient(serverHostname string, cstream s2av2pb.S2AService_SetUpSessionClient, tokenManager tokenmanager.AccessTokenManager, localIdentity *commonpbv1.Identity, verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode) (*tls.Config, error) {
|
||||
authMechanisms := getAuthMechanisms(tokenManager, []*commonpbv1.Identity{localIdentity})
|
||||
|
||||
if grpclog.V(1) {
|
||||
grpclog.Infof("Sending request to S2Av2 for client TLS config.")
|
||||
}
|
||||
// Send request to S2Av2 for config.
|
||||
if err := cstream.Send(&s2av2pb.SessionReq{
|
||||
LocalIdentity: localIdentity,
|
||||
AuthenticationMechanisms: authMechanisms,
|
||||
ReqOneof: &s2av2pb.SessionReq_GetTlsConfigurationReq{
|
||||
GetTlsConfigurationReq: &s2av2pb.GetTlsConfigurationReq{
|
||||
ConnectionSide: commonpb.ConnectionSide_CONNECTION_SIDE_CLIENT,
|
||||
},
|
||||
},
|
||||
}); err != nil {
|
||||
grpclog.Infof("Failed to send request to S2Av2 for client TLS config")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the response containing config from S2Av2.
|
||||
resp, err := cstream.Recv()
|
||||
if err != nil {
|
||||
grpclog.Infof("Failed to receive client TLS config response from S2Av2.")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(rmehta19): Add unit test for this if statement.
|
||||
if (resp.GetStatus() != nil) && (resp.GetStatus().Code != uint32(codes.OK)) {
|
||||
return nil, fmt.Errorf("failed to get TLS configuration from S2A: %d, %v", resp.GetStatus().Code, resp.GetStatus().Details)
|
||||
}
|
||||
|
||||
// Extract TLS configiguration from SessionResp.
|
||||
tlsConfig := resp.GetGetTlsConfigurationResp().GetClientTlsConfiguration()
|
||||
|
||||
var cert tls.Certificate
|
||||
for i, v := range tlsConfig.CertificateChain {
|
||||
// Populate Certificates field.
|
||||
block, _ := pem.Decode([]byte(v))
|
||||
if block == nil {
|
||||
return nil, errors.New("certificate in CertificateChain obtained from S2Av2 is empty")
|
||||
}
|
||||
x509Cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cert.Certificate = append(cert.Certificate, x509Cert.Raw)
|
||||
if i == 0 {
|
||||
cert.Leaf = x509Cert
|
||||
}
|
||||
}
|
||||
|
||||
if len(tlsConfig.CertificateChain) > 0 {
|
||||
cert.PrivateKey = remotesigner.New(cert.Leaf, cstream)
|
||||
if cert.PrivateKey == nil {
|
||||
return nil, errors.New("failed to retrieve Private Key from Remote Signer Library")
|
||||
}
|
||||
}
|
||||
|
||||
minVersion, maxVersion, err := getTLSMinMaxVersionsClient(tlsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create mTLS credentials for client.
|
||||
config := &tls.Config{
|
||||
VerifyPeerCertificate: certverifier.VerifyServerCertificateChain(serverHostname, verificationMode, cstream),
|
||||
ServerName: serverHostname,
|
||||
InsecureSkipVerify: true, // NOLINT
|
||||
ClientSessionCache: nil,
|
||||
SessionTicketsDisabled: true,
|
||||
MinVersion: minVersion,
|
||||
MaxVersion: maxVersion,
|
||||
NextProtos: []string{h2},
|
||||
}
|
||||
if len(tlsConfig.CertificateChain) > 0 {
|
||||
config.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// GetTLSConfigurationForServer returns a tls.Config instance for use by a server application.
|
||||
func GetTLSConfigurationForServer(cstream s2av2pb.S2AService_SetUpSessionClient, tokenManager tokenmanager.AccessTokenManager, localIdentities []*commonpbv1.Identity, verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode) (*tls.Config, error) {
|
||||
return &tls.Config{
|
||||
GetConfigForClient: ClientConfig(tokenManager, localIdentities, verificationMode, cstream),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ClientConfig builds a TLS config for a server to establish a secure
|
||||
// connection with a client, based on SNI communicated during ClientHello.
|
||||
// Ensures that server presents the correct certificate to establish a TLS
|
||||
// connection.
|
||||
func ClientConfig(tokenManager tokenmanager.AccessTokenManager, localIdentities []*commonpbv1.Identity, verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode, cstream s2av2pb.S2AService_SetUpSessionClient) func(chi *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
return func(chi *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
tlsConfig, err := getServerConfigFromS2Av2(tokenManager, localIdentities, chi.ServerName, cstream)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var cert tls.Certificate
|
||||
for i, v := range tlsConfig.CertificateChain {
|
||||
// Populate Certificates field.
|
||||
block, _ := pem.Decode([]byte(v))
|
||||
if block == nil {
|
||||
return nil, errors.New("certificate in CertificateChain obtained from S2Av2 is empty")
|
||||
}
|
||||
x509Cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cert.Certificate = append(cert.Certificate, x509Cert.Raw)
|
||||
if i == 0 {
|
||||
cert.Leaf = x509Cert
|
||||
}
|
||||
}
|
||||
|
||||
cert.PrivateKey = remotesigner.New(cert.Leaf, cstream)
|
||||
if cert.PrivateKey == nil {
|
||||
return nil, errors.New("failed to retrieve Private Key from Remote Signer Library")
|
||||
}
|
||||
|
||||
minVersion, maxVersion, err := getTLSMinMaxVersionsServer(tlsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clientAuth := getTLSClientAuthType(tlsConfig)
|
||||
|
||||
var cipherSuites []uint16
|
||||
cipherSuites = getCipherSuites(tlsConfig.Ciphersuites)
|
||||
|
||||
// Create mTLS credentials for server.
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
VerifyPeerCertificate: certverifier.VerifyClientCertificateChain(verificationMode, cstream),
|
||||
ClientAuth: clientAuth,
|
||||
CipherSuites: cipherSuites,
|
||||
SessionTicketsDisabled: true,
|
||||
MinVersion: minVersion,
|
||||
MaxVersion: maxVersion,
|
||||
NextProtos: []string{h2},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func getCipherSuites(tlsConfigCipherSuites []commonpb.Ciphersuite) []uint16 {
|
||||
var tlsGoCipherSuites []uint16
|
||||
for _, v := range tlsConfigCipherSuites {
|
||||
s := getTLSCipherSuite(v)
|
||||
if s != 0xffff {
|
||||
tlsGoCipherSuites = append(tlsGoCipherSuites, s)
|
||||
}
|
||||
}
|
||||
return tlsGoCipherSuites
|
||||
}
|
||||
|
||||
func getTLSCipherSuite(tlsCipherSuite commonpb.Ciphersuite) uint16 {
|
||||
switch tlsCipherSuite {
|
||||
case commonpb.Ciphersuite_CIPHERSUITE_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
|
||||
return tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
case commonpb.Ciphersuite_CIPHERSUITE_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
|
||||
return tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
|
||||
case commonpb.Ciphersuite_CIPHERSUITE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
|
||||
return tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
|
||||
case commonpb.Ciphersuite_CIPHERSUITE_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
|
||||
return tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
case commonpb.Ciphersuite_CIPHERSUITE_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
|
||||
return tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
case commonpb.Ciphersuite_CIPHERSUITE_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
|
||||
return tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
|
||||
default:
|
||||
return 0xffff
|
||||
}
|
||||
}
|
||||
|
||||
func getServerConfigFromS2Av2(tokenManager tokenmanager.AccessTokenManager, localIdentities []*commonpbv1.Identity, sni string, cstream s2av2pb.S2AService_SetUpSessionClient) (*s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration, error) {
|
||||
authMechanisms := getAuthMechanisms(tokenManager, localIdentities)
|
||||
var locID *commonpbv1.Identity
|
||||
if localIdentities != nil {
|
||||
locID = localIdentities[0]
|
||||
}
|
||||
|
||||
if err := cstream.Send(&s2av2pb.SessionReq{
|
||||
LocalIdentity: locID,
|
||||
AuthenticationMechanisms: authMechanisms,
|
||||
ReqOneof: &s2av2pb.SessionReq_GetTlsConfigurationReq{
|
||||
GetTlsConfigurationReq: &s2av2pb.GetTlsConfigurationReq{
|
||||
ConnectionSide: commonpb.ConnectionSide_CONNECTION_SIDE_SERVER,
|
||||
Sni: sni,
|
||||
},
|
||||
},
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := cstream.Recv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(rmehta19): Add unit test for this if statement.
|
||||
if (resp.GetStatus() != nil) && (resp.GetStatus().Code != uint32(codes.OK)) {
|
||||
return nil, fmt.Errorf("failed to get TLS configuration from S2A: %d, %v", resp.GetStatus().Code, resp.GetStatus().Details)
|
||||
}
|
||||
|
||||
return resp.GetGetTlsConfigurationResp().GetServerTlsConfiguration(), nil
|
||||
}
|
||||
|
||||
func getTLSClientAuthType(tlsConfig *s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration) tls.ClientAuthType {
|
||||
var clientAuth tls.ClientAuthType
|
||||
switch x := tlsConfig.RequestClientCertificate; x {
|
||||
case s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration_DONT_REQUEST_CLIENT_CERTIFICATE:
|
||||
clientAuth = tls.NoClientCert
|
||||
case s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
|
||||
clientAuth = tls.RequestClientCert
|
||||
case s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY:
|
||||
// This case actually maps to tls.VerifyClientCertIfGiven. However this
|
||||
// mapping triggers normal verification, followed by custom verification,
|
||||
// specified in VerifyPeerCertificate. To bypass normal verification, and
|
||||
// only do custom verification we set clientAuth to RequireAnyClientCert or
|
||||
// RequestClientCert. See https://github.com/google/s2a-go/pull/43 for full
|
||||
// discussion.
|
||||
clientAuth = tls.RequireAnyClientCert
|
||||
case s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
|
||||
clientAuth = tls.RequireAnyClientCert
|
||||
case s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY:
|
||||
// This case actually maps to tls.RequireAndVerifyClientCert. However this
|
||||
// mapping triggers normal verification, followed by custom verification,
|
||||
// specified in VerifyPeerCertificate. To bypass normal verification, and
|
||||
// only do custom verification we set clientAuth to RequireAnyClientCert or
|
||||
// RequestClientCert. See https://github.com/google/s2a-go/pull/43 for full
|
||||
// discussion.
|
||||
clientAuth = tls.RequireAnyClientCert
|
||||
default:
|
||||
clientAuth = tls.RequireAnyClientCert
|
||||
}
|
||||
return clientAuth
|
||||
}
|
||||
|
||||
func getAuthMechanisms(tokenManager tokenmanager.AccessTokenManager, localIdentities []*commonpbv1.Identity) []*s2av2pb.AuthenticationMechanism {
|
||||
if tokenManager == nil {
|
||||
return nil
|
||||
}
|
||||
if len(localIdentities) == 0 {
|
||||
token, err := tokenManager.DefaultToken()
|
||||
if err != nil {
|
||||
grpclog.Infof("Unable to get token for empty local identity: %v", err)
|
||||
return nil
|
||||
}
|
||||
return []*s2av2pb.AuthenticationMechanism{
|
||||
{
|
||||
MechanismOneof: &s2av2pb.AuthenticationMechanism_Token{
|
||||
Token: token,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
var authMechanisms []*s2av2pb.AuthenticationMechanism
|
||||
for _, localIdentity := range localIdentities {
|
||||
if localIdentity == nil {
|
||||
token, err := tokenManager.DefaultToken()
|
||||
if err != nil {
|
||||
grpclog.Infof("Unable to get default token for local identity %v: %v", localIdentity, err)
|
||||
continue
|
||||
}
|
||||
authMechanisms = append(authMechanisms, &s2av2pb.AuthenticationMechanism{
|
||||
Identity: localIdentity,
|
||||
MechanismOneof: &s2av2pb.AuthenticationMechanism_Token{
|
||||
Token: token,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
token, err := tokenManager.Token(localIdentity)
|
||||
if err != nil {
|
||||
grpclog.Infof("Unable to get token for local identity %v: %v", localIdentity, err)
|
||||
continue
|
||||
}
|
||||
authMechanisms = append(authMechanisms, &s2av2pb.AuthenticationMechanism{
|
||||
Identity: localIdentity,
|
||||
MechanismOneof: &s2av2pb.AuthenticationMechanism_Token{
|
||||
Token: token,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
return authMechanisms
|
||||
}
|
||||
|
||||
// TODO(rmehta19): refactor switch statements into a helper function.
|
||||
func getTLSMinMaxVersionsClient(tlsConfig *s2av2pb.GetTlsConfigurationResp_ClientTlsConfiguration) (uint16, uint16, error) {
|
||||
// Map S2Av2 TLSVersion to consts defined in tls package.
|
||||
var minVersion uint16
|
||||
var maxVersion uint16
|
||||
switch x := tlsConfig.MinTlsVersion; x {
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_0:
|
||||
minVersion = tls.VersionTLS10
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_1:
|
||||
minVersion = tls.VersionTLS11
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_2:
|
||||
minVersion = tls.VersionTLS12
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_3:
|
||||
minVersion = tls.VersionTLS13
|
||||
default:
|
||||
return minVersion, maxVersion, fmt.Errorf("S2Av2 provided invalid MinTlsVersion: %v", x)
|
||||
}
|
||||
|
||||
switch x := tlsConfig.MaxTlsVersion; x {
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_0:
|
||||
maxVersion = tls.VersionTLS10
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_1:
|
||||
maxVersion = tls.VersionTLS11
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_2:
|
||||
maxVersion = tls.VersionTLS12
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_3:
|
||||
maxVersion = tls.VersionTLS13
|
||||
default:
|
||||
return minVersion, maxVersion, fmt.Errorf("S2Av2 provided invalid MaxTlsVersion: %v", x)
|
||||
}
|
||||
if minVersion > maxVersion {
|
||||
return minVersion, maxVersion, errors.New("S2Av2 provided minVersion > maxVersion")
|
||||
}
|
||||
return minVersion, maxVersion, nil
|
||||
}
|
||||
|
||||
func getTLSMinMaxVersionsServer(tlsConfig *s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration) (uint16, uint16, error) {
|
||||
// Map S2Av2 TLSVersion to consts defined in tls package.
|
||||
var minVersion uint16
|
||||
var maxVersion uint16
|
||||
switch x := tlsConfig.MinTlsVersion; x {
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_0:
|
||||
minVersion = tls.VersionTLS10
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_1:
|
||||
minVersion = tls.VersionTLS11
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_2:
|
||||
minVersion = tls.VersionTLS12
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_3:
|
||||
minVersion = tls.VersionTLS13
|
||||
default:
|
||||
return minVersion, maxVersion, fmt.Errorf("S2Av2 provided invalid MinTlsVersion: %v", x)
|
||||
}
|
||||
|
||||
switch x := tlsConfig.MaxTlsVersion; x {
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_0:
|
||||
maxVersion = tls.VersionTLS10
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_1:
|
||||
maxVersion = tls.VersionTLS11
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_2:
|
||||
maxVersion = tls.VersionTLS12
|
||||
case commonpb.TLSVersion_TLS_VERSION_1_3:
|
||||
maxVersion = tls.VersionTLS13
|
||||
default:
|
||||
return minVersion, maxVersion, fmt.Errorf("S2Av2 provided invalid MaxTlsVersion: %v", x)
|
||||
}
|
||||
if minVersion > maxVersion {
|
||||
return minVersion, maxVersion, errors.New("S2Av2 provided minVersion > maxVersion")
|
||||
}
|
||||
return minVersion, maxVersion, nil
|
||||
}
|
||||
+409
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
// Package s2a provides the S2A transport credentials used by a gRPC
|
||||
// application.
|
||||
package s2a
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/google/s2a-go/fallback"
|
||||
"github.com/google/s2a-go/internal/handshaker"
|
||||
"github.com/google/s2a-go/internal/handshaker/service"
|
||||
"github.com/google/s2a-go/internal/tokenmanager"
|
||||
"github.com/google/s2a-go/internal/v2"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
|
||||
commonpb "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
s2av2pb "github.com/google/s2a-go/internal/proto/v2/s2a_go_proto"
|
||||
)
|
||||
|
||||
const (
|
||||
s2aSecurityProtocol = "tls"
|
||||
// defaultTimeout specifies the default server handshake timeout.
|
||||
defaultTimeout = 30.0 * time.Second
|
||||
)
|
||||
|
||||
// s2aTransportCreds are the transport credentials required for establishing
|
||||
// a secure connection using the S2A. They implement the
|
||||
// credentials.TransportCredentials interface.
|
||||
type s2aTransportCreds struct {
|
||||
info *credentials.ProtocolInfo
|
||||
minTLSVersion commonpb.TLSVersion
|
||||
maxTLSVersion commonpb.TLSVersion
|
||||
// tlsCiphersuites contains the ciphersuites used in the S2A connection.
|
||||
// Note that these are currently unconfigurable.
|
||||
tlsCiphersuites []commonpb.Ciphersuite
|
||||
// localIdentity should only be used by the client.
|
||||
localIdentity *commonpb.Identity
|
||||
// localIdentities should only be used by the server.
|
||||
localIdentities []*commonpb.Identity
|
||||
// targetIdentities should only be used by the client.
|
||||
targetIdentities []*commonpb.Identity
|
||||
isClient bool
|
||||
s2aAddr string
|
||||
ensureProcessSessionTickets *sync.WaitGroup
|
||||
}
|
||||
|
||||
// NewClientCreds returns a client-side transport credentials object that uses
|
||||
// the S2A to establish a secure connection with a server.
|
||||
func NewClientCreds(opts *ClientOptions) (credentials.TransportCredentials, error) {
|
||||
if opts == nil {
|
||||
return nil, errors.New("nil client options")
|
||||
}
|
||||
var targetIdentities []*commonpb.Identity
|
||||
for _, targetIdentity := range opts.TargetIdentities {
|
||||
protoTargetIdentity, err := toProtoIdentity(targetIdentity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
targetIdentities = append(targetIdentities, protoTargetIdentity)
|
||||
}
|
||||
localIdentity, err := toProtoIdentity(opts.LocalIdentity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if opts.EnableLegacyMode {
|
||||
return &s2aTransportCreds{
|
||||
info: &credentials.ProtocolInfo{
|
||||
SecurityProtocol: s2aSecurityProtocol,
|
||||
},
|
||||
minTLSVersion: commonpb.TLSVersion_TLS1_3,
|
||||
maxTLSVersion: commonpb.TLSVersion_TLS1_3,
|
||||
tlsCiphersuites: []commonpb.Ciphersuite{
|
||||
commonpb.Ciphersuite_AES_128_GCM_SHA256,
|
||||
commonpb.Ciphersuite_AES_256_GCM_SHA384,
|
||||
commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
|
||||
},
|
||||
localIdentity: localIdentity,
|
||||
targetIdentities: targetIdentities,
|
||||
isClient: true,
|
||||
s2aAddr: opts.S2AAddress,
|
||||
ensureProcessSessionTickets: opts.EnsureProcessSessionTickets,
|
||||
}, nil
|
||||
}
|
||||
verificationMode := getVerificationMode(opts.VerificationMode)
|
||||
var fallbackFunc fallback.ClientHandshake
|
||||
if opts.FallbackOpts != nil && opts.FallbackOpts.FallbackClientHandshakeFunc != nil {
|
||||
fallbackFunc = opts.FallbackOpts.FallbackClientHandshakeFunc
|
||||
}
|
||||
return v2.NewClientCreds(opts.S2AAddress, localIdentity, verificationMode, fallbackFunc)
|
||||
}
|
||||
|
||||
// NewServerCreds returns a server-side transport credentials object that uses
|
||||
// the S2A to establish a secure connection with a client.
|
||||
func NewServerCreds(opts *ServerOptions) (credentials.TransportCredentials, error) {
|
||||
if opts == nil {
|
||||
return nil, errors.New("nil server options")
|
||||
}
|
||||
var localIdentities []*commonpb.Identity
|
||||
for _, localIdentity := range opts.LocalIdentities {
|
||||
protoLocalIdentity, err := toProtoIdentity(localIdentity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localIdentities = append(localIdentities, protoLocalIdentity)
|
||||
}
|
||||
if opts.EnableLegacyMode {
|
||||
return &s2aTransportCreds{
|
||||
info: &credentials.ProtocolInfo{
|
||||
SecurityProtocol: s2aSecurityProtocol,
|
||||
},
|
||||
minTLSVersion: commonpb.TLSVersion_TLS1_3,
|
||||
maxTLSVersion: commonpb.TLSVersion_TLS1_3,
|
||||
tlsCiphersuites: []commonpb.Ciphersuite{
|
||||
commonpb.Ciphersuite_AES_128_GCM_SHA256,
|
||||
commonpb.Ciphersuite_AES_256_GCM_SHA384,
|
||||
commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
|
||||
},
|
||||
localIdentities: localIdentities,
|
||||
isClient: false,
|
||||
s2aAddr: opts.S2AAddress,
|
||||
}, nil
|
||||
}
|
||||
verificationMode := getVerificationMode(opts.VerificationMode)
|
||||
return v2.NewServerCreds(opts.S2AAddress, localIdentities, verificationMode)
|
||||
}
|
||||
|
||||
// ClientHandshake initiates a client-side TLS handshake using the S2A.
|
||||
func (c *s2aTransportCreds) ClientHandshake(ctx context.Context, serverAuthority string, rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
|
||||
if !c.isClient {
|
||||
return nil, nil, errors.New("client handshake called using server transport credentials")
|
||||
}
|
||||
|
||||
// Connect to the S2A.
|
||||
hsConn, err := service.Dial(c.s2aAddr)
|
||||
if err != nil {
|
||||
grpclog.Infof("Failed to connect to S2A: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
opts := &handshaker.ClientHandshakerOptions{
|
||||
MinTLSVersion: c.minTLSVersion,
|
||||
MaxTLSVersion: c.maxTLSVersion,
|
||||
TLSCiphersuites: c.tlsCiphersuites,
|
||||
TargetIdentities: c.targetIdentities,
|
||||
LocalIdentity: c.localIdentity,
|
||||
TargetName: serverAuthority,
|
||||
EnsureProcessSessionTickets: c.ensureProcessSessionTickets,
|
||||
}
|
||||
chs, err := handshaker.NewClientHandshaker(ctx, hsConn, rawConn, c.s2aAddr, opts)
|
||||
if err != nil {
|
||||
grpclog.Infof("Call to handshaker.NewClientHandshaker failed: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if closeErr := chs.Close(); closeErr != nil {
|
||||
grpclog.Infof("Close failed unexpectedly: %v", err)
|
||||
err = fmt.Errorf("%v: close unexpectedly failed: %v", err, closeErr)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
secConn, authInfo, err := chs.ClientHandshake(context.Background())
|
||||
if err != nil {
|
||||
grpclog.Infof("Handshake failed: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
return secConn, authInfo, nil
|
||||
}
|
||||
|
||||
// ServerHandshake initiates a server-side TLS handshake using the S2A.
|
||||
func (c *s2aTransportCreds) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
|
||||
if c.isClient {
|
||||
return nil, nil, errors.New("server handshake called using client transport credentials")
|
||||
}
|
||||
|
||||
// Connect to the S2A.
|
||||
hsConn, err := service.Dial(c.s2aAddr)
|
||||
if err != nil {
|
||||
grpclog.Infof("Failed to connect to S2A: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
|
||||
defer cancel()
|
||||
|
||||
opts := &handshaker.ServerHandshakerOptions{
|
||||
MinTLSVersion: c.minTLSVersion,
|
||||
MaxTLSVersion: c.maxTLSVersion,
|
||||
TLSCiphersuites: c.tlsCiphersuites,
|
||||
LocalIdentities: c.localIdentities,
|
||||
}
|
||||
shs, err := handshaker.NewServerHandshaker(ctx, hsConn, rawConn, c.s2aAddr, opts)
|
||||
if err != nil {
|
||||
grpclog.Infof("Call to handshaker.NewServerHandshaker failed: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if closeErr := shs.Close(); closeErr != nil {
|
||||
grpclog.Infof("Close failed unexpectedly: %v", err)
|
||||
err = fmt.Errorf("%v: close unexpectedly failed: %v", err, closeErr)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
secConn, authInfo, err := shs.ServerHandshake(context.Background())
|
||||
if err != nil {
|
||||
grpclog.Infof("Handshake failed: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
return secConn, authInfo, nil
|
||||
}
|
||||
|
||||
func (c *s2aTransportCreds) Info() credentials.ProtocolInfo {
|
||||
return *c.info
|
||||
}
|
||||
|
||||
func (c *s2aTransportCreds) Clone() credentials.TransportCredentials {
|
||||
info := *c.info
|
||||
var localIdentity *commonpb.Identity
|
||||
if c.localIdentity != nil {
|
||||
localIdentity = proto.Clone(c.localIdentity).(*commonpb.Identity)
|
||||
}
|
||||
var localIdentities []*commonpb.Identity
|
||||
if c.localIdentities != nil {
|
||||
localIdentities = make([]*commonpb.Identity, len(c.localIdentities))
|
||||
for i, localIdentity := range c.localIdentities {
|
||||
localIdentities[i] = proto.Clone(localIdentity).(*commonpb.Identity)
|
||||
}
|
||||
}
|
||||
var targetIdentities []*commonpb.Identity
|
||||
if c.targetIdentities != nil {
|
||||
targetIdentities = make([]*commonpb.Identity, len(c.targetIdentities))
|
||||
for i, targetIdentity := range c.targetIdentities {
|
||||
targetIdentities[i] = proto.Clone(targetIdentity).(*commonpb.Identity)
|
||||
}
|
||||
}
|
||||
return &s2aTransportCreds{
|
||||
info: &info,
|
||||
minTLSVersion: c.minTLSVersion,
|
||||
maxTLSVersion: c.maxTLSVersion,
|
||||
tlsCiphersuites: c.tlsCiphersuites,
|
||||
localIdentity: localIdentity,
|
||||
localIdentities: localIdentities,
|
||||
targetIdentities: targetIdentities,
|
||||
isClient: c.isClient,
|
||||
s2aAddr: c.s2aAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *s2aTransportCreds) OverrideServerName(serverNameOverride string) error {
|
||||
c.info.ServerName = serverNameOverride
|
||||
return nil
|
||||
}
|
||||
|
||||
// TLSClientConfigOptions specifies parameters for creating client TLS config.
|
||||
type TLSClientConfigOptions struct {
|
||||
// ServerName is required by s2a as the expected name when verifying the hostname found in server's certificate.
|
||||
// tlsConfig, _ := factory.Build(ctx, &s2a.TLSClientConfigOptions{
|
||||
// ServerName: "example.com",
|
||||
// })
|
||||
ServerName string
|
||||
}
|
||||
|
||||
// TLSClientConfigFactory defines the interface for a client TLS config factory.
|
||||
type TLSClientConfigFactory interface {
|
||||
Build(ctx context.Context, opts *TLSClientConfigOptions) (*tls.Config, error)
|
||||
}
|
||||
|
||||
// NewTLSClientConfigFactory returns an instance of s2aTLSClientConfigFactory.
|
||||
func NewTLSClientConfigFactory(opts *ClientOptions) (TLSClientConfigFactory, error) {
|
||||
if opts == nil {
|
||||
return nil, fmt.Errorf("opts must be non-nil")
|
||||
}
|
||||
if opts.EnableLegacyMode {
|
||||
return nil, fmt.Errorf("NewTLSClientConfigFactory only supports S2Av2")
|
||||
}
|
||||
tokenManager, err := tokenmanager.NewSingleTokenAccessTokenManager()
|
||||
if err != nil {
|
||||
// The only possible error is: access token not set in the environment,
|
||||
// which is okay in environments other than serverless.
|
||||
grpclog.Infof("Access token manager not initialized: %v", err)
|
||||
return &s2aTLSClientConfigFactory{
|
||||
s2av2Address: opts.S2AAddress,
|
||||
tokenManager: nil,
|
||||
verificationMode: getVerificationMode(opts.VerificationMode),
|
||||
}, nil
|
||||
}
|
||||
return &s2aTLSClientConfigFactory{
|
||||
s2av2Address: opts.S2AAddress,
|
||||
tokenManager: tokenManager,
|
||||
verificationMode: getVerificationMode(opts.VerificationMode),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type s2aTLSClientConfigFactory struct {
|
||||
s2av2Address string
|
||||
tokenManager tokenmanager.AccessTokenManager
|
||||
verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode
|
||||
}
|
||||
|
||||
func (f *s2aTLSClientConfigFactory) Build(
|
||||
ctx context.Context, opts *TLSClientConfigOptions) (*tls.Config, error) {
|
||||
serverName := ""
|
||||
if opts != nil && opts.ServerName != "" {
|
||||
serverName = opts.ServerName
|
||||
}
|
||||
return v2.NewClientTLSConfig(ctx, f.s2av2Address, f.tokenManager, f.verificationMode, serverName)
|
||||
}
|
||||
|
||||
func getVerificationMode(verificationMode VerificationModeType) s2av2pb.ValidatePeerCertificateChainReq_VerificationMode {
|
||||
switch verificationMode {
|
||||
case ConnectToGoogle:
|
||||
return s2av2pb.ValidatePeerCertificateChainReq_CONNECT_TO_GOOGLE
|
||||
case Spiffe:
|
||||
return s2av2pb.ValidatePeerCertificateChainReq_SPIFFE
|
||||
default:
|
||||
return s2av2pb.ValidatePeerCertificateChainReq_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
// NewS2ADialTLSContextFunc returns a dialer which establishes an MTLS connection using S2A.
|
||||
// Example use with http.RoundTripper:
|
||||
//
|
||||
// dialTLSContext := s2a.NewS2aDialTLSContextFunc(&s2a.ClientOptions{
|
||||
// S2AAddress: s2aAddress, // required
|
||||
// })
|
||||
// transport := http.DefaultTransport
|
||||
// transport.DialTLSContext = dialTLSContext
|
||||
func NewS2ADialTLSContextFunc(opts *ClientOptions) func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
|
||||
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
|
||||
fallback := func(err error) (net.Conn, error) {
|
||||
if opts.FallbackOpts != nil && opts.FallbackOpts.FallbackDialer != nil &&
|
||||
opts.FallbackOpts.FallbackDialer.Dialer != nil && opts.FallbackOpts.FallbackDialer.ServerAddr != "" {
|
||||
fbDialer := opts.FallbackOpts.FallbackDialer
|
||||
grpclog.Infof("fall back to dial: %s", fbDialer.ServerAddr)
|
||||
fbConn, fbErr := fbDialer.Dialer.DialContext(ctx, network, fbDialer.ServerAddr)
|
||||
if fbErr != nil {
|
||||
return nil, fmt.Errorf("error fallback to %s: %v; S2A error: %w", fbDialer.ServerAddr, fbErr, err)
|
||||
}
|
||||
return fbConn, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
factory, err := NewTLSClientConfigFactory(opts)
|
||||
if err != nil {
|
||||
grpclog.Infof("error creating S2A client config factory: %v", err)
|
||||
return fallback(err)
|
||||
}
|
||||
|
||||
serverName, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
serverName = addr
|
||||
}
|
||||
timeoutCtx, cancel := context.WithTimeout(ctx, *v2.S2ATimeout)
|
||||
defer cancel()
|
||||
s2aTLSConfig, err := factory.Build(timeoutCtx, &TLSClientConfigOptions{
|
||||
ServerName: serverName,
|
||||
})
|
||||
if err != nil {
|
||||
grpclog.Infof("error building S2A TLS config: %v", err)
|
||||
return fallback(err)
|
||||
}
|
||||
|
||||
s2aDialer := &tls.Dialer{
|
||||
Config: s2aTLSConfig,
|
||||
}
|
||||
c, err := s2aDialer.DialContext(ctx, network, addr)
|
||||
if err != nil {
|
||||
grpclog.Infof("error dialing with S2A to %s: %v", addr, err)
|
||||
return fallback(err)
|
||||
}
|
||||
grpclog.Infof("success dialing MTLS to %s with S2A", addr)
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package s2a
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/google/s2a-go/fallback"
|
||||
|
||||
s2apb "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
)
|
||||
|
||||
// Identity is the interface for S2A identities.
|
||||
type Identity interface {
|
||||
// Name returns the name of the identity.
|
||||
Name() string
|
||||
}
|
||||
|
||||
type spiffeID struct {
|
||||
spiffeID string
|
||||
}
|
||||
|
||||
func (s *spiffeID) Name() string { return s.spiffeID }
|
||||
|
||||
// NewSpiffeID creates a SPIFFE ID from id.
|
||||
func NewSpiffeID(id string) Identity {
|
||||
return &spiffeID{spiffeID: id}
|
||||
}
|
||||
|
||||
type hostname struct {
|
||||
hostname string
|
||||
}
|
||||
|
||||
func (h *hostname) Name() string { return h.hostname }
|
||||
|
||||
// NewHostname creates a hostname from name.
|
||||
func NewHostname(name string) Identity {
|
||||
return &hostname{hostname: name}
|
||||
}
|
||||
|
||||
type uid struct {
|
||||
uid string
|
||||
}
|
||||
|
||||
func (h *uid) Name() string { return h.uid }
|
||||
|
||||
// NewUID creates a UID from name.
|
||||
func NewUID(name string) Identity {
|
||||
return &uid{uid: name}
|
||||
}
|
||||
|
||||
// VerificationModeType specifies the mode that S2A must use to verify the peer
|
||||
// certificate chain.
|
||||
type VerificationModeType int
|
||||
|
||||
// Three types of verification modes.
|
||||
const (
|
||||
Unspecified = iota
|
||||
ConnectToGoogle
|
||||
Spiffe
|
||||
)
|
||||
|
||||
// ClientOptions contains the client-side options used to establish a secure
|
||||
// channel using the S2A handshaker service.
|
||||
type ClientOptions struct {
|
||||
// TargetIdentities contains a list of allowed server identities. One of the
|
||||
// target identities should match the peer identity in the handshake
|
||||
// result; otherwise, the handshake fails.
|
||||
TargetIdentities []Identity
|
||||
// LocalIdentity is the local identity of the client application. If none is
|
||||
// provided, then the S2A will choose the default identity, if one exists.
|
||||
LocalIdentity Identity
|
||||
// S2AAddress is the address of the S2A.
|
||||
S2AAddress string
|
||||
// EnsureProcessSessionTickets waits for all session tickets to be sent to
|
||||
// S2A before a process completes.
|
||||
//
|
||||
// This functionality is crucial for processes that complete very soon after
|
||||
// using S2A to establish a TLS connection, but it can be ignored for longer
|
||||
// lived processes.
|
||||
//
|
||||
// Usage example:
|
||||
// func main() {
|
||||
// var ensureProcessSessionTickets sync.WaitGroup
|
||||
// clientOpts := &s2a.ClientOptions{
|
||||
// EnsureProcessSessionTickets: &ensureProcessSessionTickets,
|
||||
// // Set other members.
|
||||
// }
|
||||
// creds, _ := s2a.NewClientCreds(clientOpts)
|
||||
// conn, _ := grpc.Dial(serverAddr, grpc.WithTransportCredentials(creds))
|
||||
// defer conn.Close()
|
||||
//
|
||||
// // Make RPC call.
|
||||
//
|
||||
// // The process terminates right after the RPC call ends.
|
||||
// // ensureProcessSessionTickets can be used to ensure resumption
|
||||
// // tickets are fully processed. If the process is long-lived, using
|
||||
// // ensureProcessSessionTickets is not necessary.
|
||||
// ensureProcessSessionTickets.Wait()
|
||||
// }
|
||||
EnsureProcessSessionTickets *sync.WaitGroup
|
||||
// If true, enables the use of legacy S2Av1.
|
||||
EnableLegacyMode bool
|
||||
// VerificationMode specifies the mode that S2A must use to verify the
|
||||
// peer certificate chain.
|
||||
VerificationMode VerificationModeType
|
||||
|
||||
// Optional fallback after dialing with S2A fails.
|
||||
FallbackOpts *FallbackOptions
|
||||
}
|
||||
|
||||
// FallbackOptions prescribes the fallback logic that should be taken if the application fails to connect with S2A.
|
||||
type FallbackOptions struct {
|
||||
// FallbackClientHandshakeFunc is used to specify fallback behavior when calling s2a.NewClientCreds().
|
||||
// It will be called by ClientHandshake function, after handshake with S2A fails.
|
||||
// s2a.NewClientCreds() ignores the other FallbackDialer field.
|
||||
FallbackClientHandshakeFunc fallback.ClientHandshake
|
||||
|
||||
// FallbackDialer is used to specify fallback behavior when calling s2a.NewS2aDialTLSContextFunc().
|
||||
// It passes in a custom fallback dialer and server address to use after dialing with S2A fails.
|
||||
// s2a.NewS2aDialTLSContextFunc() ignores the other FallbackClientHandshakeFunc field.
|
||||
FallbackDialer *FallbackDialer
|
||||
}
|
||||
|
||||
// FallbackDialer contains a fallback tls.Dialer and a server address to connect to.
|
||||
type FallbackDialer struct {
|
||||
// Dialer specifies a fallback tls.Dialer.
|
||||
Dialer *tls.Dialer
|
||||
// ServerAddr is used by Dialer to establish fallback connection.
|
||||
ServerAddr string
|
||||
}
|
||||
|
||||
// DefaultClientOptions returns the default client options.
|
||||
func DefaultClientOptions(s2aAddress string) *ClientOptions {
|
||||
return &ClientOptions{
|
||||
S2AAddress: s2aAddress,
|
||||
VerificationMode: ConnectToGoogle,
|
||||
}
|
||||
}
|
||||
|
||||
// ServerOptions contains the server-side options used to establish a secure
|
||||
// channel using the S2A handshaker service.
|
||||
type ServerOptions struct {
|
||||
// LocalIdentities is the list of local identities that may be assumed by
|
||||
// the server. If no local identity is specified, then the S2A chooses a
|
||||
// default local identity, if one exists.
|
||||
LocalIdentities []Identity
|
||||
// S2AAddress is the address of the S2A.
|
||||
S2AAddress string
|
||||
// If true, enables the use of legacy S2Av1.
|
||||
EnableLegacyMode bool
|
||||
// VerificationMode specifies the mode that S2A must use to verify the
|
||||
// peer certificate chain.
|
||||
VerificationMode VerificationModeType
|
||||
}
|
||||
|
||||
// DefaultServerOptions returns the default server options.
|
||||
func DefaultServerOptions(s2aAddress string) *ServerOptions {
|
||||
return &ServerOptions{
|
||||
S2AAddress: s2aAddress,
|
||||
VerificationMode: ConnectToGoogle,
|
||||
}
|
||||
}
|
||||
|
||||
func toProtoIdentity(identity Identity) (*s2apb.Identity, error) {
|
||||
if identity == nil {
|
||||
return nil, nil
|
||||
}
|
||||
switch id := identity.(type) {
|
||||
case *spiffeID:
|
||||
return &s2apb.Identity{IdentityOneof: &s2apb.Identity_SpiffeId{SpiffeId: id.Name()}}, nil
|
||||
case *hostname:
|
||||
return &s2apb.Identity{IdentityOneof: &s2apb.Identity_Hostname{Hostname: id.Name()}}, nil
|
||||
case *uid:
|
||||
return &s2apb.Identity{IdentityOneof: &s2apb.Identity_Uid{Uid: id.Name()}}, nil
|
||||
default:
|
||||
return nil, errors.New("unrecognized identity type")
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package s2a
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
commonpb "github.com/google/s2a-go/internal/proto/common_go_proto"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/peer"
|
||||
)
|
||||
|
||||
// AuthInfo exposes security information from the S2A to the application.
|
||||
type AuthInfo interface {
|
||||
// AuthType returns the authentication type.
|
||||
AuthType() string
|
||||
// ApplicationProtocol returns the application protocol, e.g. "grpc".
|
||||
ApplicationProtocol() string
|
||||
// TLSVersion returns the TLS version negotiated during the handshake.
|
||||
TLSVersion() commonpb.TLSVersion
|
||||
// Ciphersuite returns the ciphersuite negotiated during the handshake.
|
||||
Ciphersuite() commonpb.Ciphersuite
|
||||
// PeerIdentity returns the authenticated identity of the peer.
|
||||
PeerIdentity() *commonpb.Identity
|
||||
// LocalIdentity returns the local identity of the application used during
|
||||
// session setup.
|
||||
LocalIdentity() *commonpb.Identity
|
||||
// PeerCertFingerprint returns the SHA256 hash of the peer certificate used in
|
||||
// the S2A handshake.
|
||||
PeerCertFingerprint() []byte
|
||||
// LocalCertFingerprint returns the SHA256 hash of the local certificate used
|
||||
// in the S2A handshake.
|
||||
LocalCertFingerprint() []byte
|
||||
// IsHandshakeResumed returns true if a cached session was used to resume
|
||||
// the handshake.
|
||||
IsHandshakeResumed() bool
|
||||
// SecurityLevel returns the security level of the connection.
|
||||
SecurityLevel() credentials.SecurityLevel
|
||||
}
|
||||
|
||||
// AuthInfoFromPeer extracts the authinfo.S2AAuthInfo object from the given
|
||||
// peer, if it exists. This API should be used by gRPC clients after
|
||||
// obtaining a peer object using the grpc.Peer() CallOption.
|
||||
func AuthInfoFromPeer(p *peer.Peer) (AuthInfo, error) {
|
||||
s2aAuthInfo, ok := p.AuthInfo.(AuthInfo)
|
||||
if !ok {
|
||||
return nil, errors.New("no S2AAuthInfo found in Peer")
|
||||
}
|
||||
return s2aAuthInfo, nil
|
||||
}
|
||||
|
||||
// AuthInfoFromContext extracts the authinfo.S2AAuthInfo object from the given
|
||||
// context, if it exists. This API should be used by gRPC server RPC handlers
|
||||
// to get information about the peer. On the client-side, use the grpc.Peer()
|
||||
// CallOption and the AuthInfoFromPeer function.
|
||||
func AuthInfoFromContext(ctx context.Context) (AuthInfo, error) {
|
||||
p, ok := peer.FromContext(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New("no Peer found in Context")
|
||||
}
|
||||
return AuthInfoFromPeer(p)
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID8TCCAtmgAwIBAgIUKXNlBRVe6UepjQUijIFPZBd/4qYwDQYJKoZIhvcNAQEL
|
||||
BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2
|
||||
YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE
|
||||
AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN
|
||||
MjIwNTMxMjAwMzE1WhcNNDIwNTI2MjAwMzE1WjCBhzELMAkGA1UEBhMCVVMxCzAJ
|
||||
BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx
|
||||
ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ
|
||||
KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBAOOFuIucH7XXfohGxKd3uR/ihUA/LdduR9I8kfpUEbq5BOt8xZe5/Yn9
|
||||
a1ozEHVW6cOAbHbnwAR8tkSgZ/t42QIA2k77HWU1Jh2xiEIsJivo3imm4/kZWuR0
|
||||
OqPh7MhzxpR/hvNwpI5mJsAVBWFMa5KtecFZLnyZtwHylrRN1QXzuLrOxuKFufK3
|
||||
RKbTABScn5RbZL976H/jgfSeXrbt242NrIoBnVe6fRbekbq2DQ6zFArbQMUgHjHK
|
||||
P0UqBgdr1QmHfi9KytFyx9BTP3gXWnWIu+bY7/v7qKJMHFwGETo+dCLWYevJL316
|
||||
HnLfhApDMfP8U+Yv/y1N/YvgaSOSlEcCAwEAAaNTMFEwHQYDVR0OBBYEFKhAU4nu
|
||||
0h/lrnggbIGvx4ej0WklMB8GA1UdIwQYMBaAFKhAU4nu0h/lrnggbIGvx4ej0Wkl
|
||||
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAE/6NghzQ5fu6yR6
|
||||
EHKbj/YMrFdT7aGn5n2sAf7wJ33LIhiFHkpWBsVlm7rDtZtwhe891ZK/P60anlg9
|
||||
/P0Ua53tSRVRmCvTnEbXWOVMN4is6MsR7BlmzUxl4AtIn7jbeifEwRL7B4xDYmdA
|
||||
QrQnsqoz45dLgS5xK4WDqXATP09Q91xQDuhud/b+A4jrvgwFASmL7rMIZbp4f1JQ
|
||||
nlnl/9VoTBQBvJiWkDUtQDMpRLtauddEkv4AGz75p5IspXWD6cOemuh2iQec11xD
|
||||
X20rs2WZbAcAiUa3nmy8OKYw435vmpj8gp39WYbX/Yx9TymrFFbVY92wYn+quTco
|
||||
pKklVz0=
|
||||
-----END CERTIFICATE-----
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEA44W4i5wftdd+iEbEp3e5H+KFQD8t125H0jyR+lQRurkE63zF
|
||||
l7n9if1rWjMQdVbpw4BsdufABHy2RKBn+3jZAgDaTvsdZTUmHbGIQiwmK+jeKabj
|
||||
+Rla5HQ6o+HsyHPGlH+G83CkjmYmwBUFYUxrkq15wVkufJm3AfKWtE3VBfO4us7G
|
||||
4oW58rdEptMAFJyflFtkv3vof+OB9J5etu3bjY2sigGdV7p9Ft6RurYNDrMUCttA
|
||||
xSAeMco/RSoGB2vVCYd+L0rK0XLH0FM/eBdadYi75tjv+/uookwcXAYROj50ItZh
|
||||
68kvfXoect+ECkMx8/xT5i//LU39i+BpI5KURwIDAQABAoIBABgyjo/6iLzUMFbZ
|
||||
/+w3pW6orrdIgN2akvTfED9pVYFgUA+jc3hRhY95bkNnjuaL2cy7Cc4Tk65mfRQL
|
||||
Y0OxdJLr+EvSFSxAXM9npDA1ddHRsF8JqtFBSxNk8R+g1Yf0GDiO35Fgd3/ViWWA
|
||||
VtQkRoSRApP3oiQKTRZd8H04keFR+PvmDk/Lq11l3Kc24A1PevKIPX1oI990ggw9
|
||||
9i4uSV+cnuMxmcI9xxJtgwdDFdjr39l2arLOHr4s6LGoV2IOdXHNlv5xRqWUZ0FH
|
||||
MDHowkLgwDrdSTnNeaVNkce14Gqx+bd4hNaLCdKXMpedBTEmrut3f3hdV1kKjaKt
|
||||
aqRYr8ECgYEA/YDGZY2jvFoHHBywlqmEMFrrCvQGH51m5R1Ntpkzr+Rh3YCmrpvq
|
||||
xgwJXING0PUw3dz+xrH5lJICrfNE5Kt3fPu1rAEy+13mYsNowghtUq2Rtu0Hsjjx
|
||||
2E3Bf8vEB6RNBMmGkUpTTIAroGF5tpJoRvfnWax+k4pFdrKYFtyZdNcCgYEA5cNv
|
||||
EPltvOobjTXlUmtVP3n27KZN2aXexTcagLzRxE9CV4cYySENl3KuOMmccaZpIl6z
|
||||
aHk6BT4X+M0LqElNUczrInfVqI+SGAFLGy7W6CJaqSr6cpyFUP/fosKpm6wKGgLq
|
||||
udHfpvz5rckhKd8kJxFLvhGOK9yN5qpzih0gfhECgYAJfwRvk3G5wYmYpP58dlcs
|
||||
VIuPenqsPoI3PPTHTU/hW+XKnWIhElgmGRdUrto9Q6IT/Y5RtSMLTLjq+Tzwb/fm
|
||||
56rziYv2XJsfwgAvnI8z1Kqrto9ePsHYf3krJ1/thVsZPc9bq/QY3ohD1sLvcuaT
|
||||
GgBBnLOVJU3a12/ZE2RwOwKBgF0csWMAoj8/5IB6if+3ral2xOGsl7oPZVMo/J2V
|
||||
Z7EVqb4M6rd/pKFugTpUQgkwtkSOekhpcGD1hAN5HTNK2YG/+L5UMAsKe9sskwJm
|
||||
HgOfAHy0BSDzW3ey6i9skg2bT9Cww+0gJ3Hl7U1HSCBO5LjMYpSZSrNtwzfqdb5Q
|
||||
BX3xAoGARZdR28Ej3+/+0+fz47Yu2h4z0EI/EbrudLOWY936jIeAVwHckI3+BuqH
|
||||
qR4poj1gfbnMxNuI9UzIXzjEmGewx9kDZ7IYnvloZKqoVQODO5GlKF2ja6IcMNlh
|
||||
GCNdD6PSAS6HcmalmWo9sj+1YMkrl+GJikKZqVBHrHNwMGAG67w=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID8TCCAtmgAwIBAgIUKCoDuLtiZXvhsBY2RoDm0ugizJ8wDQYJKoZIhvcNAQEL
|
||||
BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2
|
||||
YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE
|
||||
AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN
|
||||
MjIwNTMxMjAwODI1WhcNNDIwNTI2MjAwODI1WjCBhzELMAkGA1UEBhMCVVMxCzAJ
|
||||
BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx
|
||||
ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ
|
||||
KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBAKK1++PXQ+M3hjYH/v0K4UEYl5ljzpNM1i52eQM+gFooojT87PDSaphT
|
||||
fs0PXy/PTAjHBEvPhWpOpmQXfJNYzjwcCvg66hbqkv++/VTZiFLAsHagzkEz+FRJ
|
||||
qT5Eq7G5FLyw1izX1uxyPN7tAEWEEg7eqsiaXD3Cq8+TYN9cjirPeF7RZF8yFCYE
|
||||
xqvbo+Yc6RL6xw19iXVTfctRgQe581KQuIY5/LXo3dWDEilFdsADAe8XAEcO64es
|
||||
Ow0g1UvXLnpXSE151kXBFb3sKH/ZjCecDYMCIMEb4sWLSblkSxJ5sNSmXIG4wtr2
|
||||
Qnii7CXZgnVYraQE/Jyh+NMQANuoSdMCAwEAAaNTMFEwHQYDVR0OBBYEFAyQQQuM
|
||||
ab+YUQqjK8dVVOoHVFmXMB8GA1UdIwQYMBaAFAyQQQuMab+YUQqjK8dVVOoHVFmX
|
||||
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADj0vQ6ykWhicoqR
|
||||
e6VZMwlEJV7/DSvWWKBd9MUjfKye0A4565ya5lmnzP3DiD3nqGe3miqmLsXKDs+X
|
||||
POqlPXTWIamP7D4MJ32XtSLwZB4ru+I+Ao/P/VngPepoRPQoBnzHe7jww0rokqxl
|
||||
AZERjlbTUwUAy/BPWPSzSJZ2j0tcs6ZLDNyYzpK4ao8R9/1VmQ92Tcp3feJs1QTg
|
||||
odRQc3om/AkWOwsll+oyX0UbJeHkFHiLanUPXbdh+/BkSvZJ8ynL+feSDdaurPe+
|
||||
PSfnqLtQft9/neecGRdEaQzzzSFVQUVQzTdK1Q7hA7b55b2HvIa3ktDiks+sJsYN
|
||||
Dhm6uZM=
|
||||
-----END CERTIFICATE-----
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAorX749dD4zeGNgf+/QrhQRiXmWPOk0zWLnZ5Az6AWiiiNPzs
|
||||
8NJqmFN+zQ9fL89MCMcES8+Fak6mZBd8k1jOPBwK+DrqFuqS/779VNmIUsCwdqDO
|
||||
QTP4VEmpPkSrsbkUvLDWLNfW7HI83u0ARYQSDt6qyJpcPcKrz5Ng31yOKs94XtFk
|
||||
XzIUJgTGq9uj5hzpEvrHDX2JdVN9y1GBB7nzUpC4hjn8tejd1YMSKUV2wAMB7xcA
|
||||
Rw7rh6w7DSDVS9cueldITXnWRcEVvewof9mMJ5wNgwIgwRvixYtJuWRLEnmw1KZc
|
||||
gbjC2vZCeKLsJdmCdVitpAT8nKH40xAA26hJ0wIDAQABAoIBACaNR+lsD8G+XiZf
|
||||
LqN1+HkcAo9tfnyYMAdCOtnx7SdviT9Uzi8hK/B7mAeuJLeHPlS2EuaDfPD7QaFl
|
||||
jza6S+MiIdc+3kgfvESsVAnOoOY6kZUJ9NSuI6CU82y1iJjLaYZrv9NQMLRFPPb0
|
||||
4KOX709mosB1EnXvshW0rbc+jtDFhrm1SxMt+k9TuzmMxjbOeW4LOLXPgU8X1T3Q
|
||||
Xy0hMZZtcgBs9wFIo8yCtmOixax9pnFE8rRltgDxTodn9LLdz1FieyntNgDksZ0P
|
||||
nt4kV7Mqly7ELaea+Foaj244mKsesic2e3GhAlMRLun/VSunSf7mOCxfpITB8dp1
|
||||
drDhOYECgYEA19151dVxRcviuovN6Dar+QszMTnU8pDJ8BjLFjXjP/hNBBwMTHDE
|
||||
duMuWk2qnwZqMooI/shxrF/ufmTgS0CFrh2+ANBZu27vWConJNXcyNtdigI4wt50
|
||||
L0Y2qcZn2mg67qFXHwoR3QNwrwnPwEjRXA09at9CSRZzcwDQ0ETXhYsCgYEAwPaG
|
||||
06QdK8Zyly7TTzZJwxzv9uGiqzodmGtX6NEKjgij2JaCxHpukqZBJoqa0jKeK1cm
|
||||
eNVkOvT5ff9TMzarSHQLr3pZen2/oVLb5gaFkbcJt/klv9Fd+ZRilHY3i6QwS6pD
|
||||
uMiPOWS4DrLHDRVoVlAZTDjT1RVwwTs+P2NhJdkCgYEAsriXysbxBYyMp05gqEW7
|
||||
lHIFbFgpSrs9th+Q5U6wW6JEgYaHWDJ1NslY80MiZI93FWjbkbZ7BvBWESeL3EIL
|
||||
a+EMErht0pVCbIhZ6FF4foPAqia0wAJVx14mm+G80kNBp5jE/NnleEsE3KcO7nBb
|
||||
hg8gLn+x7bk81JZ0TDrzBYkCgYEAuQKluv47SeF3tSScTfKLPpvcKCWmxe1uutkQ
|
||||
7JShPhVioyOMNb39jnYBOWbjkm4d4QgqRuiytSR0oi3QI+Ziy5EYMyNn713qAk9j
|
||||
r2TJZDDPDKnBW+zt4YI4EohWMXk3JRUW4XDKggjjwJQA7bZ812TtHHvP/xoThfG7
|
||||
eSNb3eECgYBw6ssgCtMrdvQiEmjKVX/9yI38mvC2kSGyzbrQnGUfgqRGomRpeZuD
|
||||
B5E3kysA4td5pT5lvcLgSW0TbOz+YbiriXjwOihPIelCvc9gE2eOUI71/byUWPFz
|
||||
7u5F/xQ4NaGr5suLF+lBC6h7pSbM4El9lIHQAQadpuEdzHqrw+hs3g==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"v2": "2.7.0"
|
||||
"v2": "2.8.0"
|
||||
}
|
||||
|
||||
+14
@@ -1,5 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
## [2.8.0](https://github.com/googleapis/gax-go/compare/v2.7.1...v2.8.0) (2023-03-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **v2:** add WithTimeout option ([#259](https://github.com/googleapis/gax-go/issues/259)) ([9a8da43](https://github.com/googleapis/gax-go/commit/9a8da43693002448b1e8758023699387481866d1))
|
||||
|
||||
## [2.7.1](https://github.com/googleapis/gax-go/compare/v2.7.0...v2.7.1) (2023-03-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **v2/apierror:** return Unknown GRPCStatus when err source is HTTP ([#260](https://github.com/googleapis/gax-go/issues/260)) ([043b734](https://github.com/googleapis/gax-go/commit/043b73437a240a91229207fb3ee52a9935a36f23)), refs [#254](https://github.com/googleapis/gax-go/issues/254)
|
||||
|
||||
## [2.7.0](https://github.com/googleapis/gax-go/compare/v2.6.0...v2.7.0) (2022-11-02)
|
||||
|
||||
|
||||
|
||||
+8
-3
@@ -39,6 +39,7 @@ import (
|
||||
jsonerror "github.com/googleapis/gax-go/v2/apierror/internal/proto"
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/genproto/googleapis/rpc/errdetails"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -197,12 +198,12 @@ func (a *APIError) Unwrap() error {
|
||||
// Error returns a readable representation of the APIError.
|
||||
func (a *APIError) Error() string {
|
||||
var msg string
|
||||
if a.status != nil {
|
||||
msg = a.err.Error()
|
||||
} else if a.httpErr != nil {
|
||||
if a.httpErr != nil {
|
||||
// Truncate the googleapi.Error message because it dumps the Details in
|
||||
// an ugly way.
|
||||
msg = fmt.Sprintf("googleapi: Error %d: %s", a.httpErr.Code, a.httpErr.Message)
|
||||
} else if a.status != nil {
|
||||
msg = a.err.Error()
|
||||
}
|
||||
return strings.TrimSpace(fmt.Sprintf("%s\n%s", msg, a.details))
|
||||
}
|
||||
@@ -236,6 +237,9 @@ func (a *APIError) Metadata() map[string]string {
|
||||
// setDetailsFromError parses a Status error or a googleapi.Error
|
||||
// and sets status and details or httpErr and details, respectively.
|
||||
// It returns false if neither Status nor googleapi.Error can be parsed.
|
||||
// When err is a googleapi.Error, the status of the returned error will
|
||||
// be set to an Unknown error, rather than nil, since a nil code is
|
||||
// interpreted as OK in the gRPC status package.
|
||||
func (a *APIError) setDetailsFromError(err error) bool {
|
||||
st, isStatus := status.FromError(err)
|
||||
var herr *googleapi.Error
|
||||
@@ -248,6 +252,7 @@ func (a *APIError) setDetailsFromError(err error) bool {
|
||||
case isHTTPErr:
|
||||
a.httpErr = herr
|
||||
a.details = parseHTTPDetails(herr)
|
||||
a.status = status.New(codes.Unknown, herr.Message)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
+21
@@ -218,6 +218,14 @@ func (p pathOpt) Resolve(s *CallSettings) {
|
||||
s.Path = p.p
|
||||
}
|
||||
|
||||
type timeoutOpt struct {
|
||||
t time.Duration
|
||||
}
|
||||
|
||||
func (t timeoutOpt) Resolve(s *CallSettings) {
|
||||
s.timeout = t.t
|
||||
}
|
||||
|
||||
// WithPath applies a Path override to the HTTP-based APICall.
|
||||
//
|
||||
// This is for internal use only.
|
||||
@@ -230,6 +238,15 @@ func WithGRPCOptions(opt ...grpc.CallOption) CallOption {
|
||||
return grpcOpt(append([]grpc.CallOption(nil), opt...))
|
||||
}
|
||||
|
||||
// WithTimeout is a convenience option for setting a context.WithTimeout on the
|
||||
// singular context.Context used for **all** APICall attempts. Calculated from
|
||||
// the start of the first APICall attempt.
|
||||
// If the context.Context provided to Invoke already has a Deadline set, that
|
||||
// will always be respected over the deadline calculated using this option.
|
||||
func WithTimeout(t time.Duration) CallOption {
|
||||
return &timeoutOpt{t: t}
|
||||
}
|
||||
|
||||
// CallSettings allow fine-grained control over how calls are made.
|
||||
type CallSettings struct {
|
||||
// Retry returns a Retryer to be used to control retry logic of a method call.
|
||||
@@ -241,4 +258,8 @@ type CallSettings struct {
|
||||
|
||||
// Path is an HTTP override for an APICall.
|
||||
Path string
|
||||
|
||||
// Timeout defines the amount of time that Invoke has to complete.
|
||||
// Unexported so it cannot be changed by the code in an APICall.
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
+1
-1
@@ -30,4 +30,4 @@
|
||||
package internal
|
||||
|
||||
// Version is the current tagged release of the library.
|
||||
const Version = "2.7.0"
|
||||
const Version = "2.8.0"
|
||||
|
||||
+10
@@ -68,6 +68,16 @@ type sleeper func(ctx context.Context, d time.Duration) error
|
||||
// invoke implements Invoke, taking an additional sleeper argument for testing.
|
||||
func invoke(ctx context.Context, call APICall, settings CallSettings, sp sleeper) error {
|
||||
var retryer Retryer
|
||||
|
||||
// Only use the value provided via WithTimeout if the context doesn't
|
||||
// already have a deadline. This is important for backwards compatibility if
|
||||
// the user already set a deadline on the context given to Invoke.
|
||||
if _, ok := ctx.Deadline(); !ok && settings.timeout != 0 {
|
||||
c, cc := context.WithTimeout(ctx, settings.timeout)
|
||||
defer cc()
|
||||
ctx = c
|
||||
}
|
||||
|
||||
for {
|
||||
err := call(ctx, settings)
|
||||
if err == nil {
|
||||
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD and its
|
||||
// extended nonce variant XChaCha20-Poly1305, as specified in RFC 8439 and
|
||||
// draft-irtf-cfrg-xchacha-01.
|
||||
package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305"
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// KeySize is the size of the key used by this AEAD, in bytes.
|
||||
KeySize = 32
|
||||
|
||||
// NonceSize is the size of the nonce used with the standard variant of this
|
||||
// AEAD, in bytes.
|
||||
//
|
||||
// Note that this is too short to be safely generated at random if the same
|
||||
// key is reused more than 2³² times.
|
||||
NonceSize = 12
|
||||
|
||||
// NonceSizeX is the size of the nonce used with the XChaCha20-Poly1305
|
||||
// variant of this AEAD, in bytes.
|
||||
NonceSizeX = 24
|
||||
|
||||
// Overhead is the size of the Poly1305 authentication tag, and the
|
||||
// difference between a ciphertext length and its plaintext.
|
||||
Overhead = 16
|
||||
)
|
||||
|
||||
type chacha20poly1305 struct {
|
||||
key [KeySize]byte
|
||||
}
|
||||
|
||||
// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key.
|
||||
func New(key []byte) (cipher.AEAD, error) {
|
||||
if len(key) != KeySize {
|
||||
return nil, errors.New("chacha20poly1305: bad key length")
|
||||
}
|
||||
ret := new(chacha20poly1305)
|
||||
copy(ret.key[:], key)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) NonceSize() int {
|
||||
return NonceSize
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) Overhead() int {
|
||||
return Overhead
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
if len(nonce) != NonceSize {
|
||||
panic("chacha20poly1305: bad nonce length passed to Seal")
|
||||
}
|
||||
|
||||
if uint64(len(plaintext)) > (1<<38)-64 {
|
||||
panic("chacha20poly1305: plaintext too large")
|
||||
}
|
||||
|
||||
return c.seal(dst, nonce, plaintext, additionalData)
|
||||
}
|
||||
|
||||
var errOpen = errors.New("chacha20poly1305: message authentication failed")
|
||||
|
||||
func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
if len(nonce) != NonceSize {
|
||||
panic("chacha20poly1305: bad nonce length passed to Open")
|
||||
}
|
||||
if len(ciphertext) < 16 {
|
||||
return nil, errOpen
|
||||
}
|
||||
if uint64(len(ciphertext)) > (1<<38)-48 {
|
||||
panic("chacha20poly1305: ciphertext too large")
|
||||
}
|
||||
|
||||
return c.open(dst, nonce, ciphertext, additionalData)
|
||||
}
|
||||
|
||||
// sliceForAppend takes a slice and a requested number of bytes. It returns a
|
||||
// slice with the contents of the given slice followed by that many bytes and a
|
||||
// second slice that aliases into it and contains only the extra bytes. If the
|
||||
// original slice has sufficient capacity then no allocation is performed.
|
||||
func sliceForAppend(in []byte, n int) (head, tail []byte) {
|
||||
if total := len(in) + n; cap(in) >= total {
|
||||
head = in[:total]
|
||||
} else {
|
||||
head = make([]byte, total)
|
||||
copy(head, in)
|
||||
}
|
||||
tail = head[len(in):]
|
||||
return
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gc && !purego
|
||||
// +build gc,!purego
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/crypto/internal/alias"
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
//go:noescape
|
||||
func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
|
||||
|
||||
//go:noescape
|
||||
func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
|
||||
|
||||
var (
|
||||
useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2
|
||||
)
|
||||
|
||||
// setupState writes a ChaCha20 input matrix to state. See
|
||||
// https://tools.ietf.org/html/rfc7539#section-2.3.
|
||||
func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
|
||||
state[0] = 0x61707865
|
||||
state[1] = 0x3320646e
|
||||
state[2] = 0x79622d32
|
||||
state[3] = 0x6b206574
|
||||
|
||||
state[4] = binary.LittleEndian.Uint32(key[0:4])
|
||||
state[5] = binary.LittleEndian.Uint32(key[4:8])
|
||||
state[6] = binary.LittleEndian.Uint32(key[8:12])
|
||||
state[7] = binary.LittleEndian.Uint32(key[12:16])
|
||||
state[8] = binary.LittleEndian.Uint32(key[16:20])
|
||||
state[9] = binary.LittleEndian.Uint32(key[20:24])
|
||||
state[10] = binary.LittleEndian.Uint32(key[24:28])
|
||||
state[11] = binary.LittleEndian.Uint32(key[28:32])
|
||||
|
||||
state[12] = 0
|
||||
state[13] = binary.LittleEndian.Uint32(nonce[0:4])
|
||||
state[14] = binary.LittleEndian.Uint32(nonce[4:8])
|
||||
state[15] = binary.LittleEndian.Uint32(nonce[8:12])
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
if !cpu.X86.HasSSSE3 {
|
||||
return c.sealGeneric(dst, nonce, plaintext, additionalData)
|
||||
}
|
||||
|
||||
var state [16]uint32
|
||||
setupState(&state, &c.key, nonce)
|
||||
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+16)
|
||||
if alias.InexactOverlap(out, plaintext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
}
|
||||
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
if !cpu.X86.HasSSSE3 {
|
||||
return c.openGeneric(dst, nonce, ciphertext, additionalData)
|
||||
}
|
||||
|
||||
var state [16]uint32
|
||||
setupState(&state, &c.key, nonce)
|
||||
|
||||
ciphertext = ciphertext[:len(ciphertext)-16]
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if alias.InexactOverlap(out, ciphertext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
}
|
||||
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
|
||||
for i := range out {
|
||||
out[i] = 0
|
||||
}
|
||||
return nil, errOpen
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
+2696
File diff suppressed because it is too large
Load Diff
+81
@@ -0,0 +1,81 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/crypto/chacha20"
|
||||
"golang.org/x/crypto/internal/alias"
|
||||
"golang.org/x/crypto/internal/poly1305"
|
||||
)
|
||||
|
||||
func writeWithPadding(p *poly1305.MAC, b []byte) {
|
||||
p.Write(b)
|
||||
if rem := len(b) % 16; rem != 0 {
|
||||
var buf [16]byte
|
||||
padLen := 16 - rem
|
||||
p.Write(buf[:padLen])
|
||||
}
|
||||
}
|
||||
|
||||
func writeUint64(p *poly1305.MAC, n int) {
|
||||
var buf [8]byte
|
||||
binary.LittleEndian.PutUint64(buf[:], uint64(n))
|
||||
p.Write(buf[:])
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
|
||||
ciphertext, tag := out[:len(plaintext)], out[len(plaintext):]
|
||||
if alias.InexactOverlap(out, plaintext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
}
|
||||
|
||||
var polyKey [32]byte
|
||||
s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
|
||||
s.XORKeyStream(polyKey[:], polyKey[:])
|
||||
s.SetCounter(1) // set the counter to 1, skipping 32 bytes
|
||||
s.XORKeyStream(ciphertext, plaintext)
|
||||
|
||||
p := poly1305.New(&polyKey)
|
||||
writeWithPadding(p, additionalData)
|
||||
writeWithPadding(p, ciphertext)
|
||||
writeUint64(p, len(additionalData))
|
||||
writeUint64(p, len(plaintext))
|
||||
p.Sum(tag[:0])
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
tag := ciphertext[len(ciphertext)-16:]
|
||||
ciphertext = ciphertext[:len(ciphertext)-16]
|
||||
|
||||
var polyKey [32]byte
|
||||
s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
|
||||
s.XORKeyStream(polyKey[:], polyKey[:])
|
||||
s.SetCounter(1) // set the counter to 1, skipping 32 bytes
|
||||
|
||||
p := poly1305.New(&polyKey)
|
||||
writeWithPadding(p, additionalData)
|
||||
writeWithPadding(p, ciphertext)
|
||||
writeUint64(p, len(additionalData))
|
||||
writeUint64(p, len(ciphertext))
|
||||
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if alias.InexactOverlap(out, ciphertext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
}
|
||||
if !p.Verify(tag) {
|
||||
for i := range out {
|
||||
out[i] = 0
|
||||
}
|
||||
return nil, errOpen
|
||||
}
|
||||
|
||||
s.XORKeyStream(out, ciphertext)
|
||||
return ret, nil
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !amd64 || !gc || purego
|
||||
// +build !amd64 !gc purego
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
return c.sealGeneric(dst, nonce, plaintext, additionalData)
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
return c.openGeneric(dst, nonce, ciphertext, additionalData)
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"errors"
|
||||
|
||||
"golang.org/x/crypto/chacha20"
|
||||
)
|
||||
|
||||
type xchacha20poly1305 struct {
|
||||
key [KeySize]byte
|
||||
}
|
||||
|
||||
// NewX returns a XChaCha20-Poly1305 AEAD that uses the given 256-bit key.
|
||||
//
|
||||
// XChaCha20-Poly1305 is a ChaCha20-Poly1305 variant that takes a longer nonce,
|
||||
// suitable to be generated randomly without risk of collisions. It should be
|
||||
// preferred when nonce uniqueness cannot be trivially ensured, or whenever
|
||||
// nonces are randomly generated.
|
||||
func NewX(key []byte) (cipher.AEAD, error) {
|
||||
if len(key) != KeySize {
|
||||
return nil, errors.New("chacha20poly1305: bad key length")
|
||||
}
|
||||
ret := new(xchacha20poly1305)
|
||||
copy(ret.key[:], key)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (*xchacha20poly1305) NonceSize() int {
|
||||
return NonceSizeX
|
||||
}
|
||||
|
||||
func (*xchacha20poly1305) Overhead() int {
|
||||
return Overhead
|
||||
}
|
||||
|
||||
func (x *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
if len(nonce) != NonceSizeX {
|
||||
panic("chacha20poly1305: bad nonce length passed to Seal")
|
||||
}
|
||||
|
||||
// XChaCha20-Poly1305 technically supports a 64-bit counter, so there is no
|
||||
// size limit. However, since we reuse the ChaCha20-Poly1305 implementation,
|
||||
// the second half of the counter is not available. This is unlikely to be
|
||||
// an issue because the cipher.AEAD API requires the entire message to be in
|
||||
// memory, and the counter overflows at 256 GB.
|
||||
if uint64(len(plaintext)) > (1<<38)-64 {
|
||||
panic("chacha20poly1305: plaintext too large")
|
||||
}
|
||||
|
||||
c := new(chacha20poly1305)
|
||||
hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16])
|
||||
copy(c.key[:], hKey)
|
||||
|
||||
// The first 4 bytes of the final nonce are unused counter space.
|
||||
cNonce := make([]byte, NonceSize)
|
||||
copy(cNonce[4:12], nonce[16:24])
|
||||
|
||||
return c.seal(dst, cNonce[:], plaintext, additionalData)
|
||||
}
|
||||
|
||||
func (x *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
if len(nonce) != NonceSizeX {
|
||||
panic("chacha20poly1305: bad nonce length passed to Open")
|
||||
}
|
||||
if len(ciphertext) < 16 {
|
||||
return nil, errOpen
|
||||
}
|
||||
if uint64(len(ciphertext)) > (1<<38)-48 {
|
||||
panic("chacha20poly1305: ciphertext too large")
|
||||
}
|
||||
|
||||
c := new(chacha20poly1305)
|
||||
hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16])
|
||||
copy(c.key[:], hKey)
|
||||
|
||||
// The first 4 bytes of the final nonce are unused counter space.
|
||||
cNonce := make([]byte, NonceSize)
|
||||
copy(cNonce[4:12], nonce[16:24])
|
||||
|
||||
return c.open(dst, cNonce[:], ciphertext, additionalData)
|
||||
}
|
||||
+809
@@ -0,0 +1,809 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cryptobyte
|
||||
|
||||
import (
|
||||
encoding_asn1 "encoding/asn1"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte/asn1"
|
||||
)
|
||||
|
||||
// This file contains ASN.1-related methods for String and Builder.
|
||||
|
||||
// Builder
|
||||
|
||||
// AddASN1Int64 appends a DER-encoded ASN.1 INTEGER.
|
||||
func (b *Builder) AddASN1Int64(v int64) {
|
||||
b.addASN1Signed(asn1.INTEGER, v)
|
||||
}
|
||||
|
||||
// AddASN1Int64WithTag appends a DER-encoded ASN.1 INTEGER with the
|
||||
// given tag.
|
||||
func (b *Builder) AddASN1Int64WithTag(v int64, tag asn1.Tag) {
|
||||
b.addASN1Signed(tag, v)
|
||||
}
|
||||
|
||||
// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION.
|
||||
func (b *Builder) AddASN1Enum(v int64) {
|
||||
b.addASN1Signed(asn1.ENUM, v)
|
||||
}
|
||||
|
||||
func (b *Builder) addASN1Signed(tag asn1.Tag, v int64) {
|
||||
b.AddASN1(tag, func(c *Builder) {
|
||||
length := 1
|
||||
for i := v; i >= 0x80 || i < -0x80; i >>= 8 {
|
||||
length++
|
||||
}
|
||||
|
||||
for ; length > 0; length-- {
|
||||
i := v >> uint((length-1)*8) & 0xff
|
||||
c.AddUint8(uint8(i))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// AddASN1Uint64 appends a DER-encoded ASN.1 INTEGER.
|
||||
func (b *Builder) AddASN1Uint64(v uint64) {
|
||||
b.AddASN1(asn1.INTEGER, func(c *Builder) {
|
||||
length := 1
|
||||
for i := v; i >= 0x80; i >>= 8 {
|
||||
length++
|
||||
}
|
||||
|
||||
for ; length > 0; length-- {
|
||||
i := v >> uint((length-1)*8) & 0xff
|
||||
c.AddUint8(uint8(i))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// AddASN1BigInt appends a DER-encoded ASN.1 INTEGER.
|
||||
func (b *Builder) AddASN1BigInt(n *big.Int) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b.AddASN1(asn1.INTEGER, func(c *Builder) {
|
||||
if n.Sign() < 0 {
|
||||
// A negative number has to be converted to two's-complement form. So we
|
||||
// invert and subtract 1. If the most-significant-bit isn't set then
|
||||
// we'll need to pad the beginning with 0xff in order to keep the number
|
||||
// negative.
|
||||
nMinus1 := new(big.Int).Neg(n)
|
||||
nMinus1.Sub(nMinus1, bigOne)
|
||||
bytes := nMinus1.Bytes()
|
||||
for i := range bytes {
|
||||
bytes[i] ^= 0xff
|
||||
}
|
||||
if len(bytes) == 0 || bytes[0]&0x80 == 0 {
|
||||
c.add(0xff)
|
||||
}
|
||||
c.add(bytes...)
|
||||
} else if n.Sign() == 0 {
|
||||
c.add(0)
|
||||
} else {
|
||||
bytes := n.Bytes()
|
||||
if bytes[0]&0x80 != 0 {
|
||||
c.add(0)
|
||||
}
|
||||
c.add(bytes...)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// AddASN1OctetString appends a DER-encoded ASN.1 OCTET STRING.
|
||||
func (b *Builder) AddASN1OctetString(bytes []byte) {
|
||||
b.AddASN1(asn1.OCTET_STRING, func(c *Builder) {
|
||||
c.AddBytes(bytes)
|
||||
})
|
||||
}
|
||||
|
||||
const generalizedTimeFormatStr = "20060102150405Z0700"
|
||||
|
||||
// AddASN1GeneralizedTime appends a DER-encoded ASN.1 GENERALIZEDTIME.
|
||||
func (b *Builder) AddASN1GeneralizedTime(t time.Time) {
|
||||
if t.Year() < 0 || t.Year() > 9999 {
|
||||
b.err = fmt.Errorf("cryptobyte: cannot represent %v as a GeneralizedTime", t)
|
||||
return
|
||||
}
|
||||
b.AddASN1(asn1.GeneralizedTime, func(c *Builder) {
|
||||
c.AddBytes([]byte(t.Format(generalizedTimeFormatStr)))
|
||||
})
|
||||
}
|
||||
|
||||
// AddASN1UTCTime appends a DER-encoded ASN.1 UTCTime.
|
||||
func (b *Builder) AddASN1UTCTime(t time.Time) {
|
||||
b.AddASN1(asn1.UTCTime, func(c *Builder) {
|
||||
// As utilized by the X.509 profile, UTCTime can only
|
||||
// represent the years 1950 through 2049.
|
||||
if t.Year() < 1950 || t.Year() >= 2050 {
|
||||
b.err = fmt.Errorf("cryptobyte: cannot represent %v as a UTCTime", t)
|
||||
return
|
||||
}
|
||||
c.AddBytes([]byte(t.Format(defaultUTCTimeFormatStr)))
|
||||
})
|
||||
}
|
||||
|
||||
// AddASN1BitString appends a DER-encoded ASN.1 BIT STRING. This does not
|
||||
// support BIT STRINGs that are not a whole number of bytes.
|
||||
func (b *Builder) AddASN1BitString(data []byte) {
|
||||
b.AddASN1(asn1.BIT_STRING, func(b *Builder) {
|
||||
b.AddUint8(0)
|
||||
b.AddBytes(data)
|
||||
})
|
||||
}
|
||||
|
||||
func (b *Builder) addBase128Int(n int64) {
|
||||
var length int
|
||||
if n == 0 {
|
||||
length = 1
|
||||
} else {
|
||||
for i := n; i > 0; i >>= 7 {
|
||||
length++
|
||||
}
|
||||
}
|
||||
|
||||
for i := length - 1; i >= 0; i-- {
|
||||
o := byte(n >> uint(i*7))
|
||||
o &= 0x7f
|
||||
if i != 0 {
|
||||
o |= 0x80
|
||||
}
|
||||
|
||||
b.add(o)
|
||||
}
|
||||
}
|
||||
|
||||
func isValidOID(oid encoding_asn1.ObjectIdentifier) bool {
|
||||
if len(oid) < 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
if oid[0] > 2 || (oid[0] <= 1 && oid[1] >= 40) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, v := range oid {
|
||||
if v < 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *Builder) AddASN1ObjectIdentifier(oid encoding_asn1.ObjectIdentifier) {
|
||||
b.AddASN1(asn1.OBJECT_IDENTIFIER, func(b *Builder) {
|
||||
if !isValidOID(oid) {
|
||||
b.err = fmt.Errorf("cryptobyte: invalid OID: %v", oid)
|
||||
return
|
||||
}
|
||||
|
||||
b.addBase128Int(int64(oid[0])*40 + int64(oid[1]))
|
||||
for _, v := range oid[2:] {
|
||||
b.addBase128Int(int64(v))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b *Builder) AddASN1Boolean(v bool) {
|
||||
b.AddASN1(asn1.BOOLEAN, func(b *Builder) {
|
||||
if v {
|
||||
b.AddUint8(0xff)
|
||||
} else {
|
||||
b.AddUint8(0)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (b *Builder) AddASN1NULL() {
|
||||
b.add(uint8(asn1.NULL), 0)
|
||||
}
|
||||
|
||||
// MarshalASN1 calls encoding_asn1.Marshal on its input and appends the result if
|
||||
// successful or records an error if one occurred.
|
||||
func (b *Builder) MarshalASN1(v interface{}) {
|
||||
// NOTE(martinkr): This is somewhat of a hack to allow propagation of
|
||||
// encoding_asn1.Marshal errors into Builder.err. N.B. if you call MarshalASN1 with a
|
||||
// value embedded into a struct, its tag information is lost.
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
bytes, err := encoding_asn1.Marshal(v)
|
||||
if err != nil {
|
||||
b.err = err
|
||||
return
|
||||
}
|
||||
b.AddBytes(bytes)
|
||||
}
|
||||
|
||||
// AddASN1 appends an ASN.1 object. The object is prefixed with the given tag.
|
||||
// Tags greater than 30 are not supported and result in an error (i.e.
|
||||
// low-tag-number form only). The child builder passed to the
|
||||
// BuilderContinuation can be used to build the content of the ASN.1 object.
|
||||
func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
// Identifiers with the low five bits set indicate high-tag-number format
|
||||
// (two or more octets), which we don't support.
|
||||
if tag&0x1f == 0x1f {
|
||||
b.err = fmt.Errorf("cryptobyte: high-tag number identifier octects not supported: 0x%x", tag)
|
||||
return
|
||||
}
|
||||
b.AddUint8(uint8(tag))
|
||||
b.addLengthPrefixed(1, true, f)
|
||||
}
|
||||
|
||||
// String
|
||||
|
||||
// ReadASN1Boolean decodes an ASN.1 BOOLEAN and converts it to a boolean
|
||||
// representation into out and advances. It reports whether the read
|
||||
// was successful.
|
||||
func (s *String) ReadASN1Boolean(out *bool) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.BOOLEAN) || len(bytes) != 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
switch bytes[0] {
|
||||
case 0:
|
||||
*out = false
|
||||
case 0xff:
|
||||
*out = true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem()
|
||||
|
||||
// ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does
|
||||
// not point to an integer or to a big.Int, it panics. It reports whether the
|
||||
// read was successful.
|
||||
func (s *String) ReadASN1Integer(out interface{}) bool {
|
||||
if reflect.TypeOf(out).Kind() != reflect.Ptr {
|
||||
panic("out is not a pointer")
|
||||
}
|
||||
switch reflect.ValueOf(out).Elem().Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
var i int64
|
||||
if !s.readASN1Int64(&i) || reflect.ValueOf(out).Elem().OverflowInt(i) {
|
||||
return false
|
||||
}
|
||||
reflect.ValueOf(out).Elem().SetInt(i)
|
||||
return true
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
var u uint64
|
||||
if !s.readASN1Uint64(&u) || reflect.ValueOf(out).Elem().OverflowUint(u) {
|
||||
return false
|
||||
}
|
||||
reflect.ValueOf(out).Elem().SetUint(u)
|
||||
return true
|
||||
case reflect.Struct:
|
||||
if reflect.TypeOf(out).Elem() == bigIntType {
|
||||
return s.readASN1BigInt(out.(*big.Int))
|
||||
}
|
||||
}
|
||||
panic("out does not point to an integer type")
|
||||
}
|
||||
|
||||
func checkASN1Integer(bytes []byte) bool {
|
||||
if len(bytes) == 0 {
|
||||
// An INTEGER is encoded with at least one octet.
|
||||
return false
|
||||
}
|
||||
if len(bytes) == 1 {
|
||||
return true
|
||||
}
|
||||
if bytes[0] == 0 && bytes[1]&0x80 == 0 || bytes[0] == 0xff && bytes[1]&0x80 == 0x80 {
|
||||
// Value is not minimally encoded.
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var bigOne = big.NewInt(1)
|
||||
|
||||
func (s *String) readASN1BigInt(out *big.Int) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) {
|
||||
return false
|
||||
}
|
||||
if bytes[0]&0x80 == 0x80 {
|
||||
// Negative number.
|
||||
neg := make([]byte, len(bytes))
|
||||
for i, b := range bytes {
|
||||
neg[i] = ^b
|
||||
}
|
||||
out.SetBytes(neg)
|
||||
out.Add(out, bigOne)
|
||||
out.Neg(out)
|
||||
} else {
|
||||
out.SetBytes(bytes)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readASN1Int64(out *int64) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Signed(out, bytes) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func asn1Signed(out *int64, n []byte) bool {
|
||||
length := len(n)
|
||||
if length > 8 {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
*out <<= 8
|
||||
*out |= int64(n[i])
|
||||
}
|
||||
// Shift up and down in order to sign extend the result.
|
||||
*out <<= 64 - uint8(length)*8
|
||||
*out >>= 64 - uint8(length)*8
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readASN1Uint64(out *uint64) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Unsigned(out, bytes) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func asn1Unsigned(out *uint64, n []byte) bool {
|
||||
length := len(n)
|
||||
if length > 9 || length == 9 && n[0] != 0 {
|
||||
// Too large for uint64.
|
||||
return false
|
||||
}
|
||||
if n[0]&0x80 != 0 {
|
||||
// Negative number.
|
||||
return false
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
*out <<= 8
|
||||
*out |= uint64(n[i])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1Int64WithTag decodes an ASN.1 INTEGER with the given tag into out
|
||||
// and advances. It reports whether the read was successful and resulted in a
|
||||
// value that can be represented in an int64.
|
||||
func (s *String) ReadASN1Int64WithTag(out *int64, tag asn1.Tag) bool {
|
||||
var bytes String
|
||||
return s.ReadASN1(&bytes, tag) && checkASN1Integer(bytes) && asn1Signed(out, bytes)
|
||||
}
|
||||
|
||||
// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It reports
|
||||
// whether the read was successful.
|
||||
func (s *String) ReadASN1Enum(out *int) bool {
|
||||
var bytes String
|
||||
var i int64
|
||||
if !s.ReadASN1(&bytes, asn1.ENUM) || !checkASN1Integer(bytes) || !asn1Signed(&i, bytes) {
|
||||
return false
|
||||
}
|
||||
if int64(int(i)) != i {
|
||||
return false
|
||||
}
|
||||
*out = int(i)
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readBase128Int(out *int) bool {
|
||||
ret := 0
|
||||
for i := 0; len(*s) > 0; i++ {
|
||||
if i == 5 {
|
||||
return false
|
||||
}
|
||||
// Avoid overflowing int on a 32-bit platform.
|
||||
// We don't want different behavior based on the architecture.
|
||||
if ret >= 1<<(31-7) {
|
||||
return false
|
||||
}
|
||||
ret <<= 7
|
||||
b := s.read(1)[0]
|
||||
ret |= int(b & 0x7f)
|
||||
if b&0x80 == 0 {
|
||||
*out = ret
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false // truncated
|
||||
}
|
||||
|
||||
// ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and
|
||||
// advances. It reports whether the read was successful.
|
||||
func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.OBJECT_IDENTIFIER) || len(bytes) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// In the worst case, we get two elements from the first byte (which is
|
||||
// encoded differently) and then every varint is a single byte long.
|
||||
components := make([]int, len(bytes)+1)
|
||||
|
||||
// The first varint is 40*value1 + value2:
|
||||
// According to this packing, value1 can take the values 0, 1 and 2 only.
|
||||
// When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2,
|
||||
// then there are no restrictions on value2.
|
||||
var v int
|
||||
if !bytes.readBase128Int(&v) {
|
||||
return false
|
||||
}
|
||||
if v < 80 {
|
||||
components[0] = v / 40
|
||||
components[1] = v % 40
|
||||
} else {
|
||||
components[0] = 2
|
||||
components[1] = v - 80
|
||||
}
|
||||
|
||||
i := 2
|
||||
for ; len(bytes) > 0; i++ {
|
||||
if !bytes.readBase128Int(&v) {
|
||||
return false
|
||||
}
|
||||
components[i] = v
|
||||
}
|
||||
*out = components[:i]
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and
|
||||
// advances. It reports whether the read was successful.
|
||||
func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.GeneralizedTime) {
|
||||
return false
|
||||
}
|
||||
t := string(bytes)
|
||||
res, err := time.Parse(generalizedTimeFormatStr, t)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if serialized := res.Format(generalizedTimeFormatStr); serialized != t {
|
||||
return false
|
||||
}
|
||||
*out = res
|
||||
return true
|
||||
}
|
||||
|
||||
const defaultUTCTimeFormatStr = "060102150405Z0700"
|
||||
|
||||
// ReadASN1UTCTime decodes an ASN.1 UTCTime into out and advances.
|
||||
// It reports whether the read was successful.
|
||||
func (s *String) ReadASN1UTCTime(out *time.Time) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.UTCTime) {
|
||||
return false
|
||||
}
|
||||
t := string(bytes)
|
||||
|
||||
formatStr := defaultUTCTimeFormatStr
|
||||
var err error
|
||||
res, err := time.Parse(formatStr, t)
|
||||
if err != nil {
|
||||
// Fallback to minute precision if we can't parse second
|
||||
// precision. If we are following X.509 or X.690 we shouldn't
|
||||
// support this, but we do.
|
||||
formatStr = "0601021504Z0700"
|
||||
res, err = time.Parse(formatStr, t)
|
||||
}
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if serialized := res.Format(formatStr); serialized != t {
|
||||
return false
|
||||
}
|
||||
|
||||
if res.Year() >= 2050 {
|
||||
// UTCTime interprets the low order digits 50-99 as 1950-99.
|
||||
// This only applies to its use in the X.509 profile.
|
||||
// See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
|
||||
res = res.AddDate(-100, 0, 0)
|
||||
}
|
||||
*out = res
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances.
|
||||
// It reports whether the read was successful.
|
||||
func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 ||
|
||||
len(bytes)*8/8 != len(bytes) {
|
||||
return false
|
||||
}
|
||||
|
||||
paddingBits := uint8(bytes[0])
|
||||
bytes = bytes[1:]
|
||||
if paddingBits > 7 ||
|
||||
len(bytes) == 0 && paddingBits != 0 ||
|
||||
len(bytes) > 0 && bytes[len(bytes)-1]&(1<<paddingBits-1) != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
out.BitLength = len(bytes)*8 - int(paddingBits)
|
||||
out.Bytes = bytes
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It is
|
||||
// an error if the BIT STRING is not a whole number of bytes. It reports
|
||||
// whether the read was successful.
|
||||
func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
paddingBits := uint8(bytes[0])
|
||||
if paddingBits != 0 {
|
||||
return false
|
||||
}
|
||||
*out = bytes[1:]
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1Bytes reads the contents of a DER-encoded ASN.1 element (not including
|
||||
// tag and length bytes) into out, and advances. The element must match the
|
||||
// given tag. It reports whether the read was successful.
|
||||
func (s *String) ReadASN1Bytes(out *[]byte, tag asn1.Tag) bool {
|
||||
return s.ReadASN1((*String)(out), tag)
|
||||
}
|
||||
|
||||
// ReadASN1 reads the contents of a DER-encoded ASN.1 element (not including
|
||||
// tag and length bytes) into out, and advances. The element must match the
|
||||
// given tag. It reports whether the read was successful.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadASN1(out *String, tag asn1.Tag) bool {
|
||||
var t asn1.Tag
|
||||
if !s.ReadAnyASN1(out, &t) || t != tag {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1Element reads the contents of a DER-encoded ASN.1 element (including
|
||||
// tag and length bytes) into out, and advances. The element must match the
|
||||
// given tag. It reports whether the read was successful.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadASN1Element(out *String, tag asn1.Tag) bool {
|
||||
var t asn1.Tag
|
||||
if !s.ReadAnyASN1Element(out, &t) || t != tag {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadAnyASN1 reads the contents of a DER-encoded ASN.1 element (not including
|
||||
// tag and length bytes) into out, sets outTag to its tag, and advances.
|
||||
// It reports whether the read was successful.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadAnyASN1(out *String, outTag *asn1.Tag) bool {
|
||||
return s.readASN1(out, outTag, true /* skip header */)
|
||||
}
|
||||
|
||||
// ReadAnyASN1Element reads the contents of a DER-encoded ASN.1 element
|
||||
// (including tag and length bytes) into out, sets outTag to is tag, and
|
||||
// advances. It reports whether the read was successful.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadAnyASN1Element(out *String, outTag *asn1.Tag) bool {
|
||||
return s.readASN1(out, outTag, false /* include header */)
|
||||
}
|
||||
|
||||
// PeekASN1Tag reports whether the next ASN.1 value on the string starts with
|
||||
// the given tag.
|
||||
func (s String) PeekASN1Tag(tag asn1.Tag) bool {
|
||||
if len(s) == 0 {
|
||||
return false
|
||||
}
|
||||
return asn1.Tag(s[0]) == tag
|
||||
}
|
||||
|
||||
// SkipASN1 reads and discards an ASN.1 element with the given tag. It
|
||||
// reports whether the operation was successful.
|
||||
func (s *String) SkipASN1(tag asn1.Tag) bool {
|
||||
var unused String
|
||||
return s.ReadASN1(&unused, tag)
|
||||
}
|
||||
|
||||
// ReadOptionalASN1 attempts to read the contents of a DER-encoded ASN.1
|
||||
// element (not including tag and length bytes) tagged with the given tag into
|
||||
// out. It stores whether an element with the tag was found in outPresent,
|
||||
// unless outPresent is nil. It reports whether the read was successful.
|
||||
func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag asn1.Tag) bool {
|
||||
present := s.PeekASN1Tag(tag)
|
||||
if outPresent != nil {
|
||||
*outPresent = present
|
||||
}
|
||||
if present && !s.ReadASN1(out, tag) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// SkipOptionalASN1 advances s over an ASN.1 element with the given tag, or
|
||||
// else leaves s unchanged. It reports whether the operation was successful.
|
||||
func (s *String) SkipOptionalASN1(tag asn1.Tag) bool {
|
||||
if !s.PeekASN1Tag(tag) {
|
||||
return true
|
||||
}
|
||||
var unused String
|
||||
return s.ReadASN1(&unused, tag)
|
||||
}
|
||||
|
||||
// ReadOptionalASN1Integer attempts to read an optional ASN.1 INTEGER
|
||||
// explicitly tagged with tag into out and advances. If no element with a
|
||||
// matching tag is present, it writes defaultValue into out instead. If out
|
||||
// does not point to an integer or to a big.Int, it panics. It reports
|
||||
// whether the read was successful.
|
||||
func (s *String) ReadOptionalASN1Integer(out interface{}, tag asn1.Tag, defaultValue interface{}) bool {
|
||||
if reflect.TypeOf(out).Kind() != reflect.Ptr {
|
||||
panic("out is not a pointer")
|
||||
}
|
||||
var present bool
|
||||
var i String
|
||||
if !s.ReadOptionalASN1(&i, &present, tag) {
|
||||
return false
|
||||
}
|
||||
if !present {
|
||||
switch reflect.ValueOf(out).Elem().Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(defaultValue))
|
||||
case reflect.Struct:
|
||||
if reflect.TypeOf(out).Elem() != bigIntType {
|
||||
panic("invalid integer type")
|
||||
}
|
||||
if reflect.TypeOf(defaultValue).Kind() != reflect.Ptr ||
|
||||
reflect.TypeOf(defaultValue).Elem() != bigIntType {
|
||||
panic("out points to big.Int, but defaultValue does not")
|
||||
}
|
||||
out.(*big.Int).Set(defaultValue.(*big.Int))
|
||||
default:
|
||||
panic("invalid integer type")
|
||||
}
|
||||
return true
|
||||
}
|
||||
if !i.ReadASN1Integer(out) || !i.Empty() {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadOptionalASN1OctetString attempts to read an optional ASN.1 OCTET STRING
|
||||
// explicitly tagged with tag into out and advances. If no element with a
|
||||
// matching tag is present, it sets "out" to nil instead. It reports
|
||||
// whether the read was successful.
|
||||
func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag asn1.Tag) bool {
|
||||
var present bool
|
||||
var child String
|
||||
if !s.ReadOptionalASN1(&child, &present, tag) {
|
||||
return false
|
||||
}
|
||||
if outPresent != nil {
|
||||
*outPresent = present
|
||||
}
|
||||
if present {
|
||||
var oct String
|
||||
if !child.ReadASN1(&oct, asn1.OCTET_STRING) || !child.Empty() {
|
||||
return false
|
||||
}
|
||||
*out = oct
|
||||
} else {
|
||||
*out = nil
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadOptionalASN1Boolean sets *out to the value of the next ASN.1 BOOLEAN or,
|
||||
// if the next bytes are not an ASN.1 BOOLEAN, to the value of defaultValue.
|
||||
// It reports whether the operation was successful.
|
||||
func (s *String) ReadOptionalASN1Boolean(out *bool, defaultValue bool) bool {
|
||||
var present bool
|
||||
var child String
|
||||
if !s.ReadOptionalASN1(&child, &present, asn1.BOOLEAN) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !present {
|
||||
*out = defaultValue
|
||||
return true
|
||||
}
|
||||
|
||||
return s.ReadASN1Boolean(out)
|
||||
}
|
||||
|
||||
func (s *String) readASN1(out *String, outTag *asn1.Tag, skipHeader bool) bool {
|
||||
if len(*s) < 2 {
|
||||
return false
|
||||
}
|
||||
tag, lenByte := (*s)[0], (*s)[1]
|
||||
|
||||
if tag&0x1f == 0x1f {
|
||||
// ITU-T X.690 section 8.1.2
|
||||
//
|
||||
// An identifier octet with a tag part of 0x1f indicates a high-tag-number
|
||||
// form identifier with two or more octets. We only support tags less than
|
||||
// 31 (i.e. low-tag-number form, single octet identifier).
|
||||
return false
|
||||
}
|
||||
|
||||
if outTag != nil {
|
||||
*outTag = asn1.Tag(tag)
|
||||
}
|
||||
|
||||
// ITU-T X.690 section 8.1.3
|
||||
//
|
||||
// Bit 8 of the first length byte indicates whether the length is short- or
|
||||
// long-form.
|
||||
var length, headerLen uint32 // length includes headerLen
|
||||
if lenByte&0x80 == 0 {
|
||||
// Short-form length (section 8.1.3.4), encoded in bits 1-7.
|
||||
length = uint32(lenByte) + 2
|
||||
headerLen = 2
|
||||
} else {
|
||||
// Long-form length (section 8.1.3.5). Bits 1-7 encode the number of octets
|
||||
// used to encode the length.
|
||||
lenLen := lenByte & 0x7f
|
||||
var len32 uint32
|
||||
|
||||
if lenLen == 0 || lenLen > 4 || len(*s) < int(2+lenLen) {
|
||||
return false
|
||||
}
|
||||
|
||||
lenBytes := String((*s)[2 : 2+lenLen])
|
||||
if !lenBytes.readUnsigned(&len32, int(lenLen)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// ITU-T X.690 section 10.1 (DER length forms) requires encoding the length
|
||||
// with the minimum number of octets.
|
||||
if len32 < 128 {
|
||||
// Length should have used short-form encoding.
|
||||
return false
|
||||
}
|
||||
if len32>>((lenLen-1)*8) == 0 {
|
||||
// Leading octet is 0. Length should have been at least one byte shorter.
|
||||
return false
|
||||
}
|
||||
|
||||
headerLen = 2 + uint32(lenLen)
|
||||
if headerLen+len32 < len32 {
|
||||
// Overflow.
|
||||
return false
|
||||
}
|
||||
length = headerLen + len32
|
||||
}
|
||||
|
||||
if int(length) < 0 || !s.ReadBytes((*[]byte)(out), int(length)) {
|
||||
return false
|
||||
}
|
||||
if skipHeader && !out.Skip(int(headerLen)) {
|
||||
panic("cryptobyte: internal error")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package asn1 contains supporting types for parsing and building ASN.1
|
||||
// messages with the cryptobyte package.
|
||||
package asn1 // import "golang.org/x/crypto/cryptobyte/asn1"
|
||||
|
||||
// Tag represents an ASN.1 identifier octet, consisting of a tag number
|
||||
// (indicating a type) and class (such as context-specific or constructed).
|
||||
//
|
||||
// Methods in the cryptobyte package only support the low-tag-number form, i.e.
|
||||
// a single identifier octet with bits 7-8 encoding the class and bits 1-6
|
||||
// encoding the tag number.
|
||||
type Tag uint8
|
||||
|
||||
const (
|
||||
classConstructed = 0x20
|
||||
classContextSpecific = 0x80
|
||||
)
|
||||
|
||||
// Constructed returns t with the constructed class bit set.
|
||||
func (t Tag) Constructed() Tag { return t | classConstructed }
|
||||
|
||||
// ContextSpecific returns t with the context-specific class bit set.
|
||||
func (t Tag) ContextSpecific() Tag { return t | classContextSpecific }
|
||||
|
||||
// The following is a list of standard tag and class combinations.
|
||||
const (
|
||||
BOOLEAN = Tag(1)
|
||||
INTEGER = Tag(2)
|
||||
BIT_STRING = Tag(3)
|
||||
OCTET_STRING = Tag(4)
|
||||
NULL = Tag(5)
|
||||
OBJECT_IDENTIFIER = Tag(6)
|
||||
ENUM = Tag(10)
|
||||
UTF8String = Tag(12)
|
||||
SEQUENCE = Tag(16 | classConstructed)
|
||||
SET = Tag(17 | classConstructed)
|
||||
PrintableString = Tag(19)
|
||||
T61String = Tag(20)
|
||||
IA5String = Tag(22)
|
||||
UTCTime = Tag(23)
|
||||
GeneralizedTime = Tag(24)
|
||||
GeneralString = Tag(27)
|
||||
)
|
||||
+342
@@ -0,0 +1,342 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cryptobyte
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// A Builder builds byte strings from fixed-length and length-prefixed values.
|
||||
// Builders either allocate space as needed, or are ‘fixed’, which means that
|
||||
// they write into a given buffer and produce an error if it's exhausted.
|
||||
//
|
||||
// The zero value is a usable Builder that allocates space as needed.
|
||||
//
|
||||
// Simple values are marshaled and appended to a Builder using methods on the
|
||||
// Builder. Length-prefixed values are marshaled by providing a
|
||||
// BuilderContinuation, which is a function that writes the inner contents of
|
||||
// the value to a given Builder. See the documentation for BuilderContinuation
|
||||
// for details.
|
||||
type Builder struct {
|
||||
err error
|
||||
result []byte
|
||||
fixedSize bool
|
||||
child *Builder
|
||||
offset int
|
||||
pendingLenLen int
|
||||
pendingIsASN1 bool
|
||||
inContinuation *bool
|
||||
}
|
||||
|
||||
// NewBuilder creates a Builder that appends its output to the given buffer.
|
||||
// Like append(), the slice will be reallocated if its capacity is exceeded.
|
||||
// Use Bytes to get the final buffer.
|
||||
func NewBuilder(buffer []byte) *Builder {
|
||||
return &Builder{
|
||||
result: buffer,
|
||||
}
|
||||
}
|
||||
|
||||
// NewFixedBuilder creates a Builder that appends its output into the given
|
||||
// buffer. This builder does not reallocate the output buffer. Writes that
|
||||
// would exceed the buffer's capacity are treated as an error.
|
||||
func NewFixedBuilder(buffer []byte) *Builder {
|
||||
return &Builder{
|
||||
result: buffer,
|
||||
fixedSize: true,
|
||||
}
|
||||
}
|
||||
|
||||
// SetError sets the value to be returned as the error from Bytes. Writes
|
||||
// performed after calling SetError are ignored.
|
||||
func (b *Builder) SetError(err error) {
|
||||
b.err = err
|
||||
}
|
||||
|
||||
// Bytes returns the bytes written by the builder or an error if one has
|
||||
// occurred during building.
|
||||
func (b *Builder) Bytes() ([]byte, error) {
|
||||
if b.err != nil {
|
||||
return nil, b.err
|
||||
}
|
||||
return b.result[b.offset:], nil
|
||||
}
|
||||
|
||||
// BytesOrPanic returns the bytes written by the builder or panics if an error
|
||||
// has occurred during building.
|
||||
func (b *Builder) BytesOrPanic() []byte {
|
||||
if b.err != nil {
|
||||
panic(b.err)
|
||||
}
|
||||
return b.result[b.offset:]
|
||||
}
|
||||
|
||||
// AddUint8 appends an 8-bit value to the byte string.
|
||||
func (b *Builder) AddUint8(v uint8) {
|
||||
b.add(byte(v))
|
||||
}
|
||||
|
||||
// AddUint16 appends a big-endian, 16-bit value to the byte string.
|
||||
func (b *Builder) AddUint16(v uint16) {
|
||||
b.add(byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
// AddUint24 appends a big-endian, 24-bit value to the byte string. The highest
|
||||
// byte of the 32-bit input value is silently truncated.
|
||||
func (b *Builder) AddUint24(v uint32) {
|
||||
b.add(byte(v>>16), byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
// AddUint32 appends a big-endian, 32-bit value to the byte string.
|
||||
func (b *Builder) AddUint32(v uint32) {
|
||||
b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
// AddUint64 appends a big-endian, 64-bit value to the byte string.
|
||||
func (b *Builder) AddUint64(v uint64) {
|
||||
b.add(byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
// AddBytes appends a sequence of bytes to the byte string.
|
||||
func (b *Builder) AddBytes(v []byte) {
|
||||
b.add(v...)
|
||||
}
|
||||
|
||||
// BuilderContinuation is a continuation-passing interface for building
|
||||
// length-prefixed byte sequences. Builder methods for length-prefixed
|
||||
// sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation
|
||||
// supplied to them. The child builder passed to the continuation can be used
|
||||
// to build the content of the length-prefixed sequence. For example:
|
||||
//
|
||||
// parent := cryptobyte.NewBuilder()
|
||||
// parent.AddUint8LengthPrefixed(func (child *Builder) {
|
||||
// child.AddUint8(42)
|
||||
// child.AddUint8LengthPrefixed(func (grandchild *Builder) {
|
||||
// grandchild.AddUint8(5)
|
||||
// })
|
||||
// })
|
||||
//
|
||||
// It is an error to write more bytes to the child than allowed by the reserved
|
||||
// length prefix. After the continuation returns, the child must be considered
|
||||
// invalid, i.e. users must not store any copies or references of the child
|
||||
// that outlive the continuation.
|
||||
//
|
||||
// If the continuation panics with a value of type BuildError then the inner
|
||||
// error will be returned as the error from Bytes. If the child panics
|
||||
// otherwise then Bytes will repanic with the same value.
|
||||
type BuilderContinuation func(child *Builder)
|
||||
|
||||
// BuildError wraps an error. If a BuilderContinuation panics with this value,
|
||||
// the panic will be recovered and the inner error will be returned from
|
||||
// Builder.Bytes.
|
||||
type BuildError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence.
|
||||
func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) {
|
||||
b.addLengthPrefixed(1, false, f)
|
||||
}
|
||||
|
||||
// AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence.
|
||||
func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) {
|
||||
b.addLengthPrefixed(2, false, f)
|
||||
}
|
||||
|
||||
// AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence.
|
||||
func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) {
|
||||
b.addLengthPrefixed(3, false, f)
|
||||
}
|
||||
|
||||
// AddUint32LengthPrefixed adds a big-endian, 32-bit length-prefixed byte sequence.
|
||||
func (b *Builder) AddUint32LengthPrefixed(f BuilderContinuation) {
|
||||
b.addLengthPrefixed(4, false, f)
|
||||
}
|
||||
|
||||
func (b *Builder) callContinuation(f BuilderContinuation, arg *Builder) {
|
||||
if !*b.inContinuation {
|
||||
*b.inContinuation = true
|
||||
|
||||
defer func() {
|
||||
*b.inContinuation = false
|
||||
|
||||
r := recover()
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if buildError, ok := r.(BuildError); ok {
|
||||
b.err = buildError.Err
|
||||
} else {
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
f(arg)
|
||||
}
|
||||
|
||||
func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) {
|
||||
// Subsequent writes can be ignored if the builder has encountered an error.
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
offset := len(b.result)
|
||||
b.add(make([]byte, lenLen)...)
|
||||
|
||||
if b.inContinuation == nil {
|
||||
b.inContinuation = new(bool)
|
||||
}
|
||||
|
||||
b.child = &Builder{
|
||||
result: b.result,
|
||||
fixedSize: b.fixedSize,
|
||||
offset: offset,
|
||||
pendingLenLen: lenLen,
|
||||
pendingIsASN1: isASN1,
|
||||
inContinuation: b.inContinuation,
|
||||
}
|
||||
|
||||
b.callContinuation(f, b.child)
|
||||
b.flushChild()
|
||||
if b.child != nil {
|
||||
panic("cryptobyte: internal error")
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Builder) flushChild() {
|
||||
if b.child == nil {
|
||||
return
|
||||
}
|
||||
b.child.flushChild()
|
||||
child := b.child
|
||||
b.child = nil
|
||||
|
||||
if child.err != nil {
|
||||
b.err = child.err
|
||||
return
|
||||
}
|
||||
|
||||
length := len(child.result) - child.pendingLenLen - child.offset
|
||||
|
||||
if length < 0 {
|
||||
panic("cryptobyte: internal error") // result unexpectedly shrunk
|
||||
}
|
||||
|
||||
if child.pendingIsASN1 {
|
||||
// For ASN.1, we reserved a single byte for the length. If that turned out
|
||||
// to be incorrect, we have to move the contents along in order to make
|
||||
// space.
|
||||
if child.pendingLenLen != 1 {
|
||||
panic("cryptobyte: internal error")
|
||||
}
|
||||
var lenLen, lenByte uint8
|
||||
if int64(length) > 0xfffffffe {
|
||||
b.err = errors.New("pending ASN.1 child too long")
|
||||
return
|
||||
} else if length > 0xffffff {
|
||||
lenLen = 5
|
||||
lenByte = 0x80 | 4
|
||||
} else if length > 0xffff {
|
||||
lenLen = 4
|
||||
lenByte = 0x80 | 3
|
||||
} else if length > 0xff {
|
||||
lenLen = 3
|
||||
lenByte = 0x80 | 2
|
||||
} else if length > 0x7f {
|
||||
lenLen = 2
|
||||
lenByte = 0x80 | 1
|
||||
} else {
|
||||
lenLen = 1
|
||||
lenByte = uint8(length)
|
||||
length = 0
|
||||
}
|
||||
|
||||
// Insert the initial length byte, make space for successive length bytes,
|
||||
// and adjust the offset.
|
||||
child.result[child.offset] = lenByte
|
||||
extraBytes := int(lenLen - 1)
|
||||
if extraBytes != 0 {
|
||||
child.add(make([]byte, extraBytes)...)
|
||||
childStart := child.offset + child.pendingLenLen
|
||||
copy(child.result[childStart+extraBytes:], child.result[childStart:])
|
||||
}
|
||||
child.offset++
|
||||
child.pendingLenLen = extraBytes
|
||||
}
|
||||
|
||||
l := length
|
||||
for i := child.pendingLenLen - 1; i >= 0; i-- {
|
||||
child.result[child.offset+i] = uint8(l)
|
||||
l >>= 8
|
||||
}
|
||||
if l != 0 {
|
||||
b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen)
|
||||
return
|
||||
}
|
||||
|
||||
if b.fixedSize && &b.result[0] != &child.result[0] {
|
||||
panic("cryptobyte: BuilderContinuation reallocated a fixed-size buffer")
|
||||
}
|
||||
|
||||
b.result = child.result
|
||||
}
|
||||
|
||||
func (b *Builder) add(bytes ...byte) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
if b.child != nil {
|
||||
panic("cryptobyte: attempted write while child is pending")
|
||||
}
|
||||
if len(b.result)+len(bytes) < len(bytes) {
|
||||
b.err = errors.New("cryptobyte: length overflow")
|
||||
}
|
||||
if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) {
|
||||
b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer")
|
||||
return
|
||||
}
|
||||
b.result = append(b.result, bytes...)
|
||||
}
|
||||
|
||||
// Unwrite rolls back n bytes written directly to the Builder. An attempt by a
|
||||
// child builder passed to a continuation to unwrite bytes from its parent will
|
||||
// panic.
|
||||
func (b *Builder) Unwrite(n int) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
if b.child != nil {
|
||||
panic("cryptobyte: attempted unwrite while child is pending")
|
||||
}
|
||||
length := len(b.result) - b.pendingLenLen - b.offset
|
||||
if length < 0 {
|
||||
panic("cryptobyte: internal error")
|
||||
}
|
||||
if n > length {
|
||||
panic("cryptobyte: attempted to unwrite more than was written")
|
||||
}
|
||||
b.result = b.result[:len(b.result)-n]
|
||||
}
|
||||
|
||||
// A MarshalingValue marshals itself into a Builder.
|
||||
type MarshalingValue interface {
|
||||
// Marshal is called by Builder.AddValue. It receives a pointer to a builder
|
||||
// to marshal itself into. It may return an error that occurred during
|
||||
// marshaling, such as unset or invalid values.
|
||||
Marshal(b *Builder) error
|
||||
}
|
||||
|
||||
// AddValue calls Marshal on v, passing a pointer to the builder to append to.
|
||||
// If Marshal returns an error, it is set on the Builder so that subsequent
|
||||
// appends don't have an effect.
|
||||
func (b *Builder) AddValue(v MarshalingValue) {
|
||||
err := v.Marshal(b)
|
||||
if err != nil {
|
||||
b.err = err
|
||||
}
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package cryptobyte contains types that help with parsing and constructing
|
||||
// length-prefixed, binary messages, including ASN.1 DER. (The asn1 subpackage
|
||||
// contains useful ASN.1 constants.)
|
||||
//
|
||||
// The String type is for parsing. It wraps a []byte slice and provides helper
|
||||
// functions for consuming structures, value by value.
|
||||
//
|
||||
// The Builder type is for constructing messages. It providers helper functions
|
||||
// for appending values and also for appending length-prefixed submessages –
|
||||
// without having to worry about calculating the length prefix ahead of time.
|
||||
//
|
||||
// See the documentation and examples for the Builder and String types to get
|
||||
// started.
|
||||
package cryptobyte // import "golang.org/x/crypto/cryptobyte"
|
||||
|
||||
// String represents a string of bytes. It provides methods for parsing
|
||||
// fixed-length and length-prefixed values from it.
|
||||
type String []byte
|
||||
|
||||
// read advances a String by n bytes and returns them. If less than n bytes
|
||||
// remain, it returns nil.
|
||||
func (s *String) read(n int) []byte {
|
||||
if len(*s) < n || n < 0 {
|
||||
return nil
|
||||
}
|
||||
v := (*s)[:n]
|
||||
*s = (*s)[n:]
|
||||
return v
|
||||
}
|
||||
|
||||
// Skip advances the String by n byte and reports whether it was successful.
|
||||
func (s *String) Skip(n int) bool {
|
||||
return s.read(n) != nil
|
||||
}
|
||||
|
||||
// ReadUint8 decodes an 8-bit value into out and advances over it.
|
||||
// It reports whether the read was successful.
|
||||
func (s *String) ReadUint8(out *uint8) bool {
|
||||
v := s.read(1)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = uint8(v[0])
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUint16 decodes a big-endian, 16-bit value into out and advances over it.
|
||||
// It reports whether the read was successful.
|
||||
func (s *String) ReadUint16(out *uint16) bool {
|
||||
v := s.read(2)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = uint16(v[0])<<8 | uint16(v[1])
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUint24 decodes a big-endian, 24-bit value into out and advances over it.
|
||||
// It reports whether the read was successful.
|
||||
func (s *String) ReadUint24(out *uint32) bool {
|
||||
v := s.read(3)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = uint32(v[0])<<16 | uint32(v[1])<<8 | uint32(v[2])
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUint32 decodes a big-endian, 32-bit value into out and advances over it.
|
||||
// It reports whether the read was successful.
|
||||
func (s *String) ReadUint32(out *uint32) bool {
|
||||
v := s.read(4)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = uint32(v[0])<<24 | uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3])
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUint64 decodes a big-endian, 64-bit value into out and advances over it.
|
||||
// It reports whether the read was successful.
|
||||
func (s *String) ReadUint64(out *uint64) bool {
|
||||
v := s.read(8)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = uint64(v[0])<<56 | uint64(v[1])<<48 | uint64(v[2])<<40 | uint64(v[3])<<32 | uint64(v[4])<<24 | uint64(v[5])<<16 | uint64(v[6])<<8 | uint64(v[7])
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readUnsigned(out *uint32, length int) bool {
|
||||
v := s.read(length)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
var result uint32
|
||||
for i := 0; i < length; i++ {
|
||||
result <<= 8
|
||||
result |= uint32(v[i])
|
||||
}
|
||||
*out = result
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool {
|
||||
lenBytes := s.read(lenLen)
|
||||
if lenBytes == nil {
|
||||
return false
|
||||
}
|
||||
var length uint32
|
||||
for _, b := range lenBytes {
|
||||
length = length << 8
|
||||
length = length | uint32(b)
|
||||
}
|
||||
v := s.read(int(length))
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*outChild = v
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value
|
||||
// into out and advances over it. It reports whether the read was successful.
|
||||
func (s *String) ReadUint8LengthPrefixed(out *String) bool {
|
||||
return s.readLengthPrefixed(1, out)
|
||||
}
|
||||
|
||||
// ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit
|
||||
// length-prefixed value into out and advances over it. It reports whether the
|
||||
// read was successful.
|
||||
func (s *String) ReadUint16LengthPrefixed(out *String) bool {
|
||||
return s.readLengthPrefixed(2, out)
|
||||
}
|
||||
|
||||
// ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit
|
||||
// length-prefixed value into out and advances over it. It reports whether
|
||||
// the read was successful.
|
||||
func (s *String) ReadUint24LengthPrefixed(out *String) bool {
|
||||
return s.readLengthPrefixed(3, out)
|
||||
}
|
||||
|
||||
// ReadBytes reads n bytes into out and advances over them. It reports
|
||||
// whether the read was successful.
|
||||
func (s *String) ReadBytes(out *[]byte, n int) bool {
|
||||
v := s.read(n)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = v
|
||||
return true
|
||||
}
|
||||
|
||||
// CopyBytes copies len(out) bytes into out and advances over them. It reports
|
||||
// whether the copy operation was successful
|
||||
func (s *String) CopyBytes(out []byte) bool {
|
||||
n := len(out)
|
||||
v := s.read(n)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
return copy(out, v) == n
|
||||
}
|
||||
|
||||
// Empty reports whether the string does not contain any bytes.
|
||||
func (s String) Empty() bool {
|
||||
return len(s) == 0
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package hkdf implements the HMAC-based Extract-and-Expand Key Derivation
|
||||
// Function (HKDF) as defined in RFC 5869.
|
||||
//
|
||||
// HKDF is a cryptographic key derivation function (KDF) with the goal of
|
||||
// expanding limited input keying material into one or more cryptographically
|
||||
// strong secret keys.
|
||||
package hkdf // import "golang.org/x/crypto/hkdf"
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"errors"
|
||||
"hash"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Extract generates a pseudorandom key for use with Expand from an input secret
|
||||
// and an optional independent salt.
|
||||
//
|
||||
// Only use this function if you need to reuse the extracted key with multiple
|
||||
// Expand invocations and different context values. Most common scenarios,
|
||||
// including the generation of multiple keys, should use New instead.
|
||||
func Extract(hash func() hash.Hash, secret, salt []byte) []byte {
|
||||
if salt == nil {
|
||||
salt = make([]byte, hash().Size())
|
||||
}
|
||||
extractor := hmac.New(hash, salt)
|
||||
extractor.Write(secret)
|
||||
return extractor.Sum(nil)
|
||||
}
|
||||
|
||||
type hkdf struct {
|
||||
expander hash.Hash
|
||||
size int
|
||||
|
||||
info []byte
|
||||
counter byte
|
||||
|
||||
prev []byte
|
||||
buf []byte
|
||||
}
|
||||
|
||||
func (f *hkdf) Read(p []byte) (int, error) {
|
||||
// Check whether enough data can be generated
|
||||
need := len(p)
|
||||
remains := len(f.buf) + int(255-f.counter+1)*f.size
|
||||
if remains < need {
|
||||
return 0, errors.New("hkdf: entropy limit reached")
|
||||
}
|
||||
// Read any leftover from the buffer
|
||||
n := copy(p, f.buf)
|
||||
p = p[n:]
|
||||
|
||||
// Fill the rest of the buffer
|
||||
for len(p) > 0 {
|
||||
f.expander.Reset()
|
||||
f.expander.Write(f.prev)
|
||||
f.expander.Write(f.info)
|
||||
f.expander.Write([]byte{f.counter})
|
||||
f.prev = f.expander.Sum(f.prev[:0])
|
||||
f.counter++
|
||||
|
||||
// Copy the new batch into p
|
||||
f.buf = f.prev
|
||||
n = copy(p, f.buf)
|
||||
p = p[n:]
|
||||
}
|
||||
// Save leftovers for next run
|
||||
f.buf = f.buf[n:]
|
||||
|
||||
return need, nil
|
||||
}
|
||||
|
||||
// Expand returns a Reader, from which keys can be read, using the given
|
||||
// pseudorandom key and optional context info, skipping the extraction step.
|
||||
//
|
||||
// The pseudorandomKey should have been generated by Extract, or be a uniformly
|
||||
// random or pseudorandom cryptographically strong key. See RFC 5869, Section
|
||||
// 3.3. Most common scenarios will want to use New instead.
|
||||
func Expand(hash func() hash.Hash, pseudorandomKey, info []byte) io.Reader {
|
||||
expander := hmac.New(hash, pseudorandomKey)
|
||||
return &hkdf{expander, expander.Size(), info, 1, nil, nil}
|
||||
}
|
||||
|
||||
// New returns a Reader, from which keys can be read, using the given hash,
|
||||
// secret, salt and context info. Salt and info can be nil.
|
||||
func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader {
|
||||
prk := Extract(hash, secret, salt)
|
||||
return Expand(hash, prk, info)
|
||||
}
|
||||
+1
-5
@@ -88,13 +88,9 @@ func (p *pipe) Write(d []byte) (n int, err error) {
|
||||
p.c.L = &p.mu
|
||||
}
|
||||
defer p.c.Signal()
|
||||
if p.err != nil {
|
||||
if p.err != nil || p.breakErr != nil {
|
||||
return 0, errClosedPipeWrite
|
||||
}
|
||||
if p.breakErr != nil {
|
||||
p.unread += len(d)
|
||||
return len(d), nil // discard when there is no reader
|
||||
}
|
||||
return p.b.Write(d)
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -1822,15 +1822,18 @@ func (sc *serverConn) processData(f *DataFrame) error {
|
||||
}
|
||||
|
||||
if len(data) > 0 {
|
||||
st.bodyBytes += int64(len(data))
|
||||
wrote, err := st.body.Write(data)
|
||||
if err != nil {
|
||||
// The handler has closed the request body.
|
||||
// Return the connection-level flow control for the discarded data,
|
||||
// but not the stream-level flow control.
|
||||
sc.sendWindowUpdate(nil, int(f.Length)-wrote)
|
||||
return sc.countError("body_write_err", streamError(id, ErrCodeStreamClosed))
|
||||
return nil
|
||||
}
|
||||
if wrote != len(data) {
|
||||
panic("internal error: bad Writer")
|
||||
}
|
||||
st.bodyBytes += int64(len(data))
|
||||
}
|
||||
|
||||
// Return any padded flow control now, since we won't
|
||||
|
||||
+6
-5
@@ -560,10 +560,11 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
|
||||
traceGotConn(req, cc, reused)
|
||||
res, err := cc.RoundTrip(req)
|
||||
if err != nil && retry <= 6 {
|
||||
roundTripErr := err
|
||||
if req, err = shouldRetryRequest(req, err); err == nil {
|
||||
// After the first retry, do exponential backoff with 10% jitter.
|
||||
if retry == 0 {
|
||||
t.vlogf("RoundTrip retrying after failure: %v", err)
|
||||
t.vlogf("RoundTrip retrying after failure: %v", roundTripErr)
|
||||
continue
|
||||
}
|
||||
backoff := float64(uint(1) << (uint(retry) - 1))
|
||||
@@ -572,7 +573,7 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
|
||||
timer := backoffNewTimer(d)
|
||||
select {
|
||||
case <-timer.C:
|
||||
t.vlogf("RoundTrip retrying after failure: %v", err)
|
||||
t.vlogf("RoundTrip retrying after failure: %v", roundTripErr)
|
||||
continue
|
||||
case <-req.Context().Done():
|
||||
timer.Stop()
|
||||
@@ -2555,6 +2556,9 @@ func (b transportResponseBody) Close() error {
|
||||
cs := b.cs
|
||||
cc := cs.cc
|
||||
|
||||
cs.bufPipe.BreakWithError(errClosedResponseBody)
|
||||
cs.abortStream(errClosedResponseBody)
|
||||
|
||||
unread := cs.bufPipe.Len()
|
||||
if unread > 0 {
|
||||
cc.mu.Lock()
|
||||
@@ -2573,9 +2577,6 @@ func (b transportResponseBody) Close() error {
|
||||
cc.wmu.Unlock()
|
||||
}
|
||||
|
||||
cs.bufPipe.BreakWithError(errClosedResponseBody)
|
||||
cs.abortStream(errClosedResponseBody)
|
||||
|
||||
select {
|
||||
case <-cs.donec:
|
||||
case <-cs.ctx.Done():
|
||||
|
||||
+8
-4
@@ -19,7 +19,7 @@ See pkg.go.dev for further documentation and examples.
|
||||
* [pkg.go.dev/golang.org/x/oauth2](https://pkg.go.dev/golang.org/x/oauth2)
|
||||
* [pkg.go.dev/golang.org/x/oauth2/google](https://pkg.go.dev/golang.org/x/oauth2/google)
|
||||
|
||||
## Policy for new packages
|
||||
## Policy for new endpoints
|
||||
|
||||
We no longer accept new provider-specific packages in this repo if all
|
||||
they do is add a single endpoint variable. If you just want to add a
|
||||
@@ -29,8 +29,12 @@ package.
|
||||
|
||||
## Report Issues / Send Patches
|
||||
|
||||
This repository uses Gerrit for code changes. To learn how to submit changes to
|
||||
this repository, see https://golang.org/doc/contribute.html.
|
||||
|
||||
The main issue tracker for the oauth2 repository is located at
|
||||
https://github.com/golang/oauth2/issues.
|
||||
|
||||
This repository uses Gerrit for code changes. To learn how to submit changes to
|
||||
this repository, see https://golang.org/doc/contribute.html. In particular:
|
||||
|
||||
* Excluding trivial changes, all contributions should be connected to an existing issue.
|
||||
* API changes must go through the [change proposal process](https://go.dev/s/proposal-process) before they can be accepted.
|
||||
* The code owners are listed at [dev.golang.org/owners](https://dev.golang.org/owners#:~:text=x/oauth2).
|
||||
|
||||
+13
-3
@@ -13,12 +13,15 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/authhandler"
|
||||
)
|
||||
|
||||
const adcSetupURL = "https://cloud.google.com/docs/authentication/external/set-up-adc"
|
||||
|
||||
// Credentials holds Google credentials, including "Application Default Credentials".
|
||||
// For more details, see:
|
||||
// https://developers.google.com/accounts/docs/application-default-credentials
|
||||
@@ -66,6 +69,14 @@ type CredentialsParams struct {
|
||||
// The OAuth2 TokenURL default override. This value overrides the default TokenURL,
|
||||
// unless explicitly specified by the credentials config file. Optional.
|
||||
TokenURL string
|
||||
|
||||
// EarlyTokenRefresh is the amount of time before a token expires that a new
|
||||
// token will be preemptively fetched. If unset the default value is 10
|
||||
// seconds.
|
||||
//
|
||||
// Note: This option is currently only respected when using credentials
|
||||
// fetched from the GCE metadata server.
|
||||
EarlyTokenRefresh time.Duration
|
||||
}
|
||||
|
||||
func (params CredentialsParams) deepCopy() CredentialsParams {
|
||||
@@ -153,13 +164,12 @@ func FindDefaultCredentialsWithParams(ctx context.Context, params CredentialsPar
|
||||
id, _ := metadata.ProjectID()
|
||||
return &Credentials{
|
||||
ProjectID: id,
|
||||
TokenSource: ComputeTokenSource("", params.Scopes...),
|
||||
TokenSource: computeTokenSource("", params.EarlyTokenRefresh, params.Scopes...),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// None are found; return helpful error.
|
||||
const url = "https://developers.google.com/accounts/docs/application-default-credentials"
|
||||
return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url)
|
||||
return nil, fmt.Errorf("google: could not find default credentials. See %v for more information", adcSetupURL)
|
||||
}
|
||||
|
||||
// FindDefaultCredentials invokes FindDefaultCredentialsWithParams with the specified scopes.
|
||||
|
||||
+52
-9
@@ -26,7 +26,7 @@
|
||||
//
|
||||
// Using workload identity federation, your application can access Google Cloud
|
||||
// resources from Amazon Web Services (AWS), Microsoft Azure or any identity
|
||||
// provider that supports OpenID Connect (OIDC).
|
||||
// provider that supports OpenID Connect (OIDC) or SAML 2.0.
|
||||
// Traditionally, applications running outside Google Cloud have used service
|
||||
// account keys to access Google Cloud resources. Using identity federation,
|
||||
// you can allow your workload to impersonate a service account.
|
||||
@@ -36,26 +36,70 @@
|
||||
// Follow the detailed instructions on how to configure Workload Identity Federation
|
||||
// in various platforms:
|
||||
//
|
||||
// Amazon Web Services (AWS): https://cloud.google.com/iam/docs/access-resources-aws
|
||||
// Microsoft Azure: https://cloud.google.com/iam/docs/access-resources-azure
|
||||
// OIDC identity provider: https://cloud.google.com/iam/docs/access-resources-oidc
|
||||
// Amazon Web Services (AWS): https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#aws
|
||||
// Microsoft Azure: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#azure
|
||||
// OIDC identity provider: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#oidc
|
||||
// SAML 2.0 identity provider: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#saml
|
||||
//
|
||||
// For OIDC and SAML providers, the library can retrieve tokens in three ways:
|
||||
// from a local file location (file-sourced credentials), from a server
|
||||
// (URL-sourced credentials), or from a local executable (executable-sourced
|
||||
// credentials).
|
||||
// For file-sourced credentials, a background process needs to be continuously
|
||||
// refreshing the file location with a new OIDC token prior to expiration.
|
||||
// refreshing the file location with a new OIDC/SAML token prior to expiration.
|
||||
// For tokens with one hour lifetimes, the token needs to be updated in the file
|
||||
// every hour. The token can be stored directly as plain text or in JSON format.
|
||||
// For URL-sourced credentials, a local server needs to host a GET endpoint to
|
||||
// return the OIDC token. The response can be in plain text or JSON.
|
||||
// return the OIDC/SAML token. The response can be in plain text or JSON.
|
||||
// Additional required request headers can also be specified.
|
||||
// For executable-sourced credentials, an application needs to be available to
|
||||
// output the OIDC token and other information in a JSON format.
|
||||
// output the OIDC/SAML token and other information in a JSON format.
|
||||
// For more information on how these work (and how to implement
|
||||
// executable-sourced credentials), please check out:
|
||||
// https://cloud.google.com/iam/docs/using-workload-identity-federation#oidc
|
||||
// https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#create_a_credential_configuration
|
||||
//
|
||||
// Note that this library does not perform any validation on the token_url, token_info_url,
|
||||
// or service_account_impersonation_url fields of the credential configuration.
|
||||
// It is not recommended to use a credential configuration that you did not generate with
|
||||
// the gcloud CLI unless you verify that the URL fields point to a googleapis.com domain.
|
||||
//
|
||||
// # Workforce Identity Federation
|
||||
//
|
||||
// Workforce identity federation lets you use an external identity provider (IdP) to
|
||||
// authenticate and authorize a workforce—a group of users, such as employees, partners,
|
||||
// and contractors—using IAM, so that the users can access Google Cloud services.
|
||||
// Workforce identity federation extends Google Cloud's identity capabilities to support
|
||||
// syncless, attribute-based single sign on.
|
||||
//
|
||||
// With workforce identity federation, your workforce can access Google Cloud resources
|
||||
// using an external identity provider (IdP) that supports OpenID Connect (OIDC) or
|
||||
// SAML 2.0 such as Azure Active Directory (Azure AD), Active Directory Federation
|
||||
// Services (AD FS), Okta, and others.
|
||||
//
|
||||
// Follow the detailed instructions on how to configure Workload Identity Federation
|
||||
// in various platforms:
|
||||
//
|
||||
// Azure AD: https://cloud.google.com/iam/docs/workforce-sign-in-azure-ad
|
||||
// Okta: https://cloud.google.com/iam/docs/workforce-sign-in-okta
|
||||
// OIDC identity provider: https://cloud.google.com/iam/docs/configuring-workforce-identity-federation#oidc
|
||||
// SAML 2.0 identity provider: https://cloud.google.com/iam/docs/configuring-workforce-identity-federation#saml
|
||||
//
|
||||
// For workforce identity federation, the library can retrieve tokens in three ways:
|
||||
// from a local file location (file-sourced credentials), from a server
|
||||
// (URL-sourced credentials), or from a local executable (executable-sourced
|
||||
// credentials).
|
||||
// For file-sourced credentials, a background process needs to be continuously
|
||||
// refreshing the file location with a new OIDC/SAML token prior to expiration.
|
||||
// For tokens with one hour lifetimes, the token needs to be updated in the file
|
||||
// every hour. The token can be stored directly as plain text or in JSON format.
|
||||
// For URL-sourced credentials, a local server needs to host a GET endpoint to
|
||||
// return the OIDC/SAML token. The response can be in plain text or JSON.
|
||||
// Additional required request headers can also be specified.
|
||||
// For executable-sourced credentials, an application needs to be available to
|
||||
// output the OIDC/SAML token and other information in a JSON format.
|
||||
// For more information on how these work (and how to implement
|
||||
// executable-sourced credentials), please check out:
|
||||
// https://cloud.google.com/iam/docs/workforce-obtaining-short-lived-credentials#generate_a_configuration_file_for_non-interactive_sign-in
|
||||
//
|
||||
// Note that this library does not perform any validation on the token_url, token_info_url,
|
||||
// or service_account_impersonation_url fields of the credential configuration.
|
||||
@@ -86,5 +130,4 @@
|
||||
// same as the one obtained from the oauth2.Config returned from ConfigFromJSON or
|
||||
// JWTConfigFromJSON, but the Credentials may contain additional information
|
||||
// that is useful is some circumstances.
|
||||
//
|
||||
package google // import "golang.org/x/oauth2/google"
|
||||
|
||||
+5
-1
@@ -231,7 +231,11 @@ func (f *credentialsFile) tokenSource(ctx context.Context, params CredentialsPar
|
||||
// Further information about retrieving access tokens from the GCE metadata
|
||||
// server can be found at https://cloud.google.com/compute/docs/authentication.
|
||||
func ComputeTokenSource(account string, scope ...string) oauth2.TokenSource {
|
||||
return oauth2.ReuseTokenSource(nil, computeSource{account: account, scopes: scope})
|
||||
return computeTokenSource(account, 0, scope...)
|
||||
}
|
||||
|
||||
func computeTokenSource(account string, earlyExpiry time.Duration, scope ...string) oauth2.TokenSource {
|
||||
return oauth2.ReuseTokenSourceWithExpiry(nil, computeSource{account: account, scopes: scope}, earlyExpiry)
|
||||
}
|
||||
|
||||
type computeSource struct {
|
||||
|
||||
+32
-1
@@ -16,6 +16,7 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/oauth2/internal"
|
||||
)
|
||||
@@ -140,7 +141,7 @@ func SetAuthURLParam(key, value string) AuthCodeOption {
|
||||
//
|
||||
// State is a token to protect the user from CSRF attacks. You must
|
||||
// always provide a non-empty string and validate that it matches the
|
||||
// the state query parameter on your redirect callback.
|
||||
// state query parameter on your redirect callback.
|
||||
// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
|
||||
//
|
||||
// Opts may include AccessTypeOnline or AccessTypeOffline, as well
|
||||
@@ -290,6 +291,8 @@ type reuseTokenSource struct {
|
||||
|
||||
mu sync.Mutex // guards t
|
||||
t *Token
|
||||
|
||||
expiryDelta time.Duration
|
||||
}
|
||||
|
||||
// Token returns the current token if it's still valid, else will
|
||||
@@ -305,6 +308,7 @@ func (s *reuseTokenSource) Token() (*Token, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.expiryDelta = s.expiryDelta
|
||||
s.t = t
|
||||
return t, nil
|
||||
}
|
||||
@@ -379,3 +383,30 @@ func ReuseTokenSource(t *Token, src TokenSource) TokenSource {
|
||||
new: src,
|
||||
}
|
||||
}
|
||||
|
||||
// ReuseTokenSource returns a TokenSource that acts in the same manner as the
|
||||
// TokenSource returned by ReuseTokenSource, except the expiry buffer is
|
||||
// configurable. The expiration time of a token is calculated as
|
||||
// t.Expiry.Add(-earlyExpiry).
|
||||
func ReuseTokenSourceWithExpiry(t *Token, src TokenSource, earlyExpiry time.Duration) TokenSource {
|
||||
// Don't wrap a reuseTokenSource in itself. That would work,
|
||||
// but cause an unnecessary number of mutex operations.
|
||||
// Just build the equivalent one.
|
||||
if rt, ok := src.(*reuseTokenSource); ok {
|
||||
if t == nil {
|
||||
// Just use it directly, but set the expiryDelta to earlyExpiry,
|
||||
// so the behavior matches what the user expects.
|
||||
rt.expiryDelta = earlyExpiry
|
||||
return rt
|
||||
}
|
||||
src = rt.new
|
||||
}
|
||||
if t != nil {
|
||||
t.expiryDelta = earlyExpiry
|
||||
}
|
||||
return &reuseTokenSource{
|
||||
t: t,
|
||||
new: src,
|
||||
expiryDelta: earlyExpiry,
|
||||
}
|
||||
}
|
||||
|
||||
+12
-2
@@ -16,10 +16,10 @@ import (
|
||||
"golang.org/x/oauth2/internal"
|
||||
)
|
||||
|
||||
// expiryDelta determines how earlier a token should be considered
|
||||
// defaultExpiryDelta determines how earlier a token should be considered
|
||||
// expired than its actual expiration time. It is used to avoid late
|
||||
// expirations due to client-server time mismatches.
|
||||
const expiryDelta = 10 * time.Second
|
||||
const defaultExpiryDelta = 10 * time.Second
|
||||
|
||||
// Token represents the credentials used to authorize
|
||||
// the requests to access protected resources on the OAuth 2.0
|
||||
@@ -52,6 +52,11 @@ type Token struct {
|
||||
// raw optionally contains extra metadata from the server
|
||||
// when updating a token.
|
||||
raw interface{}
|
||||
|
||||
// expiryDelta is used to calculate when a token is considered
|
||||
// expired, by subtracting from Expiry. If zero, defaultExpiryDelta
|
||||
// is used.
|
||||
expiryDelta time.Duration
|
||||
}
|
||||
|
||||
// Type returns t.TokenType if non-empty, else "Bearer".
|
||||
@@ -127,6 +132,11 @@ func (t *Token) expired() bool {
|
||||
if t.Expiry.IsZero() {
|
||||
return false
|
||||
}
|
||||
|
||||
expiryDelta := defaultExpiryDelta
|
||||
if t.expiryDelta != 0 {
|
||||
expiryDelta = t.expiryDelta
|
||||
}
|
||||
return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow())
|
||||
}
|
||||
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || solaris
|
||||
// +build aix solaris
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// ioctl itself should not be exposed directly, but additional get/set
|
||||
// functions for specific types are permissible.
|
||||
|
||||
// IoctlSetInt performs an ioctl operation which sets an integer value
|
||||
// on fd, using the specified request number.
|
||||
func IoctlSetInt(fd int, req int, value int) error {
|
||||
return ioctl(fd, req, uintptr(value))
|
||||
}
|
||||
|
||||
// IoctlSetPointerInt performs an ioctl operation which sets an
|
||||
// integer value on fd, using the specified request number. The ioctl
|
||||
// argument is called with a pointer to the integer value, rather than
|
||||
// passing the integer value directly.
|
||||
func IoctlSetPointerInt(fd int, req int, value int) error {
|
||||
v := int32(value)
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(&v))
|
||||
}
|
||||
|
||||
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
|
||||
//
|
||||
// To change fd's window size, the req argument should be TIOCSWINSZ.
|
||||
func IoctlSetWinsize(fd int, req int, value *Winsize) error {
|
||||
// TODO: if we get the chance, remove the req parameter and
|
||||
// hardcode TIOCSWINSZ.
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(value))
|
||||
}
|
||||
|
||||
// IoctlSetTermios performs an ioctl on fd with a *Termios.
|
||||
//
|
||||
// The req value will usually be TCSETA or TIOCSETA.
|
||||
func IoctlSetTermios(fd int, req int, value *Termios) error {
|
||||
// TODO: if we get the chance, remove the req parameter.
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(value))
|
||||
}
|
||||
|
||||
// IoctlGetInt performs an ioctl operation which gets an integer value
|
||||
// from fd, using the specified request number.
|
||||
//
|
||||
// A few ioctl requests use the return value as an output parameter;
|
||||
// for those, IoctlRetInt should be used instead of this function.
|
||||
func IoctlGetInt(fd int, req int) (int, error) {
|
||||
var value int
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
|
||||
return value, err
|
||||
}
|
||||
|
||||
func IoctlGetWinsize(fd int, req int) (*Winsize, error) {
|
||||
var value Winsize
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
|
||||
return &value, err
|
||||
}
|
||||
|
||||
func IoctlGetTermios(fd int, req int) (*Termios, error) {
|
||||
var value Termios
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
|
||||
return &value, err
|
||||
}
|
||||
Generated
Vendored
+2
-2
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
|
||||
// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd solaris
|
||||
//go:build darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd
|
||||
// +build darwin dragonfly freebsd hurd linux netbsd openbsd
|
||||
|
||||
package unix
|
||||
|
||||
+6
-6
@@ -17,14 +17,14 @@ import (
|
||||
|
||||
// IoctlSetInt performs an ioctl operation which sets an integer value
|
||||
// on fd, using the specified request number.
|
||||
func IoctlSetInt(fd int, req uint, value int) error {
|
||||
func IoctlSetInt(fd int, req int, value int) error {
|
||||
return ioctl(fd, req, uintptr(value))
|
||||
}
|
||||
|
||||
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
|
||||
//
|
||||
// To change fd's window size, the req argument should be TIOCSWINSZ.
|
||||
func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
|
||||
func IoctlSetWinsize(fd int, req int, value *Winsize) error {
|
||||
// TODO: if we get the chance, remove the req parameter and
|
||||
// hardcode TIOCSWINSZ.
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(value))
|
||||
@@ -33,7 +33,7 @@ func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
|
||||
// IoctlSetTermios performs an ioctl on fd with a *Termios.
|
||||
//
|
||||
// The req value is expected to be TCSETS, TCSETSW, or TCSETSF
|
||||
func IoctlSetTermios(fd int, req uint, value *Termios) error {
|
||||
func IoctlSetTermios(fd int, req int, value *Termios) error {
|
||||
if (req != TCSETS) && (req != TCSETSW) && (req != TCSETSF) {
|
||||
return ENOSYS
|
||||
}
|
||||
@@ -47,13 +47,13 @@ func IoctlSetTermios(fd int, req uint, value *Termios) error {
|
||||
//
|
||||
// A few ioctl requests use the return value as an output parameter;
|
||||
// for those, IoctlRetInt should be used instead of this function.
|
||||
func IoctlGetInt(fd int, req uint) (int, error) {
|
||||
func IoctlGetInt(fd int, req int) (int, error) {
|
||||
var value int
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
|
||||
return value, err
|
||||
}
|
||||
|
||||
func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
|
||||
func IoctlGetWinsize(fd int, req int) (*Winsize, error) {
|
||||
var value Winsize
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
|
||||
return &value, err
|
||||
@@ -62,7 +62,7 @@ func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
|
||||
// IoctlGetTermios performs an ioctl on fd with a *Termios.
|
||||
//
|
||||
// The req value is expected to be TCGETS
|
||||
func IoctlGetTermios(fd int, req uint) (*Termios, error) {
|
||||
func IoctlGetTermios(fd int, req int) (*Termios, error) {
|
||||
var value Termios
|
||||
if req != TCGETS {
|
||||
return &value, ENOSYS
|
||||
|
||||
+2
@@ -66,6 +66,7 @@ includes_Darwin='
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sys_domain.h>
|
||||
@@ -521,6 +522,7 @@ ccflags="$@"
|
||||
$2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ ||
|
||||
$2 ~ /^NFC_.*_(MAX)?SIZE$/ ||
|
||||
$2 ~ /^RAW_PAYLOAD_/ ||
|
||||
$2 ~ /^[US]F_/ ||
|
||||
$2 ~ /^TP_STATUS_/ ||
|
||||
$2 ~ /^FALLOC_/ ||
|
||||
$2 ~ /^ICMPV?6?_(FILTER|SEC)/ ||
|
||||
|
||||
+2
-2
@@ -408,8 +408,8 @@ func (w WaitStatus) CoreDump() bool { return w&0x80 == 0x80 }
|
||||
|
||||
func (w WaitStatus) TrapCause() int { return -1 }
|
||||
|
||||
//sys ioctl(fd int, req uint, arg uintptr) (err error)
|
||||
//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = ioctl
|
||||
//sys ioctl(fd int, req int, arg uintptr) (err error)
|
||||
//sys ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) = ioctl
|
||||
|
||||
// fcntl must never be called with cmd=F_DUP2FD because it doesn't work on AIX
|
||||
// There is no way to create a custom fcntl and to keep //sys fcntl easily,
|
||||
|
||||
-1
@@ -8,7 +8,6 @@
|
||||
package unix
|
||||
|
||||
//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) = getrlimit64
|
||||
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) = setrlimit64
|
||||
//sys Seek(fd int, offset int64, whence int) (off int64, err error) = lseek64
|
||||
|
||||
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
|
||||
|
||||
-1
@@ -8,7 +8,6 @@
|
||||
package unix
|
||||
|
||||
//sysnb Getrlimit(resource int, rlim *Rlimit) (err error)
|
||||
//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
|
||||
//sys Seek(fd int, offset int64, whence int) (off int64, err error) = lseek
|
||||
|
||||
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) = mmap64
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user