diff --git a/.travis.yml b/.travis.yml index 00287d666a5a..0e24e59f0567 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,8 @@ matrix: env: GO111MODULE=on - go: 1.12.x env: GO111MODULE=on + - go: 1.9.x + env: GAE=1 go_import_path: google.golang.org/grpc @@ -28,11 +30,13 @@ before_install: install: - try3() { eval "$*" || eval "$*" || eval "$*"; } - try3 'if [[ "${GO111MODULE}" = "on" ]]; then go mod download; else make testdeps; fi' + - if [[ -n "${GAE}" ]]; then source ./install_gae.sh; make testappenginedeps; fi - if [[ -n "${VET}" ]]; then ./vet.sh -install; fi script: - set -e - if [[ -n "${TESTEXTRAS}" ]]; then examples/examples_test.sh; interop/interop_test.sh; make testsubmodule; exit 0; fi - if [[ -n "${VET}" ]]; then ./vet.sh; fi + - if [[ -n "${GAE}" ]]; then make testappengine; exit 0; fi - if [[ -n "${RACE}" ]]; then make testrace; exit 0; fi - make test diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cd03f8c76888..4f1567e2f95e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -57,5 +57,6 @@ How to get your contributions merged smoothly and quickly. - `make vet` to catch vet errors - `make test` to run the tests - `make testrace` to run tests in race mode + - optional `make testappengine` to run tests with appengine - Exceptions to the rules can be made if there's a compelling reason for doing so. diff --git a/Makefile b/Makefile index cf474ae2fb97..3f661a7879d6 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,12 @@ testsubmodule: testdeps cd security/advancedtls && go test -cpu 1,4 -timeout 7m google.golang.org/grpc/security/advancedtls/... cd security/authorization && go test -cpu 1,4 -timeout 7m google.golang.org/grpc/security/authorization/... +testappengine: testappenginedeps + goapp test -cpu 1,4 -timeout 7m google.golang.org/grpc/... + +testappenginedeps: + goapp get -d -v -t -tags 'appengine appenginevm' google.golang.org/grpc/... + testdeps: go get -d -v -t google.golang.org/grpc/... @@ -48,6 +54,8 @@ vetdeps: deps \ proto \ test \ + testappengine \ + testappenginedeps \ testdeps \ testrace \ updatedeps \ diff --git a/balancer/rls/internal/balancer.go b/balancer/rls/internal/balancer.go index 7af97b76faf1..aeb509aa894b 100644 --- a/balancer/rls/internal/balancer.go +++ b/balancer/rls/internal/balancer.go @@ -1,3 +1,5 @@ +// +build go1.10 + /* * * Copyright 2020 gRPC authors. diff --git a/balancer/rls/internal/balancer_test.go b/balancer/rls/internal/balancer_test.go index d6a98aa9ab00..1c43eb423572 100644 --- a/balancer/rls/internal/balancer_test.go +++ b/balancer/rls/internal/balancer_test.go @@ -1,3 +1,5 @@ +// +build go1.10 + /* * * Copyright 2020 gRPC authors. diff --git a/balancer/rls/internal/builder.go b/balancer/rls/internal/builder.go index 7c29caef4047..c38babff4d3d 100644 --- a/balancer/rls/internal/builder.go +++ b/balancer/rls/internal/builder.go @@ -1,3 +1,5 @@ +// +build go1.10 + /* * * Copyright 2020 gRPC authors. diff --git a/balancer/rls/internal/client_test.go b/balancer/rls/internal/client_test.go index a45850dce11e..1a1a75d1be98 100644 --- a/balancer/rls/internal/client_test.go +++ b/balancer/rls/internal/client_test.go @@ -1,3 +1,5 @@ +// +build go1.10 + /* * * Copyright 2020 gRPC authors. diff --git a/balancer/rls/internal/config.go b/balancer/rls/internal/config.go index 305c09106ba3..624cc59c1f89 100644 --- a/balancer/rls/internal/config.go +++ b/balancer/rls/internal/config.go @@ -1,3 +1,5 @@ +// +build go1.10 + /* * * Copyright 2020 gRPC authors. diff --git a/balancer/rls/internal/config_test.go b/balancer/rls/internal/config_test.go index 1efd054512b2..608412c239a9 100644 --- a/balancer/rls/internal/config_test.go +++ b/balancer/rls/internal/config_test.go @@ -1,3 +1,5 @@ +// +build go1.10 + /* * * Copyright 2020 gRPC authors. diff --git a/balancer/rls/internal/keys/builder.go b/balancer/rls/internal/keys/builder.go index 5ce5a9da508a..abc076ab4da3 100644 --- a/balancer/rls/internal/keys/builder.go +++ b/balancer/rls/internal/keys/builder.go @@ -1,3 +1,5 @@ +// +build go1.10 + /* * * Copyright 2020 gRPC authors. diff --git a/balancer/rls/internal/keys/builder_test.go b/balancer/rls/internal/keys/builder_test.go index a5cad29e0c93..f5e03ac51dd7 100644 --- a/balancer/rls/internal/keys/builder_test.go +++ b/balancer/rls/internal/keys/builder_test.go @@ -1,3 +1,5 @@ +// +build go1.10 + /* * * Copyright 2020 gRPC authors. diff --git a/balancer/rls/internal/picker.go b/balancer/rls/internal/picker.go index 738449446558..72d51de61f30 100644 --- a/balancer/rls/internal/picker.go +++ b/balancer/rls/internal/picker.go @@ -1,3 +1,5 @@ +// +build go1.10 + /* * * Copyright 2020 gRPC authors. diff --git a/balancer/rls/internal/picker_test.go b/balancer/rls/internal/picker_test.go index 1397bf8085d8..9eeed2d53b8a 100644 --- a/balancer/rls/internal/picker_test.go +++ b/balancer/rls/internal/picker_test.go @@ -1,3 +1,5 @@ +// +build go1.10 + /* * * Copyright 2020 gRPC authors. diff --git a/channelz/service/func_linux.go b/channelz/service/func_linux.go index ce38a921b974..cfa457a6a8b1 100644 --- a/channelz/service/func_linux.go +++ b/channelz/service/func_linux.go @@ -1,3 +1,5 @@ +// +build !appengine + /* * * Copyright 2018 gRPC authors. diff --git a/channelz/service/func_nonlinux.go b/channelz/service/func_nonlinux.go index 64ecea947de0..eb53334ed0d1 100644 --- a/channelz/service/func_nonlinux.go +++ b/channelz/service/func_nonlinux.go @@ -1,4 +1,4 @@ -// +build !linux +// +build !linux appengine /* * diff --git a/channelz/service/service_sktopt_test.go b/channelz/service/service_sktopt_test.go index e2d024f83652..1a12ed0ed3cc 100644 --- a/channelz/service/service_sktopt_test.go +++ b/channelz/service/service_sktopt_test.go @@ -1,4 +1,4 @@ -// +build linux +// +build linux,!appengine // +build 386 amd64 /* diff --git a/channelz/service/service_test.go b/channelz/service/service_test.go index 41f4f31a5b94..e6a7d8eba3be 100644 --- a/channelz/service/service_test.go +++ b/channelz/service/service_test.go @@ -58,7 +58,7 @@ type protoToSocketOptFunc func([]*channelzpb.SocketOption) *channelz.SocketOptio // protoToSocketOpt is used in function socketProtoToStruct to extract socket option // data from unmarshaled proto message. -// It is only defined under linux environment on x86 architecture. +// It is only defined under linux, non-appengine environment on x86 architecture. var protoToSocketOpt protoToSocketOptFunc // emptyTime is used for detecting unset value of time.Time type. diff --git a/channelz/service/util_sktopt_386_test.go b/channelz/service/util_sktopt_386_test.go index d9c981271361..cdc2fda4028d 100644 --- a/channelz/service/util_sktopt_386_test.go +++ b/channelz/service/util_sktopt_386_test.go @@ -1,4 +1,4 @@ -// +build 386,linux +// +build 386,linux,!appengine /* * diff --git a/channelz/service/util_sktopt_amd64_test.go b/channelz/service/util_sktopt_amd64_test.go index 0ff06d128330..7ebe9c70eb68 100644 --- a/channelz/service/util_sktopt_amd64_test.go +++ b/channelz/service/util_sktopt_amd64_test.go @@ -1,4 +1,4 @@ -// +build amd64,linux +// +build amd64,linux,!appengine /* * diff --git a/credentials/go12.go b/credentials/go12.go new file mode 100644 index 000000000000..ccbf35b33125 --- /dev/null +++ b/credentials/go12.go @@ -0,0 +1,30 @@ +// +build go1.12 + +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package credentials + +import "crypto/tls" + +// This init function adds cipher suite constants only defined in Go 1.12. +func init() { + cipherSuiteLookup[tls.TLS_AES_128_GCM_SHA256] = "TLS_AES_128_GCM_SHA256" + cipherSuiteLookup[tls.TLS_AES_256_GCM_SHA384] = "TLS_AES_256_GCM_SHA384" + cipherSuiteLookup[tls.TLS_CHACHA20_POLY1305_SHA256] = "TLS_CHACHA20_POLY1305_SHA256" +} diff --git a/credentials/tls.go b/credentials/tls.go index 822429d93db4..48384f5050e7 100644 --- a/credentials/tls.go +++ b/credentials/tls.go @@ -227,8 +227,4 @@ var cipherSuiteLookup = map[uint16]string{ tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", - // Go 1.12 - tls.TLS_AES_128_GCM_SHA256: "TLS_AES_128_GCM_SHA256", - tls.TLS_AES_256_GCM_SHA384: "TLS_AES_256_GCM_SHA384", - tls.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256", } diff --git a/examples/features/xds/client/main.go b/examples/features/xds/client/main.go index b1daa1cae9c8..9a67aabc3764 100644 --- a/examples/features/xds/client/main.go +++ b/examples/features/xds/client/main.go @@ -1,3 +1,5 @@ +// +build go1.11 + /* * * Copyright 2020 gRPC authors. diff --git a/examples/features/xds/server/main.go b/examples/features/xds/server/main.go index 96cd6e468cf5..dd98af5c341e 100644 --- a/examples/features/xds/server/main.go +++ b/examples/features/xds/server/main.go @@ -1,3 +1,5 @@ +// +build go1.11 + /* * * Copyright 2020 gRPC authors. diff --git a/install_gae.sh b/install_gae.sh new file mode 100755 index 000000000000..7c7bcada5044 --- /dev/null +++ b/install_gae.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +TMP=$(mktemp -d /tmp/sdk.XXX) \ +&& curl -o $TMP.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.68.zip" \ +&& unzip -q $TMP.zip -d $TMP \ +&& export PATH="$PATH:$TMP/go_appengine" diff --git a/internal/channelz/types_linux.go b/internal/channelz/types_linux.go index 1b1c4cce34a9..692dd6181778 100644 --- a/internal/channelz/types_linux.go +++ b/internal/channelz/types_linux.go @@ -1,3 +1,5 @@ +// +build !appengine + /* * * Copyright 2018 gRPC authors. diff --git a/internal/channelz/types_nonlinux.go b/internal/channelz/types_nonlinux.go index 501770791524..19c2fc521dcf 100644 --- a/internal/channelz/types_nonlinux.go +++ b/internal/channelz/types_nonlinux.go @@ -1,4 +1,4 @@ -// +build !linux +// +build !linux appengine /* * @@ -37,6 +37,6 @@ type SocketOptionData struct { // Windows OS doesn't support Socket Option func (s *SocketOptionData) Getsockopt(fd uintptr) { once.Do(func() { - logger.Warning("Channelz: socket options are not supported on non-linux os.") + logger.Warning("Channelz: socket options are not supported on non-linux os and appengine.") }) } diff --git a/internal/channelz/util_linux.go b/internal/channelz/util_linux.go index 49432bebf5f4..fdf409d55de3 100644 --- a/internal/channelz/util_linux.go +++ b/internal/channelz/util_linux.go @@ -1,4 +1,4 @@ -// +build linux +// +build linux,!appengine /* * diff --git a/internal/channelz/util_nonlinux.go b/internal/channelz/util_nonlinux.go index d600417fb8c2..8864a0811164 100644 --- a/internal/channelz/util_nonlinux.go +++ b/internal/channelz/util_nonlinux.go @@ -1,4 +1,4 @@ -// +build !linux +// +build !linux appengine /* * diff --git a/internal/channelz/util_test.go b/internal/channelz/util_test.go index 2621e7410d61..9efe3873924c 100644 --- a/internal/channelz/util_test.go +++ b/internal/channelz/util_test.go @@ -1,4 +1,4 @@ -// +build linux +// +build linux,go1.10,!appengine /* * diff --git a/internal/credentials/spiffe.go b/internal/credentials/go110.go similarity index 99% rename from internal/credentials/spiffe.go rename to internal/credentials/go110.go index 406023035288..d688d39c8149 100644 --- a/internal/credentials/spiffe.go +++ b/internal/credentials/go110.go @@ -1,3 +1,5 @@ +// +build go1.10 + /* * * Copyright 2020 gRPC authors. diff --git a/internal/credentials/spiffe_test.go b/internal/credentials/go110_test.go similarity index 99% rename from internal/credentials/spiffe_test.go rename to internal/credentials/go110_test.go index 324874e6e396..19266cced492 100644 --- a/internal/credentials/spiffe_test.go +++ b/internal/credentials/go110_test.go @@ -1,3 +1,5 @@ +// +build go1.10 + /* * * Copyright 2020 gRPC authors. diff --git a/internal/credentials/gobefore110.go b/internal/credentials/gobefore110.go new file mode 100644 index 000000000000..743713e19f8d --- /dev/null +++ b/internal/credentials/gobefore110.go @@ -0,0 +1,31 @@ +// +build !go1.10 + +/* + * + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package credentials + +import ( + "crypto/tls" + "net/url" +) + +//TODO(ZhenLian): delete this file when we remove Go 1.9 tests. +func SPIFFEIDFromState(state tls.ConnectionState) *url.URL { + return nil +} diff --git a/internal/credentials/syscallconn.go b/internal/credentials/syscallconn.go index 2919632d657e..f499a614c20e 100644 --- a/internal/credentials/syscallconn.go +++ b/internal/credentials/syscallconn.go @@ -1,3 +1,5 @@ +// +build !appengine + /* * * Copyright 2018 gRPC authors. diff --git a/internal/credentials/syscallconn_appengine.go b/internal/credentials/syscallconn_appengine.go new file mode 100644 index 000000000000..d4346e9eabe6 --- /dev/null +++ b/internal/credentials/syscallconn_appengine.go @@ -0,0 +1,30 @@ +// +build appengine + +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package internal + +import ( + "net" +) + +// WrapSyscallConn returns newConn on appengine. +func WrapSyscallConn(rawConn, newConn net.Conn) net.Conn { + return newConn +} diff --git a/internal/credentials/syscallconn_test.go b/internal/credentials/syscallconn_test.go index b229a47d116e..ee17a0ca67bc 100644 --- a/internal/credentials/syscallconn_test.go +++ b/internal/credentials/syscallconn_test.go @@ -1,3 +1,5 @@ +// +build !appengine + /* * * Copyright 2018 gRPC authors. diff --git a/internal/profiling/buffer/buffer.go b/internal/profiling/buffer/buffer.go index f4cd4201de11..45745cd09197 100644 --- a/internal/profiling/buffer/buffer.go +++ b/internal/profiling/buffer/buffer.go @@ -1,3 +1,5 @@ +// +build !appengine + /* * * Copyright 2019 gRPC authors. diff --git a/internal/profiling/buffer/buffer_appengine.go b/internal/profiling/buffer/buffer_appengine.go new file mode 100644 index 000000000000..c92599e5b9c0 --- /dev/null +++ b/internal/profiling/buffer/buffer_appengine.go @@ -0,0 +1,43 @@ +// +build appengine + +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package buffer + +// CircularBuffer is a no-op implementation for appengine builds. +// +// Appengine does not support stats because of lack of the support for unsafe +// pointers, which are necessary to efficiently store and retrieve things into +// and from a circular buffer. As a result, Push does not do anything and Drain +// returns an empty slice. +type CircularBuffer struct{} + +// NewCircularBuffer returns a no-op for appengine builds. +func NewCircularBuffer(size uint32) (*CircularBuffer, error) { + return nil, nil +} + +// Push returns a no-op for appengine builds. +func (cb *CircularBuffer) Push(x interface{}) { +} + +// Drain returns a no-op for appengine builds. +func (cb *CircularBuffer) Drain() []interface{} { + return nil +} diff --git a/internal/profiling/buffer/buffer_test.go b/internal/profiling/buffer/buffer_test.go index a7f3b61e4afa..86bd77d4a2e6 100644 --- a/internal/profiling/buffer/buffer_test.go +++ b/internal/profiling/buffer/buffer_test.go @@ -1,3 +1,5 @@ +// +build !appengine + /* * * Copyright 2019 gRPC authors. diff --git a/internal/profiling/profiling_test.go b/internal/profiling/profiling_test.go index a6184a16bb4f..f20654492693 100644 --- a/internal/profiling/profiling_test.go +++ b/internal/profiling/profiling_test.go @@ -1,3 +1,5 @@ +// +build !appengine + /* * * Copyright 2019 gRPC authors. diff --git a/internal/syscall/syscall_linux.go b/internal/syscall/syscall_linux.go index 3743bd45afbc..c50468a0fc89 100644 --- a/internal/syscall/syscall_linux.go +++ b/internal/syscall/syscall_linux.go @@ -1,3 +1,5 @@ +// +build !appengine + /* * * Copyright 2018 gRPC authors. @@ -41,7 +43,7 @@ func GetCPUTime() int64 { return ts.Nano() } -// Rusage is an alias for syscall.Rusage under linux environment. +// Rusage is an alias for syscall.Rusage under linux non-appengine environment. type Rusage syscall.Rusage // GetRusage returns the resource usage of current process. diff --git a/internal/syscall/syscall_nonlinux.go b/internal/syscall/syscall_nonlinux.go index 95b713437489..adae60d65188 100644 --- a/internal/syscall/syscall_nonlinux.go +++ b/internal/syscall/syscall_nonlinux.go @@ -1,4 +1,4 @@ -// +build !linux +// +build !linux appengine /* * @@ -35,40 +35,40 @@ var logger = grpclog.Component("core") func log() { once.Do(func() { - logger.Info("CPU time info is unavailable on non-linux environment.") + logger.Info("CPU time info is unavailable on non-linux or appengine environment.") }) } // GetCPUTime returns the how much CPU time has passed since the start of this process. -// It always returns 0 under non-linux environment. +// It always returns 0 under non-linux or appengine environment. func GetCPUTime() int64 { log() return 0 } -// Rusage is an empty struct under non-linux environment. +// Rusage is an empty struct under non-linux or appengine environment. type Rusage struct{} -// GetRusage is a no-op function under non-linux environment. +// GetRusage is a no-op function under non-linux or appengine environment. func GetRusage() (rusage *Rusage) { log() return nil } // CPUTimeDiff returns the differences of user CPU time and system CPU time used -// between two Rusage structs. It a no-op function for non-linux environment. +// between two Rusage structs. It a no-op function for non-linux or appengine environment. func CPUTimeDiff(first *Rusage, latest *Rusage) (float64, float64) { log() return 0, 0 } -// SetTCPUserTimeout is a no-op function under non-linux environments +// SetTCPUserTimeout is a no-op function under non-linux or appengine environments func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error { log() return nil } -// GetTCPUserTimeout is a no-op function under non-linux environments +// GetTCPUserTimeout is a no-op function under non-linux or appengine environments // a negative return value indicates the operation is not supported func GetTCPUserTimeout(conn net.Conn) (int, error) { log() diff --git a/interop/grpclb_fallback/client.go b/interop/grpclb_fallback/client.go index 853c9a4353f1..ce7cc8e66cde 100644 --- a/interop/grpclb_fallback/client.go +++ b/interop/grpclb_fallback/client.go @@ -1,4 +1,6 @@ // +build linux +// +build !appengine +// +build go1.11 /* * diff --git a/security/advancedtls/sni_110.go b/security/advancedtls/sni_110.go new file mode 100644 index 000000000000..5c9a6ae13a0f --- /dev/null +++ b/security/advancedtls/sni_110.go @@ -0,0 +1,53 @@ +// +build go1.10 + +/* + * + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package advancedtls + +import ( + "crypto/tls" + "fmt" +) + +// buildGetCertificates returns the certificate that matches the SNI field +// for the given ClientHelloInfo, defaulting to the first element of o.GetCertificates. +func buildGetCertificates(clientHello *tls.ClientHelloInfo, o *ServerOptions) (*tls.Certificate, error) { + if o.GetCertificates == nil { + return nil, fmt.Errorf("function GetCertificates must be specified") + } + certificates, err := o.GetCertificates(clientHello) + if err != nil { + return nil, err + } + if len(certificates) == 0 { + return nil, fmt.Errorf("no certificates configured") + } + // If users pass in only one certificate, return that certificate. + if len(certificates) == 1 { + return certificates[0], nil + } + // Choose the SNI certificate using SupportsCertificate. + for _, cert := range certificates { + if err := clientHello.SupportsCertificate(cert); err == nil { + return cert, nil + } + } + // If nothing matches, return the first certificate. + return certificates[0], nil +} diff --git a/security/advancedtls/sni_before_110.go b/security/advancedtls/sni_before_110.go new file mode 100644 index 000000000000..180e3a05d494 --- /dev/null +++ b/security/advancedtls/sni_before_110.go @@ -0,0 +1,41 @@ +// +build !go1.10 + +/* + * + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package advancedtls + +import ( + "crypto/tls" + "fmt" +) + +// buildGetCertificates returns the first element of o.GetCertificates. +func buildGetCertificates(clientHello *tls.ClientHelloInfo, o *ServerOptions) (*tls.Certificate, error) { + if o.GetCertificates == nil { + return nil, fmt.Errorf("function GetCertificates must be specified") + } + certificates, err := o.GetCertificates(clientHello) + if err != nil { + return nil, err + } + if len(certificates) == 0 { + return nil, fmt.Errorf("no certificates configured") + } + return certificates[0], nil +} diff --git a/security/advancedtls/sni_test_110.go b/security/advancedtls/sni_test_110.go new file mode 100644 index 000000000000..130ccde59050 --- /dev/null +++ b/security/advancedtls/sni_test_110.go @@ -0,0 +1,108 @@ +// +build go1.10 + +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package advancedtls + +import ( + "crypto/tls" + "testing" + + "github.com/google/go-cmp/cmp" + "google.golang.org/grpc/security/advancedtls/testdata" +) + +// TestGetCertificatesSNI tests SNI logic for go1.10 and above. +func TestGetCertificatesSNI(t *testing.T) { + // Load server certificates for setting the serverGetCert callback function. + serverCert1, err := tls.LoadX509KeyPair(testdata.Path("server_cert_1.pem"), testdata.Path("server_key_1.pem")) + if err != nil { + t.Fatalf("tls.LoadX509KeyPair(server_cert_1.pem, server_key_1.pem) failed: %v", err) + } + serverCert2, err := tls.LoadX509KeyPair(testdata.Path("server_cert_2.pem"), testdata.Path("server_key_2.pem")) + if err != nil { + t.Fatalf("tls.LoadX509KeyPair(server_cert_2.pem, server_key_2.pem) failed: %v", err) + } + serverCert3, err := tls.LoadX509KeyPair(testdata.Path("server_cert_3.pem"), testdata.Path("server_key_3.pem")) + if err != nil { + t.Fatalf("tls.LoadX509KeyPair(server_cert_3.pem, server_key_3.pem) failed: %v", err) + } + + tests := []struct { + desc string + serverGetCert func(*tls.ClientHelloInfo) ([]*tls.Certificate, error) + serverName string + wantCert tls.Certificate + }{ + { + desc: "Select serverCert1", + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil + }, + // "foo.bar.com" is the common name on server certificate server_cert_1.pem. + serverName: "foo.bar.com", + wantCert: serverCert1, + }, + { + desc: "Select serverCert2", + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil + }, + // "foo.bar.server2.com" is the common name on server certificate server_cert_2.pem. + serverName: "foo.bar.server2.com", + wantCert: serverCert2, + }, + { + desc: "Select serverCert3", + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil + }, + // "google.com" is one of the DNS names on server certificate server_cert_3.pem. + serverName: "google.com", + wantCert: serverCert3, + }, + } + for _, test := range tests { + test := test + t.Run(test.desc, func(t *testing.T) { + serverOptions := &ServerOptions{ + GetCertificates: test.serverGetCert, + } + serverConfig, err := serverOptions.config() + if err != nil { + t.Fatalf("serverOptions.config() failed: %v", err) + } + pointFormatUncompressed := uint8(0) + clientHello := &tls.ClientHelloInfo{ + CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}, + ServerName: test.serverName, + SupportedCurves: []tls.CurveID{tls.CurveP256}, + SupportedPoints: []uint8{pointFormatUncompressed}, + SupportedVersions: []uint16{tls.VersionTLS10}, + } + gotCertificate, err := serverConfig.GetCertificate(clientHello) + if err != nil { + t.Fatalf("serverConfig.GetCertificate(clientHello) failed: %v", err) + } + if !cmp.Equal(gotCertificate, test.wantCert, cmp.AllowUnexported(tls.Certificate{})) { + t.Errorf("GetCertificates() = %v, want %v", gotCertificate, test.wantCert) + } + }) + } +} diff --git a/security/advancedtls/sni_test_before_110.go b/security/advancedtls/sni_test_before_110.go new file mode 100644 index 000000000000..e31e2e6ee759 --- /dev/null +++ b/security/advancedtls/sni_test_before_110.go @@ -0,0 +1,108 @@ +// +build !go1.10 + +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package advancedtls + +import ( + "crypto/tls" + "testing" + + "github.com/google/go-cmp/cmp" + "google.golang.org/grpc/security/advancedtls/testdata" +) + +// TestGetCertificatesSNI tests SNI logic for go1.9. +func TestGetCertificatesSNI(t *testing.T) { + // Load server certificates for setting the serverGetCert callback function. + serverCert1, err := tls.LoadX509KeyPair(testdata.Path("server_cert_1.pem"), testdata.Path("server_key_1.pem")) + if err != nil { + t.Fatalf("tls.LoadX509KeyPair(server_cert_1.pem, server_key_1.pem) failed: %v", err) + } + serverCert2, err := tls.LoadX509KeyPair(testdata.Path("server_cert_2.pem"), testdata.Path("server_key_2.pem")) + if err != nil { + t.Fatalf("tls.LoadX509KeyPair(server_cert_2.pem, server_key_2.pem) failed: %v", err) + } + serverCert3, err := tls.LoadX509KeyPair(testdata.Path("server_cert_3.pem"), testdata.Path("server_key_3.pem")) + if err != nil { + t.Fatalf("tls.LoadX509KeyPair(server_cert_3.pem, server_key_3.pem) failed: %v", err) + } + + tests := []struct { + desc string + serverGetCert func(*tls.ClientHelloInfo) ([]*tls.Certificate, error) + serverName string + wantCert tls.Certificate + }{ + { + desc: "Select serverCert1", + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil + }, + // "foo.bar.com" is the common name on server certificate server_cert_1.pem. + serverName: "foo.bar.com", + wantCert: serverCert1, + }, + { + desc: "Select serverCert2", + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil + }, + // "foo.bar.server2.com" is the common name on server certificate server_cert_2.pem. + serverName: "foo.bar.server2.com", + wantCert: serverCert1, + }, + { + desc: "Select serverCert3", + serverGetCert: func(info *tls.ClientHelloInfo) ([]*tls.Certificate, error) { + return []*tls.Certificate{&serverCert1, &serverCert2, &serverCert3}, nil + }, + // "google.com" is one of the DNS names on server certificate server_cert_3.pem. + serverName: "google.com", + wantCert: serverCert1, + }, + } + for _, test := range tests { + test := test + t.Run(test.desc, func(t *testing.T) { + serverOptions := &ServerOptions{ + GetCertificates: test.serverGetCert, + } + serverConfig, err := serverOptions.config() + if err != nil { + t.Fatalf("serverOptions.config() failed: %v", err) + } + pointFormatUncompressed := uint8(0) + clientHello := &tls.ClientHelloInfo{ + CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}, + ServerName: test.serverName, + SupportedCurves: []tls.CurveID{tls.CurveP256}, + SupportedPoints: []uint8{pointFormatUncompressed}, + SupportedVersions: []uint16{tls.VersionTLS10}, + } + gotCertificate, err := serverConfig.GetCertificate(clientHello) + if err != nil { + t.Fatalf("serverConfig.GetCertificate(clientHello) failed: %v", err) + } + if !cmp.Equal(gotCertificate, test.wantCert, cmp.AllowUnexported(tls.Certificate{})) { + t.Errorf("GetCertificates() = %v, want %v", gotCertificate, test.wantCert) + } + }) + } +} diff --git a/test/channelz_linux_go110_test.go b/test/channelz_linux_go110_test.go index dea374bfc08b..ede329ad6297 100644 --- a/test/channelz_linux_go110_test.go +++ b/test/channelz_linux_go110_test.go @@ -1,4 +1,4 @@ -// +build linux +// +build go1.10,linux,!appengine /* * diff --git a/test/go_vet/vet.go b/test/go_vet/vet.go new file mode 100644 index 000000000000..475e8d683fc3 --- /dev/null +++ b/test/go_vet/vet.go @@ -0,0 +1,53 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * 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. + * + */ + +// vet checks whether files that are supposed to be built on appengine running +// Go 1.10 or earlier import an unsupported package (e.g. "unsafe", "syscall"). +package main + +import ( + "fmt" + "go/build" + "os" +) + +func main() { + fail := false + b := build.Default + b.BuildTags = []string{"appengine", "appenginevm"} + argsWithoutProg := os.Args[1:] + for _, dir := range argsWithoutProg { + p, err := b.Import(".", dir, 0) + if _, ok := err.(*build.NoGoError); ok { + continue + } else if err != nil { + fmt.Printf("build.Import failed due to %v\n", err) + fail = true + continue + } + for _, pkg := range p.Imports { + if pkg == "syscall" || pkg == "unsafe" { + fmt.Printf("Package %s/%s importing %s package without appengine build tag is NOT ALLOWED!\n", p.Dir, p.Name, pkg) + fail = true + } + } + } + if fail { + os.Exit(1) + } +} diff --git a/vet.sh b/vet.sh index c52c1bdbf4c9..f644d832d232 100755 --- a/vet.sh +++ b/vet.sh @@ -92,6 +92,10 @@ not git grep "\(import \|^\s*\)\"github.com/golang/protobuf/ptypes/" -- "*.go" # - Ensure all xds proto imports are renamed to *pb or *grpc. git grep '"github.com/envoyproxy/go-control-plane/envoy' -- '*.go' ':(exclude)*.pb.go' | not grep -v 'pb "\|grpc "' +# - Check imports that are illegal in appengine (until Go 1.11). +# TODO: Remove when we drop Go 1.10 support +go list -f {{.Dir}} ./... | xargs go run test/go_vet/vet.go + # - gofmt, goimports, golint (with exceptions for generated code), go vet. gofmt -s -d -l . 2>&1 | fail_on_output goimports -l . 2>&1 | not grep -vE "\.pb\.go" diff --git a/xds/internal/client/bootstrap/bootstrap_test.go b/xds/internal/client/bootstrap/bootstrap_test.go index 18c28db346be..4a825aa35d84 100644 --- a/xds/internal/client/bootstrap/bootstrap_test.go +++ b/xds/internal/client/bootstrap/bootstrap_test.go @@ -1,3 +1,5 @@ +// +build !appengine + /* * * Copyright 2019 gRPC authors.