├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── example ├── README.md ├── client │ └── client.go ├── echo │ └── echo.go ├── proto │ ├── echo.proto │ └── echo_go_proto │ │ ├── echo.pb.go │ │ └── echo_grpc.pb.go └── server │ └── server.go ├── fallback ├── s2a_fallback.go └── s2a_fallback_test.go ├── go.mod ├── go.sum ├── internal ├── authinfo │ ├── authinfo.go │ └── authinfo_test.go ├── fakehandshaker │ └── service │ │ ├── s2a_service.go │ │ └── s2a_service_test.go ├── handshaker │ ├── handshaker.go │ ├── handshaker_test.go │ └── service │ │ ├── service.go │ │ └── service_test.go ├── proto │ ├── common │ │ └── common.proto │ ├── common_go_proto │ │ └── common.pb.go │ ├── examples │ │ ├── helloworld.proto │ │ └── helloworld_go_proto │ │ │ ├── helloworld.pb.go │ │ │ └── helloworld_grpc.pb.go │ ├── s2a │ │ └── s2a.proto │ ├── s2a_context │ │ └── s2a_context.proto │ ├── s2a_context_go_proto │ │ └── s2a_context.pb.go │ ├── s2a_go_proto │ │ ├── s2a.pb.go │ │ └── s2a_grpc.pb.go │ └── v2 │ │ ├── common │ │ └── common.proto │ │ ├── common_go_proto │ │ └── common.pb.go │ │ ├── s2a │ │ └── s2a.proto │ │ ├── s2a_context │ │ └── s2a_context.proto │ │ ├── s2a_context_go_proto │ │ └── s2a_context.pb.go │ │ └── s2a_go_proto │ │ ├── s2a.pb.go │ │ └── s2a_grpc.pb.go ├── record │ ├── internal │ │ ├── aeadcrypter │ │ │ ├── aeadcrypter.go │ │ │ ├── aesgcm.go │ │ │ ├── aesgcm_test.go │ │ │ ├── chachapoly.go │ │ │ ├── chachapoly_test.go │ │ │ ├── common.go │ │ │ ├── common_test.go │ │ │ ├── testdata │ │ │ │ ├── aes_gcm_wycheproof.json │ │ │ │ └── chacha_poly_wycheproof.json │ │ │ └── testutil │ │ │ │ ├── common.go │ │ │ │ └── wycheproofutil.go │ │ └── halfconn │ │ │ ├── ciphersuite.go │ │ │ ├── ciphersuite_test.go │ │ │ ├── counter.go │ │ │ ├── counter_test.go │ │ │ ├── expander.go │ │ │ ├── expander_test.go │ │ │ ├── halfconn.go │ │ │ └── halfconn_test.go │ ├── record.go │ ├── record_test.go │ ├── ticketsender.go │ └── ticketsender_test.go ├── tokenmanager │ ├── tokenmanager.go │ └── tokenmanager_test.go └── v2 │ ├── README.md │ ├── certverifier │ ├── certverifier.go │ ├── certverifier_test.go │ └── testdata │ │ ├── client_intermediate_cert.der │ │ ├── client_intermediate_cert.pem │ │ ├── client_intermediate_key.pem │ │ ├── client_leaf_cert.der │ │ ├── client_leaf_cert.pem │ │ ├── client_leaf_key.pem │ │ ├── client_root_cert.der │ │ ├── client_root_cert.pem │ │ ├── client_root_key.pem │ │ ├── domain.ext │ │ ├── server_intermediate_cert.der │ │ ├── server_intermediate_cert.pem │ │ ├── server_intermediate_key.pem │ │ ├── server_leaf_cert.der │ │ ├── server_leaf_cert.pem │ │ ├── server_leaf_key.pem │ │ ├── server_root_cert.der │ │ ├── server_root_cert.pem │ │ └── server_root_key.pem │ ├── fakes2av2 │ ├── fakes2av2.go │ ├── fakes2av2_test.go │ └── testdata │ │ ├── client_root_cert.der │ │ ├── client_root_cert.pem │ │ ├── client_root_key.pem │ │ ├── server_root_cert.der │ │ ├── server_root_cert.pem │ │ └── server_root_key.pem │ ├── fakes2av2_server │ └── fakes2av2_server.go │ ├── remotesigner │ ├── remotesigner.go │ ├── remotesigner_test.go │ └── testdata │ │ ├── client_cert.der │ │ ├── client_cert.pem │ │ ├── client_key.pem │ │ ├── server_cert.der │ │ ├── server_cert.pem │ │ └── server_key.pem │ ├── s2av2.go │ ├── s2av2_e2e_test.go │ ├── s2av2_test.go │ ├── testdata │ ├── README.md │ ├── client_cert.pem │ ├── client_key.pem │ ├── server_cert.pem │ └── server_key.pem │ └── tlsconfigstore │ ├── testdata │ ├── client_cert.pem │ ├── client_key.pem │ ├── server_cert.pem │ └── server_key.pem │ ├── tlsconfigstore.go │ └── tlsconfigstore_test.go ├── kokoro ├── gcp_ubuntu │ ├── continuous_gae_test.cfg │ ├── continuous_golang.cfg │ ├── continuous_hygiene.cfg │ ├── kokoro_gae_test.sh │ ├── kokoro_golang_build.sh │ ├── kokoro_hygiene.sh │ ├── presubmit_golang.cfg │ └── presubmit_hygiene.cfg └── macos_external │ ├── continuous_golang.cfg │ ├── kokoro_golang_build.sh │ └── presubmit_golang.cfg ├── retry ├── retry.go └── retry_test.go ├── s2a.go ├── s2a_e2e_test.go ├── s2a_options.go ├── s2a_options_test.go ├── s2a_test.go ├── s2a_utils.go ├── s2a_utils_test.go ├── stream └── s2a_stream.go ├── testdata ├── README.md ├── client_cert.pem ├── client_key.pem ├── config.cnf ├── mds_client.csr ├── mds_client_cert.pem ├── mds_client_key.pem ├── mds_root_cert.pem ├── mds_root_key.pem ├── mds_server.csr ├── mds_server_cert.pem ├── mds_server_key.pem ├── self_signed.csr ├── self_signed_cert.pem ├── self_signed_key.pem ├── server_cert.pem └── server_key.pem └── tools ├── internal_ci ├── run_gae_test.sh ├── run_golang_tests.sh ├── run_hygiene_tests.sh └── test_gae │ ├── app.yaml │ └── main.go └── proto └── regenerate_proto.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore binaries without extension 2 | //example/client/client 3 | //example/server/server 4 | //internal/v2/fakes2av2_server/fakes2av2_server 5 | 6 | .idea/ -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of 9 | experience, education, socio-economic status, nationality, personal appearance, 10 | race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or reject 41 | comments, commits, code, wiki edits, issues, and other contributions that are 42 | not aligned to this Code of Conduct, or to ban temporarily or permanently any 43 | contributor for other behaviors that they deem inappropriate, threatening, 44 | offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | This Code of Conduct also applies outside the project spaces when the Project 56 | Steward has a reasonable belief that an individual's behavior may have a 57 | negative impact on the project or its community. 58 | 59 | ## Conflict Resolution 60 | 61 | We do not believe that all conflict is bad; healthy debate and disagreement 62 | often yield positive results. However, it is never okay to be disrespectful or 63 | to engage in behavior that violates the project’s code of conduct. 64 | 65 | If you see someone violating the code of conduct, you are encouraged to address 66 | the behavior directly with those involved. Many issues can be resolved quickly 67 | and easily, and this gives people more control over the outcome of their 68 | dispute. If you are unable to resolve the matter for any reason, or if the 69 | behavior is threatening or harassing, report it. We are dedicated to providing 70 | an environment where participants feel welcome and safe. 71 | 72 | Reports should be directed to *[PROJECT STEWARD NAME(s) AND EMAIL(s)]*, the 73 | Project Steward(s) for *[PROJECT NAME]*. It is the Project Steward’s duty to 74 | receive and address reported violations of the code of conduct. They will then 75 | work with a committee consisting of representatives from the Open Source 76 | Programs Office and the Google Open Source Strategy team. If for any reason you 77 | are uncomfortable reaching out to the Project Steward, please email 78 | opensource@google.com. 79 | 80 | We will investigate every complaint, but you may not receive a direct response. 81 | We will use our discretion in determining when and how to follow up on reported 82 | incidents, which may range from not taking action to permanent expulsion from 83 | the project and project-sponsored spaces. We will notify the accused of the 84 | report and provide them an opportunity to discuss it before any action is taken. 85 | The identity of the reporter will be omitted from the details of the report 86 | supplied to the accused. In potentially harmful situations, such as ongoing 87 | harassment or threats to anyone's safety, we may take action without notice. 88 | 89 | ## Attribution 90 | 91 | This Code of Conduct is adapted from the Contributor Covenant, version 1.4, 92 | available at 93 | https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 94 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement (CLA). You (or your employer) retain the copyright to your 10 | contribution; this simply gives us permission to use and redistribute your 11 | contributions as part of the project. Head over to 12 | to see your current agreements on file or 13 | to sign a new one. 14 | 15 | You generally only need to submit a CLA once, so if you've already submitted one 16 | (even if it was for a different project), you probably don't need to do it 17 | again. 18 | 19 | ## Code reviews 20 | 21 | All submissions, including submissions by project members, require review. We 22 | use GitHub pull requests for this purpose. Consult 23 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 24 | information on using pull requests. 25 | 26 | ## Community Guidelines 27 | 28 | This project follows 29 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/). 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Secure Session Agent Client Libraries 2 | 3 | The Secure Session Agent is a service that enables a workload to offload select 4 | operations from the mTLS handshake and protects a workload's private key 5 | material from exfiltration. Specifically, the workload asks the Secure Session 6 | Agent for the TLS configuration to use during the handshake, to perform private 7 | key operations, and to validate the peer certificate chain. The Secure Session 8 | Agent's client libraries enable applications to communicate with the Secure 9 | Session Agent during the TLS handshake, and to encrypt traffic to the peer 10 | after the TLS handshake is complete. 11 | 12 | This repository contains the source code for the Secure Session Agent's Go 13 | client libraries, which allow gRPC and HTTP Go applications to use the Secure Session 14 | Agent. 15 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | This example implements a gRPC Go Echo client and server which use self-signed X.509 certificates and s2av2TransportCreds (implementation of 2 | TransportCredentials interface) to establish an mTLS connection. 3 | -------------------------------------------------------------------------------- /example/client/client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2022 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | // Package main establishes a connection with an Echo service. 20 | package main 21 | 22 | import ( 23 | "context" 24 | "flag" 25 | "log" 26 | "time" 27 | 28 | "github.com/google/s2a-go" 29 | "google.golang.org/grpc" 30 | 31 | pb "github.com/google/s2a-go/example/proto/echo_go_proto" 32 | ) 33 | 34 | const ( 35 | defaultTimeout = 10.0 * time.Second 36 | ) 37 | 38 | var ( 39 | serverAddr = flag.String("server_addr", "0.0.0.0:8080", "Echo service address.") 40 | s2aAddr = flag.String("s2a_addr", "0.0.0.0:61365", "S2A service address.") 41 | ) 42 | 43 | func runClient(serverAddr *string) { 44 | creds, err := s2a.NewClientCreds(&s2a.ClientOptions{ 45 | S2AAddress: *s2aAddr, 46 | VerificationMode: s2a.ConnectToGoogle, 47 | LocalIdentity: s2a.NewHostname("test_rsa_client_identity"), 48 | }) 49 | if err != nil { 50 | log.Fatalf("NewClientCreds() failed: %v", err) 51 | } 52 | opts := []grpc.DialOption{ 53 | grpc.WithTransportCredentials(creds), 54 | grpc.WithReturnConnectionError(), 55 | grpc.WithDisableRetry(), 56 | grpc.WithBlock(), 57 | } 58 | conn, err := grpc.Dial(*serverAddr, opts...) 59 | if err != nil { 60 | log.Fatalf("Client: failed to connect: %v", err) 61 | } 62 | defer conn.Close() 63 | c := pb.NewEchoClient(conn) 64 | log.Printf("Client: connected to: %s", *serverAddr) 65 | ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) 66 | defer cancel() 67 | msg := "Hello S2Av2 user!" 68 | r, err := c.Echo(ctx, &pb.EchoRequest{Msg: msg}) 69 | if err != nil { 70 | log.Fatalf("Client: failed to send echo message: %v", err) 71 | } 72 | log.Printf("Client: received message from server: %s", r.GetMsg()) 73 | } 74 | 75 | func main() { 76 | runClient(serverAddr) 77 | } 78 | -------------------------------------------------------------------------------- /example/echo/echo.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2022 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | // Package echo contains the libraries for running an Echo server. 20 | package echo 21 | 22 | import ( 23 | "context" 24 | 25 | pb "github.com/google/s2a-go/example/proto/echo_go_proto" 26 | ) 27 | 28 | // Server is an echo server used for testing. 29 | type Server struct { 30 | pb.UnimplementedEchoServer 31 | } 32 | 33 | // Echo uses the message, Msg, in EchoRequest to formulate EchoResponse. 34 | func (s *Server) Echo(ctx context.Context, req *pb.EchoRequest) (*pb.EchoResponse, error) { 35 | return &pb.EchoResponse{Msg: req.GetMsg()}, nil 36 | } 37 | -------------------------------------------------------------------------------- /example/proto/echo.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2022 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | syntax = "proto3"; 20 | 21 | package s2av2.example.proto; 22 | 23 | option go_package = "github.com/google/s2a/example/proto/echo_go_proto"; 24 | 25 | service Echo { 26 | // The echo service replies back the same message in the request. 27 | rpc Echo(EchoRequest) returns (EchoResponse) {} 28 | } 29 | 30 | message EchoRequest { 31 | string msg = 1; 32 | } 33 | 34 | message EchoResponse { 35 | string msg = 1; 36 | } 37 | -------------------------------------------------------------------------------- /example/proto/echo_go_proto/echo_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // Copyright 2022 Google LLC 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // https://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | 18 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 19 | // versions: 20 | // - protoc-gen-go-grpc v1.4.0 21 | // - protoc v3.21.12 22 | // source: example/proto/echo.proto 23 | 24 | package echo_go_proto 25 | 26 | import ( 27 | context "context" 28 | grpc "google.golang.org/grpc" 29 | codes "google.golang.org/grpc/codes" 30 | status "google.golang.org/grpc/status" 31 | ) 32 | 33 | // This is a compile-time assertion to ensure that this generated file 34 | // is compatible with the grpc package it is being compiled against. 35 | // Requires gRPC-Go v1.62.0 or later. 36 | const _ = grpc.SupportPackageIsVersion8 37 | 38 | const ( 39 | Echo_Echo_FullMethodName = "/s2av2.example.proto.Echo/Echo" 40 | ) 41 | 42 | // EchoClient is the client API for Echo service. 43 | // 44 | // 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. 45 | type EchoClient interface { 46 | // The echo service replies back the same message in the request. 47 | Echo(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoResponse, error) 48 | } 49 | 50 | type echoClient struct { 51 | cc grpc.ClientConnInterface 52 | } 53 | 54 | func NewEchoClient(cc grpc.ClientConnInterface) EchoClient { 55 | return &echoClient{cc} 56 | } 57 | 58 | func (c *echoClient) Echo(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoResponse, error) { 59 | cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) 60 | out := new(EchoResponse) 61 | err := c.cc.Invoke(ctx, Echo_Echo_FullMethodName, in, out, cOpts...) 62 | if err != nil { 63 | return nil, err 64 | } 65 | return out, nil 66 | } 67 | 68 | // EchoServer is the server API for Echo service. 69 | // All implementations must embed UnimplementedEchoServer 70 | // for forward compatibility 71 | type EchoServer interface { 72 | // The echo service replies back the same message in the request. 73 | Echo(context.Context, *EchoRequest) (*EchoResponse, error) 74 | mustEmbedUnimplementedEchoServer() 75 | } 76 | 77 | // UnimplementedEchoServer must be embedded to have forward compatible implementations. 78 | type UnimplementedEchoServer struct { 79 | } 80 | 81 | func (UnimplementedEchoServer) Echo(context.Context, *EchoRequest) (*EchoResponse, error) { 82 | return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") 83 | } 84 | func (UnimplementedEchoServer) mustEmbedUnimplementedEchoServer() {} 85 | 86 | // UnsafeEchoServer may be embedded to opt out of forward compatibility for this service. 87 | // Use of this interface is not recommended, as added methods to EchoServer will 88 | // result in compilation errors. 89 | type UnsafeEchoServer interface { 90 | mustEmbedUnimplementedEchoServer() 91 | } 92 | 93 | func RegisterEchoServer(s grpc.ServiceRegistrar, srv EchoServer) { 94 | s.RegisterService(&Echo_ServiceDesc, srv) 95 | } 96 | 97 | func _Echo_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 98 | in := new(EchoRequest) 99 | if err := dec(in); err != nil { 100 | return nil, err 101 | } 102 | if interceptor == nil { 103 | return srv.(EchoServer).Echo(ctx, in) 104 | } 105 | info := &grpc.UnaryServerInfo{ 106 | Server: srv, 107 | FullMethod: Echo_Echo_FullMethodName, 108 | } 109 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 110 | return srv.(EchoServer).Echo(ctx, req.(*EchoRequest)) 111 | } 112 | return interceptor(ctx, in, info, handler) 113 | } 114 | 115 | // Echo_ServiceDesc is the grpc.ServiceDesc for Echo service. 116 | // It's only intended for direct use with grpc.RegisterService, 117 | // and not to be introspected or modified (even as a copy) 118 | var Echo_ServiceDesc = grpc.ServiceDesc{ 119 | ServiceName: "s2av2.example.proto.Echo", 120 | HandlerType: (*EchoServer)(nil), 121 | Methods: []grpc.MethodDesc{ 122 | { 123 | MethodName: "Echo", 124 | Handler: _Echo_Echo_Handler, 125 | }, 126 | }, 127 | Streams: []grpc.StreamDesc{}, 128 | Metadata: "example/proto/echo.proto", 129 | } 130 | -------------------------------------------------------------------------------- /example/server/server.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2022 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | // Package main runs an Echo service. 20 | package main 21 | 22 | import ( 23 | "flag" 24 | "log" 25 | "net" 26 | 27 | "github.com/google/s2a-go" 28 | "github.com/google/s2a-go/example/echo" 29 | "google.golang.org/grpc" 30 | 31 | pb "github.com/google/s2a-go/example/proto/echo_go_proto" 32 | ) 33 | 34 | var ( 35 | port = flag.String("port", ":8080", "Echo service address port.") 36 | s2aAddr = flag.String("s2a_addr", "0.0.0.0:61365", "S2A service address.") 37 | ) 38 | 39 | func runServer(listenPort *string) { 40 | creds, err := s2a.NewServerCreds(&s2a.ServerOptions{ 41 | S2AAddress: *s2aAddr, 42 | VerificationMode: s2a.ConnectToGoogle, 43 | LocalIdentities: []s2a.Identity{s2a.NewHostname("test_rsa_server_identity")}, 44 | }) 45 | if err != nil { 46 | log.Fatalf("NewClientCreds() failed: %v", err) 47 | } 48 | listener, err := net.Listen("tcp", *port) 49 | if err != nil { 50 | log.Fatalf("Failed to listen on addres %s: %v", *port, err) 51 | } 52 | s := grpc.NewServer(grpc.Creds(creds)) 53 | log.Printf("Server: started gRPC Echo Server at: %s", *port) 54 | pb.RegisterEchoServer(s, &echo.Server{}) 55 | if err := s.Serve(listener); err != nil { 56 | log.Fatalf("Failed to serve: %v", err) 57 | } 58 | } 59 | 60 | func main() { 61 | runServer(port) 62 | } 63 | -------------------------------------------------------------------------------- /fallback/s2a_fallback_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2023 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package fallback 20 | 21 | import ( 22 | "context" 23 | "fmt" 24 | "net" 25 | "reflect" 26 | "testing" 27 | ) 28 | 29 | func TestDefaultFallbackClientHandshakeFunc(t *testing.T) { 30 | testDialContextFunc := func(context.Context, string, string) (net.Conn, error) { 31 | return nil, fmt.Errorf("testDialError") 32 | } 33 | for _, tc := range []struct { 34 | desc string 35 | inputFallbackAddr string 36 | funcInitialized bool 37 | expectedAddr string 38 | expectNilErr bool 39 | }{ 40 | { 41 | "working case, fallback address has port suffix", 42 | "example.com:443", 43 | true, 44 | "example.com:443", 45 | true, 46 | }, 47 | { 48 | "working case, fallback address has no port suffix", 49 | "example.com", 50 | true, 51 | "example.com:443", 52 | 53 | true, 54 | }, 55 | { 56 | "working case, IP address, with port", 57 | "192.168.1.1:443", 58 | true, 59 | "192.168.1.1:443", 60 | 61 | true, 62 | }, 63 | { 64 | "working case, IP address, no port", 65 | "192.168.1.1", 66 | true, 67 | "192.168.1.1:443", 68 | 69 | true, 70 | }, 71 | { 72 | "working case, IPv6 address, with port", 73 | "[2001:db8::1]:443", 74 | true, 75 | "[2001:db8::1]:443", 76 | true, 77 | }, 78 | { 79 | "working case, IPv6 address, no port", 80 | "2001:db8::1", 81 | true, 82 | "[2001:db8::1]:443", 83 | true, 84 | }, 85 | { 86 | "test empty fallback address", 87 | "", 88 | false, 89 | "", 90 | false, 91 | }, 92 | } { 93 | fbFunc, err := defaultFallbackClientHandshakeFuncInternal(tc.inputFallbackAddr, testDialContextFunc) 94 | if got, want := fbFunc != nil, tc.funcInitialized; got != want { 95 | t.Errorf("%v: fallback handshake func is initialized=[%v], want [%v]", tc.desc, got, want) 96 | } 97 | if got, want := err == nil, tc.expectNilErr; got != want { 98 | t.Errorf("%v: got error [%v], want nil error [%v]", tc.desc, err, want) 99 | } 100 | if err == nil { 101 | _, _, err := fbFunc(context.TODO(), "", nil, fmt.Errorf("testS2AError")) 102 | if err == nil { 103 | t.Errorf("%v: expecting an error from the test dial function, got nil instead", tc.desc) 104 | } 105 | expectedErr := fmt.Sprintf("dialing to fallback server %s failed: testDialError; S2A client handshake with error: testS2AError", tc.expectedAddr) 106 | if got, want := err.Error(), expectedErr; got != want { 107 | t.Errorf("%v: fallback handshake got error [%v], want error [%v]", tc.desc, got, want) 108 | } 109 | } 110 | } 111 | } 112 | func TestDefaultFallbackDialerAndAddress(t *testing.T) { 113 | for _, tc := range []struct { 114 | desc string 115 | inputFallbackAddr string 116 | dialerInitialized bool 117 | expectedAddr string 118 | expectNilErr bool 119 | }{ 120 | { 121 | "working case, fallback address has port suffix", 122 | "example.com:443", 123 | true, 124 | "example.com:443", 125 | true, 126 | }, 127 | { 128 | "working case, fallback address has no port suffix", 129 | "example.com", 130 | true, 131 | "example.com:443", 132 | true, 133 | }, 134 | { 135 | "working case, IP address, with port", 136 | "192.168.1.1:443", 137 | true, 138 | "192.168.1.1:443", 139 | true, 140 | }, 141 | { 142 | "working case, IP address, no port", 143 | "192.168.1.1", 144 | true, 145 | "192.168.1.1:443", 146 | true, 147 | }, 148 | { 149 | "working case, IPv6 address, with port", 150 | "[2001:db8::1]:443", 151 | true, 152 | "[2001:db8::1]:443", 153 | true, 154 | }, 155 | { 156 | "working case, IPv6 address, no port", 157 | "2001:db8::1", 158 | true, 159 | "[2001:db8::1]:443", 160 | true, 161 | }, 162 | { 163 | "test empty fallback address", 164 | "", 165 | false, 166 | "", 167 | false, 168 | }, 169 | } { 170 | fbDialer, fbAddr, err := DefaultFallbackDialerAndAddress(tc.inputFallbackAddr) 171 | if got, want := fbDialer != nil, tc.dialerInitialized; got != want { 172 | t.Errorf("%v: fallback dialer is initialized=[%v], want [%v]", tc.desc, got, want) 173 | } 174 | if got, want := fbAddr, tc.expectedAddr; got != want { 175 | t.Errorf("%v: returned fallback address=[%v], want [%v]", tc.desc, got, want) 176 | } 177 | if got, want := err == nil, tc.expectNilErr; got != want { 178 | t.Errorf("%v: got error [%v], want nil error [%v]", tc.desc, err, want) 179 | } 180 | if err == nil { 181 | if !reflect.DeepEqual(fbDialer.Config, &FallbackTLSConfigHTTP) { 182 | t.Errorf("%v: unexpected tls config from fallback dialer: [%v], expected: [%v]", tc.desc, fbDialer.Config, &FallbackTLSConfigHTTP) 183 | } 184 | 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/google/s2a-go 2 | 3 | go 1.20 4 | 5 | require ( 6 | cloud.google.com/go/translate v1.10.3 7 | github.com/google/go-cmp v0.6.0 8 | golang.org/x/crypto v0.31.0 9 | golang.org/x/sync v0.10.0 10 | google.golang.org/api v0.177.0 11 | google.golang.org/appengine v1.6.8 12 | google.golang.org/grpc v1.63.2 13 | google.golang.org/protobuf v1.34.2 14 | ) 15 | 16 | require ( 17 | cloud.google.com/go v0.112.2 // indirect 18 | cloud.google.com/go/auth v0.3.0 // indirect 19 | cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect 20 | cloud.google.com/go/compute/metadata v0.3.0 // indirect 21 | cloud.google.com/go/longrunning v0.5.6 // indirect 22 | github.com/felixge/httpsnoop v1.0.4 // indirect 23 | github.com/go-logr/logr v1.4.1 // indirect 24 | github.com/go-logr/stdr v1.2.2 // indirect 25 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 26 | github.com/golang/protobuf v1.5.4 // indirect 27 | github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect 28 | github.com/googleapis/gax-go/v2 v2.12.3 // indirect 29 | go.opencensus.io v0.24.0 // indirect 30 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect 31 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect 32 | go.opentelemetry.io/otel v1.24.0 // indirect 33 | go.opentelemetry.io/otel/metric v1.24.0 // indirect 34 | go.opentelemetry.io/otel/trace v1.24.0 // indirect 35 | golang.org/x/net v0.33.0 // indirect 36 | golang.org/x/oauth2 v0.19.0 // indirect 37 | golang.org/x/sys v0.28.0 // indirect 38 | golang.org/x/text v0.21.0 // indirect 39 | golang.org/x/time v0.5.0 // indirect 40 | google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6 // indirect 41 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6 // indirect 42 | ) 43 | -------------------------------------------------------------------------------- /internal/authinfo/authinfo.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | // Package authinfo provides authentication and authorization information that 20 | // results from the TLS handshake. 21 | package authinfo 22 | 23 | import ( 24 | "errors" 25 | 26 | commonpb "github.com/google/s2a-go/internal/proto/common_go_proto" 27 | contextpb "github.com/google/s2a-go/internal/proto/s2a_context_go_proto" 28 | grpcpb "github.com/google/s2a-go/internal/proto/s2a_go_proto" 29 | "google.golang.org/grpc/credentials" 30 | ) 31 | 32 | var _ credentials.AuthInfo = (*S2AAuthInfo)(nil) 33 | 34 | const s2aAuthType = "s2a" 35 | 36 | // S2AAuthInfo exposes authentication and authorization information from the 37 | // S2A session result to the gRPC stack. 38 | type S2AAuthInfo struct { 39 | s2aContext *contextpb.S2AContext 40 | commonAuthInfo credentials.CommonAuthInfo 41 | } 42 | 43 | // NewS2AAuthInfo returns a new S2AAuthInfo object from the S2A session result. 44 | func NewS2AAuthInfo(result *grpcpb.SessionResult) (credentials.AuthInfo, error) { 45 | return newS2AAuthInfo(result) 46 | } 47 | 48 | func newS2AAuthInfo(result *grpcpb.SessionResult) (*S2AAuthInfo, error) { 49 | if result == nil { 50 | return nil, errors.New("NewS2aAuthInfo given nil session result") 51 | } 52 | return &S2AAuthInfo{ 53 | s2aContext: &contextpb.S2AContext{ 54 | ApplicationProtocol: result.GetApplicationProtocol(), 55 | TlsVersion: result.GetState().GetTlsVersion(), 56 | Ciphersuite: result.GetState().GetTlsCiphersuite(), 57 | PeerIdentity: result.GetPeerIdentity(), 58 | LocalIdentity: result.GetLocalIdentity(), 59 | PeerCertFingerprint: result.GetPeerCertFingerprint(), 60 | LocalCertFingerprint: result.GetLocalCertFingerprint(), 61 | IsHandshakeResumed: result.GetState().GetIsHandshakeResumed(), 62 | }, 63 | commonAuthInfo: credentials.CommonAuthInfo{SecurityLevel: credentials.PrivacyAndIntegrity}, 64 | }, nil 65 | } 66 | 67 | // AuthType returns the authentication type. 68 | func (s *S2AAuthInfo) AuthType() string { 69 | return s2aAuthType 70 | } 71 | 72 | // ApplicationProtocol returns the application protocol, e.g. "grpc". 73 | func (s *S2AAuthInfo) ApplicationProtocol() string { 74 | return s.s2aContext.GetApplicationProtocol() 75 | } 76 | 77 | // TLSVersion returns the TLS version negotiated during the handshake. 78 | func (s *S2AAuthInfo) TLSVersion() commonpb.TLSVersion { 79 | return s.s2aContext.GetTlsVersion() 80 | } 81 | 82 | // Ciphersuite returns the ciphersuite negotiated during the handshake. 83 | func (s *S2AAuthInfo) Ciphersuite() commonpb.Ciphersuite { 84 | return s.s2aContext.GetCiphersuite() 85 | } 86 | 87 | // PeerIdentity returns the authenticated identity of the peer. 88 | func (s *S2AAuthInfo) PeerIdentity() *commonpb.Identity { 89 | return s.s2aContext.GetPeerIdentity() 90 | } 91 | 92 | // LocalIdentity returns the local identity of the application used during 93 | // session setup. 94 | func (s *S2AAuthInfo) LocalIdentity() *commonpb.Identity { 95 | return s.s2aContext.GetLocalIdentity() 96 | } 97 | 98 | // PeerCertFingerprint returns the SHA256 hash of the peer certificate used in 99 | // the S2A handshake. 100 | func (s *S2AAuthInfo) PeerCertFingerprint() []byte { 101 | return s.s2aContext.GetPeerCertFingerprint() 102 | } 103 | 104 | // LocalCertFingerprint returns the SHA256 hash of the local certificate used 105 | // in the S2A handshake. 106 | func (s *S2AAuthInfo) LocalCertFingerprint() []byte { 107 | return s.s2aContext.GetLocalCertFingerprint() 108 | } 109 | 110 | // IsHandshakeResumed returns true if a cached session was used to resume 111 | // the handshake. 112 | func (s *S2AAuthInfo) IsHandshakeResumed() bool { 113 | return s.s2aContext.GetIsHandshakeResumed() 114 | } 115 | 116 | // SecurityLevel returns the security level of the connection. 117 | func (s *S2AAuthInfo) SecurityLevel() credentials.SecurityLevel { 118 | return s.commonAuthInfo.SecurityLevel 119 | } 120 | -------------------------------------------------------------------------------- /internal/handshaker/service/service.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | // Package service is a utility for calling the S2A handshaker service. 20 | package service 21 | 22 | import ( 23 | "context" 24 | "sync" 25 | 26 | grpc "google.golang.org/grpc" 27 | "google.golang.org/grpc/credentials" 28 | "google.golang.org/grpc/credentials/insecure" 29 | ) 30 | 31 | var ( 32 | // mu guards hsConnMap and hsDialer. 33 | mu sync.Mutex 34 | // hsConnMap represents a mapping from an S2A handshaker service address 35 | // to a corresponding connection to an S2A handshaker service instance. 36 | hsConnMap = make(map[string]*grpc.ClientConn) 37 | // hsDialer will be reassigned in tests. 38 | hsDialer = grpc.DialContext 39 | ) 40 | 41 | // Dial dials the S2A handshaker service. If a connection has already been 42 | // established, this function returns it. Otherwise, a new connection is 43 | // created. 44 | func Dial(ctx context.Context, handshakerServiceAddress string, transportCreds credentials.TransportCredentials) (*grpc.ClientConn, error) { 45 | mu.Lock() 46 | defer mu.Unlock() 47 | 48 | hsConn, ok := hsConnMap[handshakerServiceAddress] 49 | if !ok { 50 | // Create a new connection to the S2A handshaker service. Note that 51 | // this connection stays open until the application is closed. 52 | var grpcOpts []grpc.DialOption 53 | if transportCreds != nil { 54 | grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(transportCreds)) 55 | } else { 56 | grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) 57 | } 58 | var err error 59 | hsConn, err = hsDialer(ctx, handshakerServiceAddress, grpcOpts...) 60 | if err != nil { 61 | return nil, err 62 | } 63 | hsConnMap[handshakerServiceAddress] = hsConn 64 | } 65 | return hsConn, nil 66 | } 67 | -------------------------------------------------------------------------------- /internal/handshaker/service/service_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package service 20 | 21 | import ( 22 | "context" 23 | "crypto/tls" 24 | "testing" 25 | 26 | "google.golang.org/grpc/credentials" 27 | 28 | grpc "google.golang.org/grpc" 29 | ) 30 | 31 | const ( 32 | testAddress1 = "test_address_1" 33 | testAddress2 = "test_address_2" 34 | testAddress3 = "test_address_3" 35 | ) 36 | 37 | func TestDial(t *testing.T) { 38 | defer func() func() { 39 | temp := hsDialer 40 | hsDialer = func(ctx context.Context, target string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { 41 | return &grpc.ClientConn{}, nil 42 | } 43 | return func() { 44 | hsDialer = temp 45 | } 46 | }() 47 | 48 | ctx := context.Background() 49 | 50 | // First call to Dial, it should create a connection to the server running 51 | // at the given address. 52 | conn1, err := Dial(ctx, testAddress1, nil) 53 | if err != nil { 54 | t.Fatalf("first call to Dial(%v) failed: %v", testAddress1, err) 55 | } 56 | if conn1 == nil { 57 | t.Fatalf("first call to Dial(%v)=(nil, _), want not nil", testAddress1) 58 | } 59 | if got, want := hsConnMap[testAddress1], conn1; got != want { 60 | t.Fatalf("hsConnMap[%v] = %v, want %v", testAddress1, got, want) 61 | } 62 | 63 | // Second call to Dial should return conn1 above. 64 | conn2, err := Dial(ctx, testAddress1, nil) 65 | if err != nil { 66 | t.Fatalf("second call to Dial(%v) failed: %v", testAddress1, err) 67 | } 68 | if got, want := conn2, conn1; got != want { 69 | t.Fatalf("second call to Dial(%v)=(%v, _), want (%v, _)", testAddress1, got, want) 70 | } 71 | if got, want := hsConnMap[testAddress1], conn1; got != want { 72 | t.Fatalf("hsConnMap[%v] = %v, want %v", testAddress1, got, want) 73 | } 74 | 75 | // Third call to Dial using a different address should create a new 76 | // connection. 77 | conn3, err := Dial(ctx, testAddress2, nil) 78 | if err != nil { 79 | t.Fatalf("third call to Dial(%v) failed: %v", testAddress2, err) 80 | } 81 | if conn3 == nil { 82 | t.Fatalf("third call to Dial(%v)=(nil, _), want not nil", testAddress2) 83 | } 84 | if got, want := hsConnMap[testAddress2], conn3; got != want { 85 | t.Fatalf("hsConnMap[%v] = %v, want %v", testAddress2, got, want) 86 | } 87 | if got, want := conn2 == conn3, false; got != want { 88 | t.Fatalf("(conn2 == conn3) = %v, want %v", got, want) 89 | } 90 | 91 | // Connect to an address with transportCredentials. 92 | conn4, err := Dial(ctx, testAddress3, credentials.NewTLS(&tls.Config{})) 93 | if err != nil { 94 | t.Fatalf("first call to Dial(%v) failed: %v", testAddress3, err) 95 | } 96 | if conn4 == nil { 97 | t.Fatalf("first call to Dial(%v)=(nil, _), want not nil", testAddress3) 98 | } 99 | if got, want := hsConnMap[testAddress3], conn4; got != want { 100 | t.Fatalf("hsConnMap[%v] = %v, want %v", testAddress3, got, want) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /internal/proto/common/common.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package s2a.proto; 18 | 19 | option go_package = "github.com/google/s2a/internal/proto/common_go_proto"; 20 | 21 | // The ciphersuites supported by S2A. The name determines the confidentiality, 22 | // and authentication ciphers as well as the hash algorithm used for PRF in 23 | // TLS 1.2 or HKDF in TLS 1.3. Thus, the components of the name are: 24 | // - AEAD -- for encryption and authentication, e.g., AES_128_GCM. 25 | // - Hash algorithm -- used in PRF or HKDF, e.g., SHA256. 26 | enum Ciphersuite { 27 | AES_128_GCM_SHA256 = 0; 28 | AES_256_GCM_SHA384 = 1; 29 | CHACHA20_POLY1305_SHA256 = 2; 30 | } 31 | 32 | // The TLS versions supported by S2A's handshaker module. 33 | enum TLSVersion { 34 | TLS1_2 = 0; 35 | TLS1_3 = 1; 36 | } 37 | 38 | message Identity { 39 | oneof identity_oneof { 40 | // The SPIFFE ID of a connection endpoint. 41 | string spiffe_id = 1; 42 | 43 | // The hostname of a connection endpoint. 44 | string hostname = 2; 45 | 46 | // The UID of a connection endpoint. 47 | string uid = 4; 48 | 49 | // The username of a connection endpoint. 50 | string username = 5; 51 | 52 | // The GCP ID of a connection endpoint. 53 | string gcp_id = 6; 54 | } 55 | 56 | // Additional identity-specific attributes. 57 | map attributes = 3; 58 | } 59 | -------------------------------------------------------------------------------- /internal/proto/examples/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package s2a.examples; 18 | 19 | option go_package = "github.com/google/s2a/internal/proto/examples/helloworld_go_proto"; 20 | 21 | // The greeting service definition. 22 | service Greeter { 23 | // A unary RPC. 24 | rpc SayHello(HelloRequest) returns (HelloReply) {} 25 | 26 | // A client-side streaming RPC. 27 | rpc SayHelloManyRequests(stream HelloRequest) returns (HelloReply) {} 28 | 29 | // A server-side streaming RPC. 30 | rpc SayHelloManyReplies(HelloRequest) returns (stream HelloReply) {} 31 | 32 | // A bidirectional streaming RPC. 33 | rpc SayHelloConversation(stream HelloRequest) returns (stream HelloReply) {} 34 | } 35 | 36 | // The request message containing the user's name. 37 | message HelloRequest { 38 | string name = 1; 39 | } 40 | 41 | // The response message containing the greetings 42 | message HelloReply { 43 | string message = 1; 44 | } 45 | -------------------------------------------------------------------------------- /internal/proto/s2a_context/s2a_context.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package s2a.proto; 18 | 19 | option go_package = "github.com/google/s2a/internal/proto/s2a_context_go_proto"; 20 | 21 | import "internal/proto/common/common.proto"; 22 | 23 | message S2AContext { 24 | // The application protocol negotiated for this connection, e.g., 'grpc'. 25 | string application_protocol = 1; 26 | 27 | // The TLS version number that the S2A's handshaker module used to set up the 28 | // session. 29 | TLSVersion tls_version = 2; 30 | 31 | // The TLS ciphersuite negotiated by the S2A's handshaker module. 32 | Ciphersuite ciphersuite = 3; 33 | 34 | // The authenticated identity of the peer. 35 | Identity peer_identity = 4; 36 | 37 | // The local identity used during session setup. This could be: 38 | // - The local identity that the client specifies in ClientSessionStartReq. 39 | // - One of the local identities that the server specifies in 40 | // ServerSessionStartReq. 41 | // - If neither client or server specifies local identities, the S2A picks the 42 | // default one. In this case, this field will contain that identity. 43 | Identity local_identity = 5; 44 | 45 | // The SHA256 hash of the peer certificate used in the handshake. 46 | bytes peer_cert_fingerprint = 6; 47 | 48 | // The SHA256 hash of the local certificate used in the handshake. 49 | bytes local_cert_fingerprint = 7; 50 | 51 | // Set to true if a cached session was reused to resume the handshake. 52 | bool is_handshake_resumed = 8; 53 | } 54 | -------------------------------------------------------------------------------- /internal/proto/v2/common/common.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package s2a.proto.v2; 18 | 19 | option go_package = "github.com/google/s2a/internal/proto/v2/common_go_proto"; 20 | 21 | // The TLS 1.0-1.2 ciphersuites that the application can negotiate when using 22 | // S2A. 23 | enum Ciphersuite { 24 | CIPHERSUITE_UNSPECIFIED = 0; 25 | CIPHERSUITE_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 1; 26 | CIPHERSUITE_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 2; 27 | CIPHERSUITE_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 3; 28 | CIPHERSUITE_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 4; 29 | CIPHERSUITE_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 5; 30 | CIPHERSUITE_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 6; 31 | } 32 | 33 | // The TLS versions supported by S2A's handshaker module. 34 | enum TLSVersion { 35 | TLS_VERSION_UNSPECIFIED = 0; 36 | TLS_VERSION_1_0 = 1; 37 | TLS_VERSION_1_1 = 2; 38 | TLS_VERSION_1_2 = 3; 39 | TLS_VERSION_1_3 = 4; 40 | } 41 | 42 | // The side in the TLS connection. 43 | enum ConnectionSide { 44 | CONNECTION_SIDE_UNSPECIFIED = 0; 45 | CONNECTION_SIDE_CLIENT = 1; 46 | CONNECTION_SIDE_SERVER = 2; 47 | } 48 | 49 | // The ALPN protocols that the application can negotiate during a TLS handshake. 50 | enum AlpnProtocol { 51 | ALPN_PROTOCOL_UNSPECIFIED = 0; 52 | ALPN_PROTOCOL_GRPC = 1; 53 | ALPN_PROTOCOL_HTTP2 = 2; 54 | ALPN_PROTOCOL_HTTP1_1 = 3; 55 | } 56 | 57 | message Identity { 58 | oneof identity_oneof { 59 | // The SPIFFE ID of a connection endpoint. 60 | string spiffe_id = 1; 61 | 62 | // The hostname of a connection endpoint. 63 | string hostname = 2; 64 | 65 | // The UID of a connection endpoint. 66 | string uid = 4; 67 | 68 | // The username of a connection endpoint. 69 | string username = 5; 70 | 71 | // The GCP ID of a connection endpoint. 72 | string gcp_id = 6; 73 | } 74 | 75 | // Additional identity-specific attributes. 76 | map attributes = 3; 77 | } 78 | -------------------------------------------------------------------------------- /internal/proto/v2/s2a_context/s2a_context.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package s2a.proto.v2; 18 | 19 | option go_package = "github.com/google/s2a/internal/proto/v2/s2a_context_go_proto"; 20 | 21 | import "internal/proto/v2/common/common.proto"; 22 | 23 | message S2AContext { 24 | reserved 5, 7, 8; 25 | 26 | // The SPIFFE ID from the peer leaf certificate, if present. 27 | // 28 | // This field is only populated if the leaf certificate is a valid SPIFFE 29 | // SVID; in particular, there is a unique URI SAN and this URI SAN is a valid 30 | // SPIFFE ID. 31 | string leaf_cert_spiffe_id = 1; 32 | 33 | // The URIs that are present in the SubjectAltName extension of the peer leaf 34 | // certificate. 35 | // 36 | // Note that the extracted URIs are not validated and may not be properly 37 | // formatted. 38 | repeated string leaf_cert_uris = 2; 39 | 40 | // The DNSNames that are present in the SubjectAltName extension of the peer 41 | // leaf certificate. 42 | repeated string leaf_cert_dnsnames = 3; 43 | 44 | // The (ordered) list of fingerprints in the certificate chain used to verify 45 | // the given leaf certificate. The order MUST be from leaf certificate 46 | // fingerprint to root certificate fingerprint. 47 | // 48 | // A fingerprint is the base-64 encoding of the SHA256 hash of the 49 | // DER-encoding of a certificate. The list MAY be populated even if the peer 50 | // certificate chain was NOT validated successfully. 51 | repeated string peer_certificate_chain_fingerprints = 4; 52 | 53 | // The local identity used during session setup. 54 | Identity local_identity = 9; 55 | 56 | // The SHA256 hash of the DER-encoding of the local leaf certificate used in 57 | // the handshake. 58 | bytes local_leaf_cert_fingerprint = 6; 59 | } 60 | 61 | -------------------------------------------------------------------------------- /internal/proto/v2/s2a_go_proto/s2a_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 16 | // versions: 17 | // - protoc-gen-go-grpc v1.4.0 18 | // - protoc v3.21.12 19 | // source: internal/proto/v2/s2a/s2a.proto 20 | 21 | package s2a_go_proto 22 | 23 | import ( 24 | context "context" 25 | grpc "google.golang.org/grpc" 26 | codes "google.golang.org/grpc/codes" 27 | status "google.golang.org/grpc/status" 28 | ) 29 | 30 | // This is a compile-time assertion to ensure that this generated file 31 | // is compatible with the grpc package it is being compiled against. 32 | // Requires gRPC-Go v1.62.0 or later. 33 | const _ = grpc.SupportPackageIsVersion8 34 | 35 | const ( 36 | S2AService_SetUpSession_FullMethodName = "/s2a.proto.v2.S2AService/SetUpSession" 37 | ) 38 | 39 | // S2AServiceClient is the client API for S2AService service. 40 | // 41 | // 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. 42 | type S2AServiceClient interface { 43 | // SetUpSession is a bidirectional stream used by applications to offload 44 | // operations from the TLS handshake. 45 | SetUpSession(ctx context.Context, opts ...grpc.CallOption) (S2AService_SetUpSessionClient, error) 46 | } 47 | 48 | type s2AServiceClient struct { 49 | cc grpc.ClientConnInterface 50 | } 51 | 52 | func NewS2AServiceClient(cc grpc.ClientConnInterface) S2AServiceClient { 53 | return &s2AServiceClient{cc} 54 | } 55 | 56 | func (c *s2AServiceClient) SetUpSession(ctx context.Context, opts ...grpc.CallOption) (S2AService_SetUpSessionClient, error) { 57 | cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) 58 | stream, err := c.cc.NewStream(ctx, &S2AService_ServiceDesc.Streams[0], S2AService_SetUpSession_FullMethodName, cOpts...) 59 | if err != nil { 60 | return nil, err 61 | } 62 | x := &s2AServiceSetUpSessionClient{ClientStream: stream} 63 | return x, nil 64 | } 65 | 66 | type S2AService_SetUpSessionClient interface { 67 | Send(*SessionReq) error 68 | Recv() (*SessionResp, error) 69 | grpc.ClientStream 70 | } 71 | 72 | type s2AServiceSetUpSessionClient struct { 73 | grpc.ClientStream 74 | } 75 | 76 | func (x *s2AServiceSetUpSessionClient) Send(m *SessionReq) error { 77 | return x.ClientStream.SendMsg(m) 78 | } 79 | 80 | func (x *s2AServiceSetUpSessionClient) Recv() (*SessionResp, error) { 81 | m := new(SessionResp) 82 | if err := x.ClientStream.RecvMsg(m); err != nil { 83 | return nil, err 84 | } 85 | return m, nil 86 | } 87 | 88 | // S2AServiceServer is the server API for S2AService service. 89 | // All implementations must embed UnimplementedS2AServiceServer 90 | // for forward compatibility 91 | type S2AServiceServer interface { 92 | // SetUpSession is a bidirectional stream used by applications to offload 93 | // operations from the TLS handshake. 94 | SetUpSession(S2AService_SetUpSessionServer) error 95 | mustEmbedUnimplementedS2AServiceServer() 96 | } 97 | 98 | // UnimplementedS2AServiceServer must be embedded to have forward compatible implementations. 99 | type UnimplementedS2AServiceServer struct { 100 | } 101 | 102 | func (UnimplementedS2AServiceServer) SetUpSession(S2AService_SetUpSessionServer) error { 103 | return status.Errorf(codes.Unimplemented, "method SetUpSession not implemented") 104 | } 105 | func (UnimplementedS2AServiceServer) mustEmbedUnimplementedS2AServiceServer() {} 106 | 107 | // UnsafeS2AServiceServer may be embedded to opt out of forward compatibility for this service. 108 | // Use of this interface is not recommended, as added methods to S2AServiceServer will 109 | // result in compilation errors. 110 | type UnsafeS2AServiceServer interface { 111 | mustEmbedUnimplementedS2AServiceServer() 112 | } 113 | 114 | func RegisterS2AServiceServer(s grpc.ServiceRegistrar, srv S2AServiceServer) { 115 | s.RegisterService(&S2AService_ServiceDesc, srv) 116 | } 117 | 118 | func _S2AService_SetUpSession_Handler(srv interface{}, stream grpc.ServerStream) error { 119 | return srv.(S2AServiceServer).SetUpSession(&s2AServiceSetUpSessionServer{ServerStream: stream}) 120 | } 121 | 122 | type S2AService_SetUpSessionServer interface { 123 | Send(*SessionResp) error 124 | Recv() (*SessionReq, error) 125 | grpc.ServerStream 126 | } 127 | 128 | type s2AServiceSetUpSessionServer struct { 129 | grpc.ServerStream 130 | } 131 | 132 | func (x *s2AServiceSetUpSessionServer) Send(m *SessionResp) error { 133 | return x.ServerStream.SendMsg(m) 134 | } 135 | 136 | func (x *s2AServiceSetUpSessionServer) Recv() (*SessionReq, error) { 137 | m := new(SessionReq) 138 | if err := x.ServerStream.RecvMsg(m); err != nil { 139 | return nil, err 140 | } 141 | return m, nil 142 | } 143 | 144 | // S2AService_ServiceDesc is the grpc.ServiceDesc for S2AService service. 145 | // It's only intended for direct use with grpc.RegisterService, 146 | // and not to be introspected or modified (even as a copy) 147 | var S2AService_ServiceDesc = grpc.ServiceDesc{ 148 | ServiceName: "s2a.proto.v2.S2AService", 149 | HandlerType: (*S2AServiceServer)(nil), 150 | Methods: []grpc.MethodDesc{}, 151 | Streams: []grpc.StreamDesc{ 152 | { 153 | StreamName: "SetUpSession", 154 | Handler: _S2AService_SetUpSession_Handler, 155 | ServerStreams: true, 156 | ClientStreams: true, 157 | }, 158 | }, 159 | Metadata: "internal/proto/v2/s2a/s2a.proto", 160 | } 161 | -------------------------------------------------------------------------------- /internal/record/internal/aeadcrypter/aeadcrypter.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | // Package aeadcrypter provides the interface for AEAD cipher implementations 20 | // used by S2A's record protocol. 21 | package aeadcrypter 22 | 23 | // S2AAEADCrypter is the interface for an AEAD cipher used by the S2A record 24 | // protocol. 25 | type S2AAEADCrypter interface { 26 | // Encrypt encrypts the plaintext and computes the tag of dst and plaintext. 27 | // dst and plaintext may fully overlap or not at all. 28 | Encrypt(dst, plaintext, nonce, aad []byte) ([]byte, error) 29 | // Decrypt decrypts ciphertext and verifies the tag. dst and ciphertext may 30 | // fully overlap or not at all. 31 | Decrypt(dst, ciphertext, nonce, aad []byte) ([]byte, error) 32 | // TagSize returns the tag size in bytes. 33 | TagSize() int 34 | } 35 | -------------------------------------------------------------------------------- /internal/record/internal/aeadcrypter/aesgcm.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package aeadcrypter 20 | 21 | import ( 22 | "crypto/aes" 23 | "crypto/cipher" 24 | "fmt" 25 | ) 26 | 27 | // Supported key sizes in bytes. 28 | const ( 29 | AES128GCMKeySize = 16 30 | AES256GCMKeySize = 32 31 | ) 32 | 33 | // aesgcm is the struct that holds an AES-GCM cipher for the S2A AEAD crypter. 34 | type aesgcm struct { 35 | aead cipher.AEAD 36 | } 37 | 38 | // NewAESGCM creates an AES-GCM crypter instance. Note that the key must be 39 | // either 128 bits or 256 bits. 40 | func NewAESGCM(key []byte) (S2AAEADCrypter, error) { 41 | if len(key) != AES128GCMKeySize && len(key) != AES256GCMKeySize { 42 | return nil, fmt.Errorf("%d or %d bytes, given: %d", AES128GCMKeySize, AES256GCMKeySize, len(key)) 43 | } 44 | c, err := aes.NewCipher(key) 45 | if err != nil { 46 | return nil, err 47 | } 48 | a, err := cipher.NewGCM(c) 49 | if err != nil { 50 | return nil, err 51 | } 52 | return &aesgcm{aead: a}, nil 53 | } 54 | 55 | // Encrypt is the encryption function. dst can contain bytes at the beginning of 56 | // the ciphertext that will not be encrypted but will be authenticated. If dst 57 | // has enough capacity to hold these bytes, the ciphertext and the tag, no 58 | // allocation and copy operations will be performed. dst and plaintext may 59 | // fully overlap or not at all. 60 | func (s *aesgcm) Encrypt(dst, plaintext, nonce, aad []byte) ([]byte, error) { 61 | return encrypt(s.aead, dst, plaintext, nonce, aad) 62 | } 63 | 64 | func (s *aesgcm) Decrypt(dst, ciphertext, nonce, aad []byte) ([]byte, error) { 65 | return decrypt(s.aead, dst, ciphertext, nonce, aad) 66 | } 67 | 68 | func (s *aesgcm) TagSize() int { 69 | return TagSize 70 | } 71 | -------------------------------------------------------------------------------- /internal/record/internal/aeadcrypter/chachapoly.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package aeadcrypter 20 | 21 | import ( 22 | "crypto/cipher" 23 | "fmt" 24 | 25 | "golang.org/x/crypto/chacha20poly1305" 26 | ) 27 | 28 | // Supported key size in bytes. 29 | const ( 30 | Chacha20Poly1305KeySize = 32 31 | ) 32 | 33 | // chachapoly is the struct that holds a CHACHA-POLY cipher for the S2A AEAD 34 | // crypter. 35 | type chachapoly struct { 36 | aead cipher.AEAD 37 | } 38 | 39 | // NewChachaPoly creates a Chacha-Poly crypter instance. Note that the key must 40 | // be Chacha20Poly1305KeySize bytes in length. 41 | func NewChachaPoly(key []byte) (S2AAEADCrypter, error) { 42 | if len(key) != Chacha20Poly1305KeySize { 43 | return nil, fmt.Errorf("%d bytes, given: %d", Chacha20Poly1305KeySize, len(key)) 44 | } 45 | c, err := chacha20poly1305.New(key) 46 | if err != nil { 47 | return nil, err 48 | } 49 | return &chachapoly{aead: c}, nil 50 | } 51 | 52 | // Encrypt is the encryption function. dst can contain bytes at the beginning of 53 | // the ciphertext that will not be encrypted but will be authenticated. If dst 54 | // has enough capacity to hold these bytes, the ciphertext and the tag, no 55 | // allocation and copy operations will be performed. dst and plaintext may 56 | // fully overlap or not at all. 57 | func (s *chachapoly) Encrypt(dst, plaintext, nonce, aad []byte) ([]byte, error) { 58 | return encrypt(s.aead, dst, plaintext, nonce, aad) 59 | } 60 | 61 | func (s *chachapoly) Decrypt(dst, ciphertext, nonce, aad []byte) ([]byte, error) { 62 | return decrypt(s.aead, dst, ciphertext, nonce, aad) 63 | } 64 | 65 | func (s *chachapoly) TagSize() int { 66 | return TagSize 67 | } 68 | -------------------------------------------------------------------------------- /internal/record/internal/aeadcrypter/common.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package aeadcrypter 20 | 21 | import ( 22 | "crypto/cipher" 23 | "fmt" 24 | ) 25 | 26 | const ( 27 | // TagSize is the tag size in bytes for AES-128-GCM-SHA256, 28 | // AES-256-GCM-SHA384, and CHACHA20-POLY1305-SHA256. 29 | TagSize = 16 30 | // NonceSize is the size of the nonce in number of bytes for 31 | // AES-128-GCM-SHA256, AES-256-GCM-SHA384, and CHACHA20-POLY1305-SHA256. 32 | NonceSize = 12 33 | // SHA256DigestSize is the digest size of sha256 in bytes. 34 | SHA256DigestSize = 32 35 | // SHA384DigestSize is the digest size of sha384 in bytes. 36 | SHA384DigestSize = 48 37 | ) 38 | 39 | // sliceForAppend takes a slice and a requested number of bytes. It returns a 40 | // slice with the contents of the given slice followed by that many bytes and a 41 | // second slice that aliases into it and contains only the extra bytes. If the 42 | // original slice has sufficient capacity then no allocation is performed. 43 | func sliceForAppend(in []byte, n int) (head, tail []byte) { 44 | if total := len(in) + n; cap(in) >= total { 45 | head = in[:total] 46 | } else { 47 | head = make([]byte, total) 48 | copy(head, in) 49 | } 50 | tail = head[len(in):] 51 | return head, tail 52 | } 53 | 54 | // encrypt is the encryption function for an AEAD crypter. aead determines 55 | // the type of AEAD crypter. dst can contain bytes at the beginning of the 56 | // ciphertext that will not be encrypted but will be authenticated. If dst has 57 | // enough capacity to hold these bytes, the ciphertext and the tag, no 58 | // allocation and copy operations will be performed. dst and plaintext may 59 | // fully overlap or not at all. 60 | func encrypt(aead cipher.AEAD, dst, plaintext, nonce, aad []byte) ([]byte, error) { 61 | if len(nonce) != NonceSize { 62 | return nil, fmt.Errorf("nonce size must be %d bytes. received: %d", NonceSize, len(nonce)) 63 | } 64 | // If we need to allocate an output buffer, we want to include space for 65 | // the tag to avoid forcing the caller to reallocate as well. 66 | dlen := len(dst) 67 | dst, out := sliceForAppend(dst, len(plaintext)+TagSize) 68 | data := out[:len(plaintext)] 69 | copy(data, plaintext) // data may fully overlap plaintext 70 | 71 | // Seal appends the ciphertext and the tag to its first argument and 72 | // returns the updated slice. However, sliceForAppend above ensures that 73 | // dst has enough capacity to avoid a reallocation and copy due to the 74 | // append. 75 | dst = aead.Seal(dst[:dlen], nonce, data, aad) 76 | return dst, nil 77 | } 78 | 79 | // decrypt is the decryption function for an AEAD crypter, where aead determines 80 | // the type of AEAD crypter, and dst the destination bytes for the decrypted 81 | // ciphertext. The dst buffer may fully overlap with plaintext or not at all. 82 | func decrypt(aead cipher.AEAD, dst, ciphertext, nonce, aad []byte) ([]byte, error) { 83 | if len(nonce) != NonceSize { 84 | return nil, fmt.Errorf("nonce size must be %d bytes. received: %d", NonceSize, len(nonce)) 85 | } 86 | // If dst is equal to ciphertext[:0], ciphertext storage is reused. 87 | plaintext, err := aead.Open(dst, nonce, ciphertext, aad) 88 | if err != nil { 89 | return nil, fmt.Errorf("message auth failed: %v", err) 90 | } 91 | return plaintext, nil 92 | } 93 | -------------------------------------------------------------------------------- /internal/record/internal/aeadcrypter/common_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package aeadcrypter 20 | 21 | import ( 22 | "bytes" 23 | "testing" 24 | 25 | "github.com/google/s2a-go/internal/record/internal/aeadcrypter/testutil" 26 | ) 27 | 28 | // fakeAEAD is a fake implementation of an AEAD interface used for testing. 29 | type fakeAEAD struct{} 30 | 31 | func (*fakeAEAD) NonceSize() int { return NonceSize } 32 | func (*fakeAEAD) Overhead() int { return TagSize } 33 | func (*fakeAEAD) Seal(_, _, plaintext, _ []byte) []byte { return plaintext } 34 | func (*fakeAEAD) Open(_, _, ciphertext, _ []byte) ([]byte, error) { return ciphertext, nil } 35 | 36 | type encryptDecryptTestVector struct { 37 | desc string 38 | nonce []byte 39 | outErr bool 40 | } 41 | 42 | func TestSliceForAppend(t *testing.T) { 43 | for _, tc := range []struct { 44 | desc string 45 | inBuf []byte 46 | n int 47 | }{ 48 | { 49 | desc: "nil buf and zero length", 50 | }, 51 | { 52 | desc: "nil buf and non-zero length", 53 | n: 5, 54 | }, 55 | { 56 | desc: "non-empty buf and zero length", 57 | inBuf: testutil.Dehex("1111111111"), 58 | }, 59 | { 60 | desc: "non-empty buf and non-zero length", 61 | inBuf: testutil.Dehex("1111111111"), 62 | n: 5, 63 | }, 64 | { 65 | desc: "test slice capacity pre allocated", 66 | inBuf: make([]byte, 0, 5), 67 | n: 5, 68 | }, 69 | } { 70 | t.Run(tc.desc, func(t *testing.T) { 71 | head, tail := sliceForAppend(tc.inBuf, tc.n) 72 | // Check that the resulting head buffer starts with the same byte 73 | // sequence as the input buffer. 74 | if got, want := head, tc.inBuf; !bytes.HasPrefix(head, tc.inBuf) { 75 | t.Errorf("sliceForAppend(%v, %v).head = %v, want %v", tc.inBuf, tc.n, got, want) 76 | } 77 | // Check that the length of the resulting head buffer is equal 78 | // to the initial buffer + the additional length requested. 79 | if got, want := len(head), len(tc.inBuf)+tc.n; got != want { 80 | t.Errorf("sliceForAppend(%v, %v).tail = %v, want %v", tc.inBuf, tc.n, got, want) 81 | } 82 | // Check that the length of the resulting tail buffer is what was 83 | // requested. 84 | if got, want := len(tail), tc.n; got != want { 85 | t.Errorf("sliceForAppend(%v, %v).tail = %v, want %v", tc.inBuf, tc.n, got, want) 86 | } 87 | }) 88 | } 89 | } 90 | 91 | func TestEncrypt(t *testing.T) { 92 | plaintext := []byte("test") 93 | for _, tc := range []encryptDecryptTestVector{ 94 | { 95 | desc: "valid nonce size", 96 | nonce: make([]byte, NonceSize), 97 | }, 98 | { 99 | desc: "invalid nonce size", 100 | nonce: make([]byte, 1), 101 | outErr: true, 102 | }, 103 | } { 104 | ciphertext, err := encrypt(&fakeAEAD{}, nil, plaintext, tc.nonce, nil) 105 | if got, want := err == nil, !tc.outErr; got != want { 106 | t.Fatalf("encrypt(&fakeAEAD{}, nil, %v, %v, nil)=(err=nil)=%v, want %v", plaintext, tc.nonce, got, want) 107 | } 108 | if got, want := ciphertext, plaintext; err == nil && !bytes.Equal(got, want) { 109 | t.Fatalf("encrypt(&fakeAEAD{}, nil, %v, %v, nil) = %v, want %v", plaintext, tc.nonce, got, want) 110 | } 111 | } 112 | } 113 | 114 | func TestDecrypt(t *testing.T) { 115 | ciphertext := []byte("test") 116 | for _, tc := range []encryptDecryptTestVector{ 117 | { 118 | desc: "valid nonce size", 119 | nonce: make([]byte, NonceSize), 120 | }, 121 | { 122 | desc: "invalid nonce size", 123 | nonce: make([]byte, 1), 124 | outErr: true, 125 | }, 126 | } { 127 | plaintext, err := decrypt(&fakeAEAD{}, nil, ciphertext, tc.nonce, nil) 128 | if got, want := err == nil, !tc.outErr; got != want { 129 | t.Fatalf("decrypt(&fakeAEAD{}, nil, %v, %v, nil)=(err=nil)=%v, want %v", ciphertext, tc.nonce, got, want) 130 | } 131 | if got, want := plaintext, ciphertext; err == nil && !bytes.Equal(got, want) { 132 | t.Fatalf("decrypt(&fakeAEAD{}, nil, %v, %v, nil) = %v, want %v", ciphertext, tc.nonce, got, want) 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /internal/record/internal/aeadcrypter/testutil/common.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | // Package testutil is a collection of test utilities for the AEAD crypter. 20 | package testutil 21 | 22 | import ( 23 | "encoding/hex" 24 | ) 25 | 26 | // Constants indicating whether the test vector is valid or not. 27 | const ( 28 | ValidResult = "valid" 29 | InvalidResult = "invalid" 30 | ) 31 | 32 | // CryptoTestVector is a struct representing a test vector for an S2AAEADCrypter 33 | // instance. 34 | type CryptoTestVector struct { 35 | Desc string 36 | ID int 37 | Key, Plaintext, Ciphertext, Tag, Nonce, Aad []byte 38 | Result string 39 | AllocateDst bool 40 | } 41 | 42 | // TestVector is a struct for a WycheProof test vector. 43 | type TestVector struct { 44 | TcID int `json:"tcId"` 45 | Comment string `json:"comment"` 46 | Key string `json:"key"` 47 | IV string `json:"iv"` 48 | Aad string `json:"aad"` 49 | Msg string `json:"msg"` 50 | Ct string `json:"ct"` 51 | Tag string `json:"tag"` 52 | Result string `json:"result"` 53 | } 54 | 55 | // TestGroup is a struct for a WycheProof test group. 56 | type TestGroup struct { 57 | IVSize int `json:"ivSize"` 58 | KeySize int `json:"keySize"` 59 | TagSize int `json:"tagSize"` 60 | Tests []TestVector `json:"tests"` 61 | } 62 | 63 | // TestFile is a struct for a WycheProof test file. 64 | type TestFile struct { 65 | TestGroups []TestGroup `json:"testGroups"` 66 | } 67 | 68 | // Dehex converts a byte string into a byte array. 69 | func Dehex(s string) []byte { 70 | if len(s) == 0 { 71 | return make([]byte, 0) 72 | } 73 | b, err := hex.DecodeString(s) 74 | if err != nil { 75 | panic(err) 76 | } 77 | return b 78 | } 79 | -------------------------------------------------------------------------------- /internal/record/internal/aeadcrypter/testutil/wycheproofutil.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package testutil 20 | 21 | import ( 22 | "bytes" 23 | "encoding/json" 24 | "os" 25 | "testing" 26 | ) 27 | 28 | // ParseWycheProofTestVectors takes a path to a WycheProof test vector, a test 29 | // group filter, and returns the resulting CryptoTestVector. The test group 30 | // filter will be used to filter out unsupported test inputs. 31 | func ParseWycheProofTestVectors(jsonFilePath string, shouldFilter func(TestGroup) bool, t *testing.T) []CryptoTestVector { 32 | jsonFile, err := os.Open(jsonFilePath) 33 | if err != nil { 34 | t.Fatalf("failed to open wycheproof json test vectors file: %v", err) 35 | } 36 | defer jsonFile.Close() 37 | 38 | dec := json.NewDecoder(jsonFile) 39 | 40 | var tf TestFile 41 | if err = dec.Decode(&tf); err != nil { 42 | t.Fatalf("failed to decode wycheproof json file: %v", err) 43 | } 44 | 45 | var testVectors []CryptoTestVector 46 | for _, testGroup := range tf.TestGroups { 47 | // Skip over unsupported inputs. 48 | if shouldFilter(testGroup) { 49 | continue 50 | } 51 | for _, test := range testGroup.Tests { 52 | testVectors = append(testVectors, CryptoTestVector{ 53 | Key: Dehex(test.Key), 54 | Plaintext: Dehex(test.Msg), 55 | Ciphertext: Dehex(test.Ct), 56 | Tag: Dehex(test.Tag), 57 | Nonce: Dehex(test.IV), 58 | Aad: Dehex(test.Aad), 59 | Result: test.Result, 60 | Desc: test.Comment, 61 | ID: test.TcID, 62 | AllocateDst: true, 63 | }) 64 | } 65 | } 66 | 67 | return testVectors 68 | } 69 | 70 | // IsFailure takes in test result validity, error message, test output, 71 | // expected test output, and returns true if the test failed. 72 | func IsFailure(result string, err error, got, expected []byte) bool { 73 | return (result == ValidResult && (err != nil || !bytes.Equal(got, expected))) || 74 | (result == InvalidResult && err == nil && bytes.Equal(got, expected)) 75 | } 76 | -------------------------------------------------------------------------------- /internal/record/internal/halfconn/ciphersuite.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package halfconn 20 | 21 | import ( 22 | "crypto/sha256" 23 | "crypto/sha512" 24 | "fmt" 25 | "hash" 26 | 27 | s2apb "github.com/google/s2a-go/internal/proto/common_go_proto" 28 | "github.com/google/s2a-go/internal/record/internal/aeadcrypter" 29 | ) 30 | 31 | // ciphersuite is the interface for retrieving ciphersuite-specific information 32 | // and utilities. 33 | type ciphersuite interface { 34 | // keySize returns the key size in bytes. This refers to the key used by 35 | // the AEAD crypter. This is derived by calling HKDF expand on the traffic 36 | // secret. 37 | keySize() int 38 | // nonceSize returns the nonce size in bytes. 39 | nonceSize() int 40 | // trafficSecretSize returns the traffic secret size in bytes. This refers 41 | // to the secret used to derive the traffic key and nonce, as specified in 42 | // https://tools.ietf.org/html/rfc8446#section-7. 43 | trafficSecretSize() int 44 | // hashFunction returns the hash function for the ciphersuite. 45 | hashFunction() func() hash.Hash 46 | // aeadCrypter takes a key and creates an AEAD crypter for the ciphersuite 47 | // using that key. 48 | aeadCrypter(key []byte) (aeadcrypter.S2AAEADCrypter, error) 49 | } 50 | 51 | func newCiphersuite(ciphersuite s2apb.Ciphersuite) (ciphersuite, error) { 52 | switch ciphersuite { 53 | case s2apb.Ciphersuite_AES_128_GCM_SHA256: 54 | return &aesgcm128sha256{}, nil 55 | case s2apb.Ciphersuite_AES_256_GCM_SHA384: 56 | return &aesgcm256sha384{}, nil 57 | case s2apb.Ciphersuite_CHACHA20_POLY1305_SHA256: 58 | return &chachapolysha256{}, nil 59 | default: 60 | return nil, fmt.Errorf("unrecognized ciphersuite: %v", ciphersuite) 61 | } 62 | } 63 | 64 | // aesgcm128sha256 is the AES-128-GCM-SHA256 implementation of the ciphersuite 65 | // interface. 66 | type aesgcm128sha256 struct{} 67 | 68 | func (aesgcm128sha256) keySize() int { return aeadcrypter.AES128GCMKeySize } 69 | func (aesgcm128sha256) nonceSize() int { return aeadcrypter.NonceSize } 70 | func (aesgcm128sha256) trafficSecretSize() int { return aeadcrypter.SHA256DigestSize } 71 | func (aesgcm128sha256) hashFunction() func() hash.Hash { return sha256.New } 72 | func (aesgcm128sha256) aeadCrypter(key []byte) (aeadcrypter.S2AAEADCrypter, error) { 73 | return aeadcrypter.NewAESGCM(key) 74 | } 75 | 76 | // aesgcm256sha384 is the AES-256-GCM-SHA384 implementation of the ciphersuite 77 | // interface. 78 | type aesgcm256sha384 struct{} 79 | 80 | func (aesgcm256sha384) keySize() int { return aeadcrypter.AES256GCMKeySize } 81 | func (aesgcm256sha384) nonceSize() int { return aeadcrypter.NonceSize } 82 | func (aesgcm256sha384) trafficSecretSize() int { return aeadcrypter.SHA384DigestSize } 83 | func (aesgcm256sha384) hashFunction() func() hash.Hash { return sha512.New384 } 84 | func (aesgcm256sha384) aeadCrypter(key []byte) (aeadcrypter.S2AAEADCrypter, error) { 85 | return aeadcrypter.NewAESGCM(key) 86 | } 87 | 88 | // chachapolysha256 is the ChaChaPoly-SHA256 implementation of the ciphersuite 89 | // interface. 90 | type chachapolysha256 struct{} 91 | 92 | func (chachapolysha256) keySize() int { return aeadcrypter.Chacha20Poly1305KeySize } 93 | func (chachapolysha256) nonceSize() int { return aeadcrypter.NonceSize } 94 | func (chachapolysha256) trafficSecretSize() int { return aeadcrypter.SHA256DigestSize } 95 | func (chachapolysha256) hashFunction() func() hash.Hash { return sha256.New } 96 | func (chachapolysha256) aeadCrypter(key []byte) (aeadcrypter.S2AAEADCrypter, error) { 97 | return aeadcrypter.NewChachaPoly(key) 98 | } 99 | -------------------------------------------------------------------------------- /internal/record/internal/halfconn/ciphersuite_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package halfconn 20 | 21 | import ( 22 | "crypto/sha256" 23 | "crypto/sha512" 24 | "hash" 25 | "reflect" 26 | "testing" 27 | 28 | s2apb "github.com/google/s2a-go/internal/proto/common_go_proto" 29 | "github.com/google/s2a-go/internal/record/internal/aeadcrypter" 30 | "github.com/google/s2a-go/internal/record/internal/aeadcrypter/testutil" 31 | ) 32 | 33 | func TestCiphersuites(t *testing.T) { 34 | for _, tc := range []struct { 35 | s2aProtoCiphersuite s2apb.Ciphersuite 36 | expectedCiphersuite ciphersuite 37 | key []byte 38 | keySize, NonceSize, trafficSecretSize int 39 | hashFunction func() hash.Hash 40 | aeadCrypterConstructor func([]byte) (aeadcrypter.S2AAEADCrypter, error) 41 | }{ 42 | { 43 | s2aProtoCiphersuite: s2apb.Ciphersuite_AES_128_GCM_SHA256, 44 | expectedCiphersuite: &aesgcm128sha256{}, 45 | key: testutil.Dehex("88ee087fd95da9fbf6725aa9d757b0cd"), 46 | keySize: aeadcrypter.AES128GCMKeySize, 47 | NonceSize: aeadcrypter.NonceSize, 48 | trafficSecretSize: aeadcrypter.SHA256DigestSize, 49 | hashFunction: sha256.New, 50 | aeadCrypterConstructor: aeadcrypter.NewAESGCM, 51 | }, 52 | { 53 | s2aProtoCiphersuite: s2apb.Ciphersuite_AES_256_GCM_SHA384, 54 | expectedCiphersuite: &aesgcm256sha384{}, 55 | key: testutil.Dehex("83c093b58de7ffe1c0da926ac43fb3609ac1c80fee1b624497ef942e2f79a823"), 56 | keySize: aeadcrypter.AES256GCMKeySize, 57 | NonceSize: aeadcrypter.NonceSize, 58 | trafficSecretSize: aeadcrypter.SHA384DigestSize, 59 | hashFunction: sha512.New384, 60 | aeadCrypterConstructor: aeadcrypter.NewAESGCM, 61 | }, 62 | { 63 | s2aProtoCiphersuite: s2apb.Ciphersuite_CHACHA20_POLY1305_SHA256, 64 | expectedCiphersuite: &chachapolysha256{}, 65 | key: testutil.Dehex("83c093b58de7ffe1c0da926ac43fb3609ac1c80fee1b624497ef942e2f79a823"), 66 | keySize: aeadcrypter.Chacha20Poly1305KeySize, 67 | NonceSize: aeadcrypter.NonceSize, 68 | trafficSecretSize: aeadcrypter.SHA256DigestSize, 69 | hashFunction: sha256.New, 70 | aeadCrypterConstructor: aeadcrypter.NewChachaPoly, 71 | }, 72 | } { 73 | t.Run(tc.s2aProtoCiphersuite.String(), func(t *testing.T) { 74 | hc, err := newCiphersuite(tc.s2aProtoCiphersuite) 75 | if err != nil { 76 | t.Fatalf("newCiphersuite(%v) failed: %v", tc.s2aProtoCiphersuite, err) 77 | } 78 | if got, want := reflect.TypeOf(hc), reflect.TypeOf(tc.expectedCiphersuite); got != want { 79 | t.Fatalf("newCiphersuite(%v) = %v, want %v", tc.s2aProtoCiphersuite, got, want) 80 | } 81 | if got, want := hc.keySize(), tc.keySize; got != want { 82 | t.Errorf("hc.keySize() = %v, want %v", got, want) 83 | } 84 | if got, want := hc.nonceSize(), tc.NonceSize; got != want { 85 | t.Errorf("hc.nonceSize() = %v, want %v", got, want) 86 | } 87 | if got, want := hc.trafficSecretSize(), tc.trafficSecretSize; got != want { 88 | t.Errorf("hc.trafficSecretSize() = %v, want %v", got, want) 89 | } 90 | if got, want := reflect.TypeOf(hc.hashFunction()), reflect.TypeOf(tc.hashFunction); got != want { 91 | t.Errorf("hc.hashFunction() = %v, want %v", got, want) 92 | } 93 | aeadCrypter, err := hc.aeadCrypter(tc.key) 94 | if err != nil { 95 | t.Fatalf("hc.aeadCrypter(%v) failed: %v", tc.key, err) 96 | } 97 | tcAEADCrypter, err := tc.aeadCrypterConstructor(make([]byte, tc.keySize)) 98 | if err != nil { 99 | t.Fatalf("tc.aeadCrypterConstructor(make([]byte, %v)) failed: %v", tc.keySize, err) 100 | } 101 | if got, want := reflect.TypeOf(aeadCrypter), reflect.TypeOf(tcAEADCrypter); got != want { 102 | t.Errorf("hc.aeadCrypter(%v) = %v, want %v", tc.key, got, want) 103 | } 104 | }) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /internal/record/internal/halfconn/counter.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package halfconn 20 | 21 | import "errors" 22 | 23 | // counter is a 64-bit counter. 24 | type counter struct { 25 | val uint64 26 | hasOverflowed bool 27 | } 28 | 29 | // newCounter creates a new counter with the initial value set to val. 30 | func newCounter(val uint64) counter { 31 | return counter{val: val} 32 | } 33 | 34 | // value returns the current value of the counter. 35 | func (c *counter) value() (uint64, error) { 36 | if c.hasOverflowed { 37 | return 0, errors.New("counter has overflowed") 38 | } 39 | return c.val, nil 40 | } 41 | 42 | // increment increments the counter and checks for overflow. 43 | func (c *counter) increment() { 44 | // If the counter is already invalid due to overflow, there is no need to 45 | // increase it. We check for the hasOverflowed flag in the call to value(). 46 | if c.hasOverflowed { 47 | return 48 | } 49 | c.val++ 50 | if c.val == 0 { 51 | c.hasOverflowed = true 52 | } 53 | } 54 | 55 | // reset sets the counter value to zero and sets the hasOverflowed flag to 56 | // false. 57 | func (c *counter) reset() { 58 | c.val = 0 59 | c.hasOverflowed = false 60 | } 61 | -------------------------------------------------------------------------------- /internal/record/internal/halfconn/counter_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package halfconn 20 | 21 | import ( 22 | "math" 23 | "testing" 24 | ) 25 | 26 | func TestNewCounter(t *testing.T) { 27 | counter := newCounter(1) 28 | if got, want := counter.val, uint64(1); got != want { 29 | t.Errorf("counter.val = %v, want %v", got, want) 30 | } 31 | if got, want := counter.hasOverflowed, false; got != want { 32 | t.Errorf("counter.hasOverflowed = %v, want %v", got, want) 33 | } 34 | } 35 | 36 | func TestCounterInc(t *testing.T) { 37 | for _, tc := range []struct { 38 | desc string 39 | counter, expectedCounter uint64 40 | shouldOverflow bool 41 | }{ 42 | { 43 | desc: "basic 1", 44 | counter: 0, 45 | expectedCounter: 1, 46 | }, 47 | { 48 | desc: "basic 2", 49 | counter: 123, 50 | expectedCounter: 124, 51 | }, 52 | { 53 | desc: "almost overflow", 54 | counter: math.MaxUint64 - 1, 55 | expectedCounter: math.MaxUint64, 56 | }, 57 | { 58 | desc: "max overflow", 59 | counter: math.MaxUint64, 60 | shouldOverflow: true, 61 | }, 62 | } { 63 | t.Run(tc.desc, func(t *testing.T) { 64 | c := counter{val: tc.counter} 65 | c.increment() 66 | val, err := c.value() 67 | if got, want := err == nil, !tc.shouldOverflow; got != want { 68 | t.Errorf("counter starting with %v, val()=(err=nil)=%v, want %v", tc.counter, got, want) 69 | } 70 | if got, want := val, tc.expectedCounter; err == nil && got != want { 71 | t.Errorf("counter starting with %v, val() = %v, want %v", tc.counter, got, want) 72 | } 73 | if got, want := tc.shouldOverflow, c.hasOverflowed; got != want { 74 | t.Errorf("counter starting with %v, c.hasOverflowed = %v, want %v", tc.counter, got, want) 75 | } 76 | }) 77 | } 78 | } 79 | 80 | func TestCounterReset(t *testing.T) { 81 | for _, tc := range []struct { 82 | desc string 83 | counter uint64 84 | hasOverflowed bool 85 | }{ 86 | { 87 | desc: "non-zero no overflow", 88 | counter: 1, 89 | hasOverflowed: false, 90 | }, 91 | { 92 | desc: "zero no overflow", 93 | counter: 0, 94 | hasOverflowed: false, 95 | }, 96 | { 97 | desc: "non-zero has overflow", 98 | counter: 1, 99 | hasOverflowed: true, 100 | }, 101 | { 102 | desc: "zero has overflow", 103 | counter: 0, 104 | hasOverflowed: true, 105 | }, 106 | } { 107 | t.Run(tc.desc, func(t *testing.T) { 108 | c := counter{tc.counter, tc.hasOverflowed} 109 | c.reset() 110 | if got, want := c.val, uint64(0); got != want { 111 | t.Errorf("counter with value %v, c.value = %v, want %v", tc.counter, got, want) 112 | } 113 | if got, want := c.hasOverflowed, false; got != want { 114 | t.Errorf("counter with value %v, c.hasOverflowed = %v, want %v", tc.counter, got, want) 115 | } 116 | }) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /internal/record/internal/halfconn/expander.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package halfconn 20 | 21 | import ( 22 | "fmt" 23 | "hash" 24 | 25 | "golang.org/x/crypto/hkdf" 26 | ) 27 | 28 | // hkdfExpander is the interface for the HKDF expansion function; see 29 | // https://tools.ietf.org/html/rfc5869 for details. its use in TLS 1.3 is 30 | // specified in https://tools.ietf.org/html/rfc8446#section-7.2 31 | type hkdfExpander interface { 32 | // expand takes a secret, a label, and the output length in bytes, and 33 | // returns the resulting expanded key. 34 | expand(secret, label []byte, length int) ([]byte, error) 35 | } 36 | 37 | // defaultHKDFExpander is the default HKDF expander which uses Go's crypto/hkdf 38 | // for HKDF expansion. 39 | type defaultHKDFExpander struct { 40 | h func() hash.Hash 41 | } 42 | 43 | // newDefaultHKDFExpander creates an instance of the default HKDF expander 44 | // using the given hash function. 45 | func newDefaultHKDFExpander(h func() hash.Hash) hkdfExpander { 46 | return &defaultHKDFExpander{h: h} 47 | } 48 | 49 | func (d *defaultHKDFExpander) expand(secret, label []byte, length int) ([]byte, error) { 50 | outBuf := make([]byte, length) 51 | n, err := hkdf.Expand(d.h, secret, label).Read(outBuf) 52 | if err != nil { 53 | return nil, fmt.Errorf("hkdf.Expand.Read failed with error: %v", err) 54 | } 55 | if n < length { 56 | return nil, fmt.Errorf("hkdf.Expand.Read returned unexpected length, got %d, want %d", n, length) 57 | } 58 | return outBuf, nil 59 | } 60 | -------------------------------------------------------------------------------- /internal/record/internal/halfconn/expander_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package halfconn 20 | 21 | import ( 22 | "bytes" 23 | "crypto/sha256" 24 | "testing" 25 | 26 | "github.com/google/s2a-go/internal/record/internal/aeadcrypter/testutil" 27 | ) 28 | 29 | func TestExpand(t *testing.T) { 30 | // The following test vectors were taken from 31 | // https://tools.ietf.org/html/rfc5869. Note that `prk` and `okm` 32 | // mentioned in the RFC have been renamed to `secret` and `out`. 33 | for _, tc := range []struct { 34 | desc string 35 | secret, info, out []byte 36 | length int 37 | }{ 38 | { 39 | desc: "sha256 basic", 40 | secret: testutil.Dehex("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"), 41 | info: testutil.Dehex("f0f1f2f3f4f5f6f7f8f9"), 42 | out: testutil.Dehex("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"), 43 | length: 42, 44 | }, 45 | { 46 | desc: "sha256 longer input/output", 47 | secret: testutil.Dehex("06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244"), 48 | info: testutil.Dehex("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), 49 | out: testutil.Dehex("b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87"), 50 | length: 82, 51 | }, 52 | { 53 | desc: "sha256 zero length info", 54 | secret: testutil.Dehex("19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04"), 55 | out: testutil.Dehex("8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8"), 56 | length: 42, 57 | }, 58 | } { 59 | t.Run(tc.desc, func(t *testing.T) { 60 | expander := newDefaultHKDFExpander(sha256.New) 61 | got, err := expander.expand(tc.secret, tc.info, tc.length) 62 | if err != nil { 63 | t.Errorf("expand failed with error: %v", err) 64 | } 65 | if !bytes.Equal(got, tc.out) { 66 | t.Errorf("expand(sha256.New, %v, %v, %v) = %v, want %v.", tc.secret, tc.info, tc.length, got, tc.out) 67 | } 68 | }) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /internal/tokenmanager/tokenmanager.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | // Package tokenmanager provides tokens for authenticating to S2A. 20 | package tokenmanager 21 | 22 | import ( 23 | "fmt" 24 | "os" 25 | 26 | commonpbv1 "github.com/google/s2a-go/internal/proto/common_go_proto" 27 | commonpb "github.com/google/s2a-go/internal/proto/v2/common_go_proto" 28 | ) 29 | 30 | const ( 31 | s2aAccessTokenEnvironmentVariable = "S2A_ACCESS_TOKEN" 32 | ) 33 | 34 | // AccessTokenManager manages tokens for authenticating to S2A. 35 | type AccessTokenManager interface { 36 | // DefaultToken returns a token that an application with no specified local 37 | // identity must use to authenticate to S2A. 38 | DefaultToken() (token string, err error) 39 | // Token returns a token that an application with local identity equal to 40 | // identity must use to authenticate to S2A. 41 | Token(identity interface{}) (token string, err error) 42 | } 43 | 44 | type singleTokenAccessTokenManager struct { 45 | token string 46 | } 47 | 48 | // NewSingleTokenAccessTokenManager returns a new AccessTokenManager instance 49 | // that will always manage the same token. 50 | // 51 | // The token to be managed is read from the s2aAccessTokenEnvironmentVariable 52 | // environment variable. If this environment variable is not set, then this 53 | // function returns an error. 54 | func NewSingleTokenAccessTokenManager() (AccessTokenManager, error) { 55 | token, variableExists := os.LookupEnv(s2aAccessTokenEnvironmentVariable) 56 | if !variableExists { 57 | return nil, fmt.Errorf("%s environment variable is not set", s2aAccessTokenEnvironmentVariable) 58 | } 59 | return &singleTokenAccessTokenManager{token: token}, nil 60 | } 61 | 62 | // DefaultToken always returns the token managed by the 63 | // singleTokenAccessTokenManager. 64 | func (m *singleTokenAccessTokenManager) DefaultToken() (string, error) { 65 | return m.token, nil 66 | } 67 | 68 | // Token always returns the token managed by the singleTokenAccessTokenManager. 69 | func (m *singleTokenAccessTokenManager) Token(identity interface{}) (string, error) { 70 | switch v := identity.(type) { 71 | case *commonpbv1.Identity: 72 | // valid type. 73 | case *commonpb.Identity: 74 | // valid type. 75 | default: 76 | return "", fmt.Errorf("Incorrect identity type: %v", v) 77 | } 78 | return m.token, nil 79 | } 80 | -------------------------------------------------------------------------------- /internal/tokenmanager/tokenmanager_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package tokenmanager 20 | 21 | import ( 22 | "os" 23 | "testing" 24 | 25 | commonpb "github.com/google/s2a-go/internal/proto/common_go_proto" 26 | ) 27 | 28 | const testAccessToken = "test_access_token" 29 | 30 | func TestNewSingleTokenAccessTokenManagerFailure(t *testing.T) { 31 | os.Unsetenv(s2aAccessTokenEnvironmentVariable) 32 | if _, err := NewSingleTokenAccessTokenManager(); err == nil { 33 | t.Errorf("expected NewSingleTokenAccessTokenManager() to return non-nil error") 34 | } 35 | } 36 | 37 | func TestNewSingleTokenAccessTokenManagerDefaultTokenSuccess(t *testing.T) { 38 | os.Setenv(s2aAccessTokenEnvironmentVariable, testAccessToken) 39 | tokenManager, err := NewSingleTokenAccessTokenManager() 40 | if err != nil { 41 | t.Errorf("NewSingleTokenAccessTokenManager() returned unexpected error: %v", err) 42 | } 43 | 44 | token, err := tokenManager.DefaultToken() 45 | if err != nil { 46 | t.Errorf("tokenManager.DefaultToken() returned unexpected error: %v", err) 47 | } 48 | if got, want := token, testAccessToken; got != want { 49 | t.Errorf("tokenManager.DefaultToken()= %v, want %s", got, want) 50 | } 51 | } 52 | 53 | func TestNewSingleTokenAccessTokenManagerTokenSuccess(t *testing.T) { 54 | os.Setenv(s2aAccessTokenEnvironmentVariable, testAccessToken) 55 | tokenManager, err := NewSingleTokenAccessTokenManager() 56 | if err != nil { 57 | t.Errorf("NewSingleTokenAccessTokenManager() returned unexpected error: %v", err) 58 | } 59 | 60 | token, err := tokenManager.Token(&commonpb.Identity{}) 61 | if err != nil { 62 | t.Errorf("tokenManager.Token() returned unexpected error: %v", err) 63 | } 64 | if got, want := token, testAccessToken; got != want { 65 | t.Errorf("tokenManager.Token(%v)= %v, want %s", &commonpb.Identity{}, got, want) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /internal/v2/README.md: -------------------------------------------------------------------------------- 1 | **This directory has the implementation of the S2Av2's gRPC-Go client libraries** 2 | -------------------------------------------------------------------------------- /internal/v2/certverifier/certverifier.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2022 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | // Package certverifier offloads verifications to S2Av2. 20 | package certverifier 21 | 22 | import ( 23 | "crypto/x509" 24 | "fmt" 25 | 26 | "github.com/google/s2a-go/stream" 27 | "google.golang.org/grpc/codes" 28 | "google.golang.org/grpc/grpclog" 29 | 30 | s2av2pb "github.com/google/s2a-go/internal/proto/v2/s2a_go_proto" 31 | ) 32 | 33 | // VerifyClientCertificateChain builds a SessionReq, sends it to S2Av2 and 34 | // receives a SessionResp. 35 | func VerifyClientCertificateChain(verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode, s2AStream stream.S2AStream) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 36 | return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 37 | // Offload verification to S2Av2. 38 | if grpclog.V(1) { 39 | grpclog.Infof("Sending request to S2Av2 for client peer cert chain validation.") 40 | } 41 | if err := s2AStream.Send(&s2av2pb.SessionReq{ 42 | ReqOneof: &s2av2pb.SessionReq_ValidatePeerCertificateChainReq{ 43 | ValidatePeerCertificateChainReq: &s2av2pb.ValidatePeerCertificateChainReq{ 44 | Mode: verificationMode, 45 | PeerOneof: &s2av2pb.ValidatePeerCertificateChainReq_ClientPeer_{ 46 | ClientPeer: &s2av2pb.ValidatePeerCertificateChainReq_ClientPeer{ 47 | CertificateChain: rawCerts, 48 | }, 49 | }, 50 | }, 51 | }, 52 | }); err != nil { 53 | grpclog.Infof("Failed to send request to S2Av2 for client peer cert chain validation.") 54 | return err 55 | } 56 | 57 | // Get the response from S2Av2. 58 | resp, err := s2AStream.Recv() 59 | if err != nil { 60 | grpclog.Infof("Failed to receive client peer cert chain validation response from S2Av2.") 61 | return err 62 | } 63 | 64 | // Parse the response. 65 | if (resp.GetStatus() != nil) && (resp.GetStatus().Code != uint32(codes.OK)) { 66 | return fmt.Errorf("failed to offload client cert verification to S2A: %d, %v", resp.GetStatus().Code, resp.GetStatus().Details) 67 | 68 | } 69 | 70 | if resp.GetValidatePeerCertificateChainResp().ValidationResult != s2av2pb.ValidatePeerCertificateChainResp_SUCCESS { 71 | return fmt.Errorf("client cert verification failed: %v", resp.GetValidatePeerCertificateChainResp().ValidationDetails) 72 | } 73 | 74 | return nil 75 | } 76 | } 77 | 78 | // VerifyServerCertificateChain builds a SessionReq, sends it to S2Av2 and 79 | // receives a SessionResp. 80 | func VerifyServerCertificateChain(hostname string, verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode, s2AStream stream.S2AStream, serverAuthorizationPolicy []byte) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 81 | return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 82 | // Offload verification to S2Av2. 83 | if grpclog.V(1) { 84 | grpclog.Infof("Sending request to S2Av2 for server peer cert chain validation.") 85 | } 86 | if err := s2AStream.Send(&s2av2pb.SessionReq{ 87 | ReqOneof: &s2av2pb.SessionReq_ValidatePeerCertificateChainReq{ 88 | ValidatePeerCertificateChainReq: &s2av2pb.ValidatePeerCertificateChainReq{ 89 | Mode: verificationMode, 90 | PeerOneof: &s2av2pb.ValidatePeerCertificateChainReq_ServerPeer_{ 91 | ServerPeer: &s2av2pb.ValidatePeerCertificateChainReq_ServerPeer{ 92 | CertificateChain: rawCerts, 93 | ServerHostname: hostname, 94 | SerializedUnrestrictedClientPolicy: serverAuthorizationPolicy, 95 | }, 96 | }, 97 | }, 98 | }, 99 | }); err != nil { 100 | grpclog.Infof("Failed to send request to S2Av2 for server peer cert chain validation.") 101 | return err 102 | } 103 | 104 | // Get the response from S2Av2. 105 | resp, err := s2AStream.Recv() 106 | if err != nil { 107 | grpclog.Infof("Failed to receive server peer cert chain validation response from S2Av2.") 108 | return err 109 | } 110 | 111 | // Parse the response. 112 | if (resp.GetStatus() != nil) && (resp.GetStatus().Code != uint32(codes.OK)) { 113 | return fmt.Errorf("failed to offload server cert verification to S2A: %d, %v", resp.GetStatus().Code, resp.GetStatus().Details) 114 | } 115 | 116 | if resp.GetValidatePeerCertificateChainResp().ValidationResult != s2av2pb.ValidatePeerCertificateChainResp_SUCCESS { 117 | return fmt.Errorf("server cert verification failed: %v", resp.GetValidatePeerCertificateChainResp().ValidationDetails) 118 | } 119 | 120 | return nil 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/client_intermediate_cert.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/s2a-go/fbd6033e0eb8ff67810a4ee603284b541f03ac71/internal/v2/certverifier/testdata/client_intermediate_cert.der -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/client_intermediate_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID4jCCAsqgAwIBAgIUTe5U1a+hWMy6E90wGQMdT1m8kG4wDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNjE1MjEzNjM3WhcNNDIwNjE1MjEzNjM3WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAMO+fKYnXxZQ7Xff8wvzwzi8y4illQ00dEgbuGMH+k9oixSR/xAZKTLp 11 | 3Cf0Lnc14hUN6HX94tVAbHuQ9ylh6A67C3hsQdZ1YXG+j5V891kSYT4GV2rmz8x8 12 | HNw6NEDhzlV8C2uE3CTztU93COk5eY9PA9FML/WcYf4iyifr5pvCAWNnWSFMa298 13 | WiEX57AixBRKmjTs0jwtrf+isLgqvhGCVXy/0T8aE8fik1MjDfPJlq7hmwfQ677q 14 | qO89IvSWXkKbAurIxzhiOTbcGOyvPtC8Blxxvkiro71iaHepWarDKyE5tvc3qMYG 15 | IPmQGm8LcI7Xv/cWqaDLx8bg559i4/MCAwEAAaNEMEIwHwYDVR0jBBgwFoAUqEBT 16 | ie7SH+WueCBsga/Hh6PRaSUwDAYDVR0TBAUwAwEB/zARBgNVHREECjAIggZkb21h 17 | aW4wDQYJKoZIhvcNAQELBQADggEBAK4kgQqkqWRvzQ++if+TfKDarlzw+W2665Qn 18 | W+HmVc5cEJXzybQJ3nVUXCm8djBja0k5NQPz4/eecrY1QIKNMpfCN98fPfV2l4BM 19 | aIF9pcfQ1GF2J/MT7lqdaj3EdBzO68z+ODalKhK5ALUTG6+Oxmhke9jhJnmVKaH3 20 | DUbEHm3Mjj2bPiYFfLVS38/inN0cpJ0LnQv12jZF/zz+fA0Fk8bNIehC4u4eO4xG 21 | eqA/PqSqUsj0Ot81cCtaq097jwnno0/WxsjljIl7bkeuksk4rraFIoNyHWTYYfM6 22 | JohezYBt5o4OEixy5oRxg89OGnzO/uPCbd5fJLUUrQppdM5bOWM= 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/client_intermediate_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAw758pidfFlDtd9/zC/PDOLzLiKWVDTR0SBu4Ywf6T2iLFJH/ 3 | EBkpMuncJ/QudzXiFQ3odf3i1UBse5D3KWHoDrsLeGxB1nVhcb6PlXz3WRJhPgZX 4 | aubPzHwc3Do0QOHOVXwLa4TcJPO1T3cI6Tl5j08D0Uwv9Zxh/iLKJ+vmm8IBY2dZ 5 | IUxrb3xaIRfnsCLEFEqaNOzSPC2t/6KwuCq+EYJVfL/RPxoTx+KTUyMN88mWruGb 6 | B9Drvuqo7z0i9JZeQpsC6sjHOGI5NtwY7K8+0LwGXHG+SKujvWJod6lZqsMrITm2 7 | 9zeoxgYg+ZAabwtwjte/9xapoMvHxuDnn2Lj8wIDAQABAoIBAQCxOeHP6ivMn78x 8 | 3wFGnBDwaPd7JDhcuVZjBz4d49Y9WXE7Uah3IeDMaTLctdfwNUgaOfp0AkgDPo46 9 | Hpm5zRx3YeDTymidzK9Kdfe4qGmnKt4Cc2lor8wK34Cd4ND4wbm4alRIqAVOK53I 10 | cgUObOxj1W2mbW2q2kla+JLCLHMiJ6A8IMf0ZmciZ0YcY9NStstJEX/QwCCxM0Wd 11 | 6lCVOnRu5+tMnEGLfipqTgKLy+Xkm9mbI+pNV6uo37TF1ugo7f62b4kpPnZSCcf5 12 | sMB4+MAYdXJQ4uqFLg7UsplFchD/b+mPOmrRv39V6Sh4P+MmHayJcIAS8N81xNuM 13 | 06jCT+DhAoGBAPvoCfRERBNUJz/i3J7X+ro9u/Zr0ehjTo7WxTGMSOJPwB90K/dY 14 | GjiVQ/naH6yke9MM0t18Sgp/INKr74naxqjx98m4vvyo5o0H3R73hTe3S6yc3SOr 15 | rB8Z4xculgfH5rVi1cbRn8XnPTYxI2SjiZERSqOuaiIdjHIMZ1ptFEXxAoGBAMbs 16 | zla4YFzvcxOKQT1U1On+m66631OCHD+B+4bYIu3DbCXRY/LJ3a7IrLz9O51UJUO5 17 | 0HykrxS1UW8TENxbl2hc0N7x2eL+p5IpaPzXQZaKqX2crkf52mkSMndgZtJvIASo 18 | 8aNXneDjYbzv3WPuKkjm97cybe+t/lwKqh/KDpQjAoGBAM5YwO6qjOkYYh5fA0HK 19 | wcOVlkbBA21NC6jOHTH9LCbWFRau3uT58mCvRMOB/bg59IRpWMG9chkvEgAAf3N5 20 | FoqFyugewbPN1y1nZ6ZaM3H0X7TBuhPiKFhBqFfw/UzaXw3uLBd012ARj364ublS 21 | jPmcJHv3/1B6y/UQXAkimRzBAoGAQDV7vN4yrIzV1j7QJB3Xw9fdJJ9JKslamN05 22 | 9SKa06g6plJaMqoaFirMJwyOS5A3nw7BTxpRMRv9tx6uWJJv4s3i1bO3IuAT8sfP 23 | DZ3lm9QSNWt3jeAGMdgf1gyV4+LesOJfbNwBJ+/9QmEiUvkzSOjUmJt8hNriuY7v 24 | rucnoYUCgYBXDa7ZR8QN/boJkfegYSba2w6Buy/GU4XrBt/El/Y9Xii0PkkEFkRp 25 | KRrcwIa202wXpK7N3OzyfgDIAtDyLMfsQIHxpVwEc7n36ryMrPv1IS1IJ6gFEGv2 26 | 9vdxI/DqT0928osv6hRX+EnfS4yXePLF/MWWgWwQB2eItrZ/Og7kmw== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/client_leaf_cert.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/s2a-go/fbd6033e0eb8ff67810a4ee603284b541f03ac71/internal/v2/certverifier/testdata/client_leaf_cert.der -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/client_leaf_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEdzCCA1+gAwIBAgIUDv1aq8fQZA6jA1Jnr1v6tjDsVOswDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNjE1MjE0MTEzWhcNNDIwNjE1MjE0MTEzWjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAOThYZoVB3ffqIgSgqwTpSO8uf2rUvYbbWufqYEXggxp8f4CIn6RMO/g 11 | ObrWGm9jUd5xyp1DZZuxYIWKHQu2ehy1OP+C57qni8v5kPVzoFYYeG7/rU1B4u8j 12 | kKyjOG0Q2i0cauP1RWWg1QsPM5uRwnWRIghT+pAhzsriQwy6aeW+PCSDKeHjXb+B 13 | HWTZZXVV0KdkTYo2jdJ/6/ir0iR+Up41gCoR3WCGxAOaRlym95dpI4G7E7+IRtzr 14 | tvVKc9kouk5Qqfz9mamxbGyu1QHExVGoMTS0IOqpt4KwdRjJtf+vxpS4OvwPZu4p 15 | s+0kATNrCqHIcKwQdZ2uDBtmQGMEClsCAwEAAaOB2DCB1TCBsQYDVR0jBIGpMIGm 16 | oYGNpIGKMIGHMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCVN1 17 | bm55dmFsZTEQMA4GA1UECgwHQ29tcGFueTERMA8GA1UECwwIRGl2aXNpb24xFjAU 18 | BgNVBAMMDXMyYV90ZXN0X2NlcnQxGjAYBgkqhkiG9w0BCQEWC3h5ekB4eXouY29t 19 | ghRN7lTVr6FYzLoT3TAZAx1PWbyQbjAMBgNVHRMEBTADAQH/MBEGA1UdEQQKMAiC 20 | BmRvbWFpbjANBgkqhkiG9w0BAQsFAAOCAQEAI81PW+0mbcZqFzcEKtrpLq1IwBtt 21 | x3US/vXBnNvzbwcyNIug0IpDqHZ7nvDwiFv/YVme8ckC/aFYbfIlhWlOusw0FcDW 22 | OqOYbJkBFvlMlcTz/jYhN+OruPHaredJlFXylFj/F/tx4WlWIIH/5dYvqyUUReCY 23 | cW977T4duKweugkoFwzOlqIAH9PbuWsmlYzbmTTqmgD9fjuAHHOgv2qQPERWdEoy 24 | vs1/uTkAsdxsyHV24Eh9xqvU2i+GviBt9QLYNTQibzyu6V97bz9Rw/pf6kcJkxyJ 25 | fUCO6liI0g8CPktmz4BxSSDvJwjDz0l1gfv91DefxIkkINqZ2kVz2KF6VQ== 26 | -----END CERTIFICATE----- 27 | -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/client_leaf_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEA5OFhmhUHd9+oiBKCrBOlI7y5/atS9htta5+pgReCDGnx/gIi 3 | fpEw7+A5utYab2NR3nHKnUNlm7FghYodC7Z6HLU4/4LnuqeLy/mQ9XOgVhh4bv+t 4 | TUHi7yOQrKM4bRDaLRxq4/VFZaDVCw8zm5HCdZEiCFP6kCHOyuJDDLpp5b48JIMp 5 | 4eNdv4EdZNlldVXQp2RNijaN0n/r+KvSJH5SnjWAKhHdYIbEA5pGXKb3l2kjgbsT 6 | v4hG3Ou29Upz2Si6TlCp/P2ZqbFsbK7VAcTFUagxNLQg6qm3grB1GMm1/6/GlLg6 7 | /A9m7imz7SQBM2sKochwrBB1na4MG2ZAYwQKWwIDAQABAoIBAByJSSz30D2O4ilM 8 | /YPM0zsYbawF70sF8meHuY+BydIYZ3Z+96QGIC7YKvpzdUpL/MoaL+PZolJ+FAWy 9 | SZrLPoBTy+53eMLZ3uEolX001FnHpURZllbajxu3uHL9yqw2fK1BLMaNLwDTw5wk 10 | Yg/UZYVY+gBF0CimPm0nNqrglxFwoQ4npSMNoN4alLTqELiVd4qmBbp++UoGS62q 11 | dJeHy4VyuBleUTyDs6g5iiwjyPHY39FzPVGcMLR7K50gKpp3u8KUhtXzkVOh2N7r 12 | B25rRgszUFXlPlPDhjwREoCmjZsn8Rhnv/CTS1Fy2/xFvt6XSHwSf+Rnu0UkPBqu 13 | /KW+3skCgYEA/Ne00cubD12wUHE1EhVp7aXZ6Mj99HpyUdNZPiYCk7RmaZralKxN 14 | tu5/lQlqMnOiDNkEKS101TA0YQCBrfWWT2iyuAXJYUXX95ljEOLJ3iL9aWP7JxZz 15 | 3L5wy8Czuo3RS9x2jIYSwg9K9GxU7XbZ+MA/QK//uDCUfP3/TtyED3UCgYEA570S 16 | amy66jo7PFDDQpe2/0suNT3kzBFahwERt13PNUWJXGxdFKtrxP5iNRRDyRFMaNQK 17 | 44an4JAdkEixmNjwvvpJNwi0elWGqnhg5zJqBGYMQ4A3gxY6Xb14wkKneN6BY55R 18 | 5lgPIdrywSjXgCEBwzsUE2oT8iCzYhiDAUr8yI8CgYEAnzNuzh5mXvF939i4Ms+6 19 | 6ADiyTks9i/XJYBvE7u5KamQRnRTpwMq18EqIfxQmr3GTlKi1Q6jHs0AXgeEn7Uf 20 | 1JY22boDB7WDe4pgHzS9KJpdd2uVqxHvGBHtUc3fHNrI6vxAxNBypTAd4PMJMpAA 21 | RSk/aoqm+CHWjTEc/VnJ6TUCgYAOj6zWjxp3mU0bjx+V0Z6oD/tJUShNQlHj5cdN 22 | NFHO0R2+dviqUdMlv65AE5Pm0HVyqNA+V7m4vJV++XJfXlJSTbvH/34HqdQaZhIA 23 | tQRAXoEqxKW4UO898Kfj3PhU+fY7YjlXNfVNdUqHpJ9V570KnW23gpTaQ//BjDS/ 24 | Ig0cNQKBgQDANW1GIXJC0LaNLm7E03vVgRzE4Ww2zHZbxJE309PSsL4zkHkSwLHX 25 | WOnesAYGgItB/oxyb4ySVtE+WyqCGxEeyefjPbylUDqBSaf3/A++dwkB+VaEtZ/C 26 | H9nK6uVAcp1Pw55Rtaooe+oPv5j9+RFw+ctb5J4MZTR2+izprsQN1Q== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/client_root_cert.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/s2a-go/fbd6033e0eb8ff67810a4ee603284b541f03ac71/internal/v2/certverifier/testdata/client_root_cert.der -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/client_root_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID8TCCAtmgAwIBAgIUKXNlBRVe6UepjQUijIFPZBd/4qYwDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNTMxMjAwMzE1WhcNNDIwNTI2MjAwMzE1WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAOOFuIucH7XXfohGxKd3uR/ihUA/LdduR9I8kfpUEbq5BOt8xZe5/Yn9 11 | a1ozEHVW6cOAbHbnwAR8tkSgZ/t42QIA2k77HWU1Jh2xiEIsJivo3imm4/kZWuR0 12 | OqPh7MhzxpR/hvNwpI5mJsAVBWFMa5KtecFZLnyZtwHylrRN1QXzuLrOxuKFufK3 13 | RKbTABScn5RbZL976H/jgfSeXrbt242NrIoBnVe6fRbekbq2DQ6zFArbQMUgHjHK 14 | P0UqBgdr1QmHfi9KytFyx9BTP3gXWnWIu+bY7/v7qKJMHFwGETo+dCLWYevJL316 15 | HnLfhApDMfP8U+Yv/y1N/YvgaSOSlEcCAwEAAaNTMFEwHQYDVR0OBBYEFKhAU4nu 16 | 0h/lrnggbIGvx4ej0WklMB8GA1UdIwQYMBaAFKhAU4nu0h/lrnggbIGvx4ej0Wkl 17 | MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAE/6NghzQ5fu6yR6 18 | EHKbj/YMrFdT7aGn5n2sAf7wJ33LIhiFHkpWBsVlm7rDtZtwhe891ZK/P60anlg9 19 | /P0Ua53tSRVRmCvTnEbXWOVMN4is6MsR7BlmzUxl4AtIn7jbeifEwRL7B4xDYmdA 20 | QrQnsqoz45dLgS5xK4WDqXATP09Q91xQDuhud/b+A4jrvgwFASmL7rMIZbp4f1JQ 21 | nlnl/9VoTBQBvJiWkDUtQDMpRLtauddEkv4AGz75p5IspXWD6cOemuh2iQec11xD 22 | X20rs2WZbAcAiUa3nmy8OKYw435vmpj8gp39WYbX/Yx9TymrFFbVY92wYn+quTco 23 | pKklVz0= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/client_root_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEA44W4i5wftdd+iEbEp3e5H+KFQD8t125H0jyR+lQRurkE63zF 3 | l7n9if1rWjMQdVbpw4BsdufABHy2RKBn+3jZAgDaTvsdZTUmHbGIQiwmK+jeKabj 4 | +Rla5HQ6o+HsyHPGlH+G83CkjmYmwBUFYUxrkq15wVkufJm3AfKWtE3VBfO4us7G 5 | 4oW58rdEptMAFJyflFtkv3vof+OB9J5etu3bjY2sigGdV7p9Ft6RurYNDrMUCttA 6 | xSAeMco/RSoGB2vVCYd+L0rK0XLH0FM/eBdadYi75tjv+/uookwcXAYROj50ItZh 7 | 68kvfXoect+ECkMx8/xT5i//LU39i+BpI5KURwIDAQABAoIBABgyjo/6iLzUMFbZ 8 | /+w3pW6orrdIgN2akvTfED9pVYFgUA+jc3hRhY95bkNnjuaL2cy7Cc4Tk65mfRQL 9 | Y0OxdJLr+EvSFSxAXM9npDA1ddHRsF8JqtFBSxNk8R+g1Yf0GDiO35Fgd3/ViWWA 10 | VtQkRoSRApP3oiQKTRZd8H04keFR+PvmDk/Lq11l3Kc24A1PevKIPX1oI990ggw9 11 | 9i4uSV+cnuMxmcI9xxJtgwdDFdjr39l2arLOHr4s6LGoV2IOdXHNlv5xRqWUZ0FH 12 | MDHowkLgwDrdSTnNeaVNkce14Gqx+bd4hNaLCdKXMpedBTEmrut3f3hdV1kKjaKt 13 | aqRYr8ECgYEA/YDGZY2jvFoHHBywlqmEMFrrCvQGH51m5R1Ntpkzr+Rh3YCmrpvq 14 | xgwJXING0PUw3dz+xrH5lJICrfNE5Kt3fPu1rAEy+13mYsNowghtUq2Rtu0Hsjjx 15 | 2E3Bf8vEB6RNBMmGkUpTTIAroGF5tpJoRvfnWax+k4pFdrKYFtyZdNcCgYEA5cNv 16 | EPltvOobjTXlUmtVP3n27KZN2aXexTcagLzRxE9CV4cYySENl3KuOMmccaZpIl6z 17 | aHk6BT4X+M0LqElNUczrInfVqI+SGAFLGy7W6CJaqSr6cpyFUP/fosKpm6wKGgLq 18 | udHfpvz5rckhKd8kJxFLvhGOK9yN5qpzih0gfhECgYAJfwRvk3G5wYmYpP58dlcs 19 | VIuPenqsPoI3PPTHTU/hW+XKnWIhElgmGRdUrto9Q6IT/Y5RtSMLTLjq+Tzwb/fm 20 | 56rziYv2XJsfwgAvnI8z1Kqrto9ePsHYf3krJ1/thVsZPc9bq/QY3ohD1sLvcuaT 21 | GgBBnLOVJU3a12/ZE2RwOwKBgF0csWMAoj8/5IB6if+3ral2xOGsl7oPZVMo/J2V 22 | Z7EVqb4M6rd/pKFugTpUQgkwtkSOekhpcGD1hAN5HTNK2YG/+L5UMAsKe9sskwJm 23 | HgOfAHy0BSDzW3ey6i9skg2bT9Cww+0gJ3Hl7U1HSCBO5LjMYpSZSrNtwzfqdb5Q 24 | BX3xAoGARZdR28Ej3+/+0+fz47Yu2h4z0EI/EbrudLOWY936jIeAVwHckI3+BuqH 25 | qR4poj1gfbnMxNuI9UzIXzjEmGewx9kDZ7IYnvloZKqoVQODO5GlKF2ja6IcMNlh 26 | GCNdD6PSAS6HcmalmWo9sj+1YMkrl+GJikKZqVBHrHNwMGAG67w= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/domain.ext: -------------------------------------------------------------------------------- 1 | authorityKeyIdentifier=keyid,issuer 2 | basicConstraints=CA:TRUE 3 | subjectAltName = @alt_names 4 | [alt_names] 5 | DNS.1 = domain 6 | -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/server_intermediate_cert.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/s2a-go/fbd6033e0eb8ff67810a4ee603284b541f03ac71/internal/v2/certverifier/testdata/server_intermediate_cert.der -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/server_intermediate_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID4jCCAsqgAwIBAgIUMH/0WOi/luXSyJyOZnaS2KpViZUwDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNjE1MjE1MTU4WhcNNDIwNjE1MjE1MTU4WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAK5X4SoJ+ihmcBKCLylFsmn3Xi9uLvcd2uetj7lcAqTxznM3ya6y0LBp 11 | Q0tVabB8sGDYOss3V5hJWx6f+qjr2iXjl/Ie1iFFWL+jJeBtcs+irrEruvsyOhJr 12 | q0nJrRGHFPTese0clgoDdcECKqUbHY2t/jS7k1D0BKLCGUr02dFfGjS4XCP/0ORN 13 | vzOIVZuRCHKO+OqRGYYOzViuSQqMXfeNTQWLbTNs6GDO5O7KMwO1qks+OTIe8Hpk 14 | pgxDEnafymuCo0ub7ce4hR0YSMC/yuNjEnE/f6mG7p3G6qc5p0bGoMsEPWeCxl/F 15 | XKlHqIcue6hREBn5dl6eVEbnHh8skTECAwEAAaNEMEIwHwYDVR0jBBgwFoAUDJBB 16 | C4xpv5hRCqMrx1VU6gdUWZcwDAYDVR0TBAUwAwEB/zARBgNVHREECjAIggZkb21h 17 | aW4wDQYJKoZIhvcNAQELBQADggEBADgnk/NA509qoVES6/zWkR8WmVObupE9x8u7 18 | TRfx00KUT9nv8YbdSvt1dtzp5OA5SVgMNsp+rQmzeM7PwJkhL0FTl2zrmQj6CQxc 19 | 93uOuHuArZykaCccy4a6l7zcH85vU3sVqh/u5MVx3RcuGzMei/1Q5Mw7D2IXUq+o 20 | 3xjU3RPrc7zJ8nHrc8U5NZ0nVsC1QiNPNl6w4y0WjaC+dHRdS4JujVhZJmrvoA+z 21 | Jpu/ja1BaW4nS1zW5SJm977stQS37gFvAO9A7GKenC9IVvUQIWayld/p0CIZS5Kz 22 | U2KWGSlnkC9E6xoT5sopCyW2CXm9Xdp8MjzHMeBiedALMMdZ3y0= 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/server_intermediate_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEArlfhKgn6KGZwEoIvKUWyafdeL24u9x3a562PuVwCpPHOczfJ 3 | rrLQsGlDS1VpsHywYNg6yzdXmElbHp/6qOvaJeOX8h7WIUVYv6Ml4G1yz6KusSu6 4 | +zI6EmurScmtEYcU9N6x7RyWCgN1wQIqpRsdja3+NLuTUPQEosIZSvTZ0V8aNLhc 5 | I//Q5E2/M4hVm5EIco746pEZhg7NWK5JCoxd941NBYttM2zoYM7k7sozA7WqSz45 6 | Mh7wemSmDEMSdp/Ka4KjS5vtx7iFHRhIwL/K42MScT9/qYbuncbqpzmnRsagywQ9 7 | Z4LGX8VcqUeohy57qFEQGfl2Xp5URuceHyyRMQIDAQABAoIBAGQ8FDFmQRPfKUoK 8 | 3PB+qL/xv43HbGsZGBUhHUO1mbOZbleh2Gt/VSpHqq/yMGyOk51qVAsoC017x06J 9 | LcTWrLoh6ucCQZwpUYgEVa99XYfxATzNZpgrXWXfz0ACGmW8YxkRu/wV9lFVgerw 10 | wvHf8BLX2RIaUe02DkBBFeeZdG3BqxO/ACRLovRjBVAUlkZLxwTHPAkPKzYwYSDx 11 | +BOJ9qpilghgVwHWCwlFtewCNL9fqEQygNi03yaWmVRhddhunbs5If1wNhXbeDtV 12 | G/KlDLMRs3Q3vBCD+JUBgrIWJG9zA0H9eGhSbqoqcKv5MWM8mKSsUpEKGNIIO/uk 13 | buXwPhECgYEA5IYUVJflioQM8/kZztoGUfX7uHTBJ0Z7EIHEAwQoo0a9AtII/MIt 14 | Ve8UnCyogfJgVQ2H9zEStJKoLrZ5Oqzxj9Xeb9cKiO/U6dxI8b434ThLT7QeoGXr 15 | KRLNxF6rMO9UrwsqFqACV4Ebw0S0d5dDbqaRXY+ASu23beTn6w5alUUCgYEAw04i 16 | iDimikp/hTFNDHzdiE1r5p43Wkr3jnCBRLsI0G/Ix4VpWHNjXyp/pg1IIpax00no 17 | vtjERTsHRy1+RqE0RW3h6V37h6gRRtYMvokLDz8Ww+M3MjFdn8YcETCnzR0Q5ALu 18 | +R3dQ0fbX/cWNy2cJLQLGuJi3zjv/ZKGeBJ9nP0CgYEApKkPwRxp4vLfOnRE6k0i 19 | vK/XnsNR4fDg/7Xg/KNkfLGdw4h/vVBUxlSsrxNmn6t7Sg2j6LNNXRtHX9FPbL3s 20 | mM1rp351MtJMwe1eCgIb1YZwjY+lecG2PjQ0W8gy5eGtTStoOkE1LsPyszKwLnOp 21 | vPL8T0P1FwhOYTrM+QuwrVkCgYEAlX1R+zh5aPKa5uUUl5Ffs7um8m956Nfm4pUE 22 | rQoINhrJ8MYSG0y+7BHIgN47r5Xu6M3yo1mh6WfEK1wMAp3TN61itNBl/bDMAI9I 23 | U/LrjzD4CNn63qVghzIJO7MlTV+JFS2VowKT4LK4nJyw2W1EzectdNeBXGDleQ7V 24 | dESa9zUCgYAT1YG0D8C0TmM5xSvhOme4K3El8f7fxSbIjF+TC8fbXuGGqvA7n3EL 25 | rYGNivz94ZhedOfURaCPWbkucaiTDeVz90BCnzcvH++eSmFeBRz3H+vYlimhyy3Y 26 | 6qkfc6/vpSmacqAEWrXdu5ZXh8shWeS3raO4zEcj8wsgup3l0Xeuyg== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/server_leaf_cert.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/s2a-go/fbd6033e0eb8ff67810a4ee603284b541f03ac71/internal/v2/certverifier/testdata/server_leaf_cert.der -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/server_leaf_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEdzCCA1+gAwIBAgIUKRfziVAbC9B6XOi25UTmHUz6fj4wDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNjE1MjIwMDM5WhcNNDIwNjE1MjIwMDM5WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAMCIJro63RfCfXWLSUfs6Q0D5HbrVmBwL4EvkxSxDg+rWbMw9al8sMPn 11 | vjATrbW1d6kzLXeRwJTD2oxX+DJHE+eiLyQeMb/nxxrKZLC3vu2ZPLbKGl6MCtxo 12 | cM4vwYB1vum84dLbJG5BrQMfXOvPqNOE7aDkmE2GZo3hl700Q9vQxZmqHgH0diUb 13 | aGb+d72OM7r7z8c6DbhHUHLbDSb4JlIWue8J0umZADL53U1CmJHm5nESiGW30kBe 14 | 9XVaR3mQ3xcI5qfwGsA1ZUuH86FkQOPVE2BWuprUb6liqfmnJ8m+MheC5nnRqvFb 15 | hJY41lZD3vNjtb4gPxrK1fnwjRyfVT8CAwEAAaOB2DCB1TCBsQYDVR0jBIGpMIGm 16 | oYGNpIGKMIGHMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCVN1 17 | bm55dmFsZTEQMA4GA1UECgwHQ29tcGFueTERMA8GA1UECwwIRGl2aXNpb24xFjAU 18 | BgNVBAMMDXMyYV90ZXN0X2NlcnQxGjAYBgkqhkiG9w0BCQEWC3h5ekB4eXouY29t 19 | ghQwf/RY6L+W5dLInI5mdpLYqlWJlTAMBgNVHRMEBTADAQH/MBEGA1UdEQQKMAiC 20 | BmRvbWFpbjANBgkqhkiG9w0BAQsFAAOCAQEAa2n8FdRHlGdMvQGqQ4V5E9CUjz8X 21 | O4UEjXovJbUbRg3hBIeN+abRQsEBjmfMZn60+rTT65uEklvSGFAb0R5AEVjKKnVX 22 | CexSgQrHjKZJ9jnWJOpIt+XWzT2u1x81OR7vRmSkhfmiWum3ny1yQSgmij+2HLy/ 23 | C8yLZRXZFNDP3+SOYZL8xCFzPXTllroGN8HM5F5TdeUUmO5gMCJIS8Olp/k5q26H 24 | A6F4HfY7hDOB9j6UZj1nwIFSONkbAyaiuabcEQOwxlGwt34xxpdyi69kos5/Y6fX 25 | ydjV4qwOAwox+AzFfvmN422c9uk0BcybolK4vvdD4iPjAkTDfst6gFTUCQ== 26 | -----END CERTIFICATE----- 27 | -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/server_leaf_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEA5OFhmhUHd9+oiBKCrBOlI7y5/atS9htta5+pgReCDGnx/gIi 3 | fpEw7+A5utYab2NR3nHKnUNlm7FghYodC7Z6HLU4/4LnuqeLy/mQ9XOgVhh4bv+t 4 | TUHi7yOQrKM4bRDaLRxq4/VFZaDVCw8zm5HCdZEiCFP6kCHOyuJDDLpp5b48JIMp 5 | 4eNdv4EdZNlldVXQp2RNijaN0n/r+KvSJH5SnjWAKhHdYIbEA5pGXKb3l2kjgbsT 6 | v4hG3Ou29Upz2Si6TlCp/P2ZqbFsbK7VAcTFUagxNLQg6qm3grB1GMm1/6/GlLg6 7 | /A9m7imz7SQBM2sKochwrBB1na4MG2ZAYwQKWwIDAQABAoIBAByJSSz30D2O4ilM 8 | /YPM0zsYbawF70sF8meHuY+BydIYZ3Z+96QGIC7YKvpzdUpL/MoaL+PZolJ+FAWy 9 | SZrLPoBTy+53eMLZ3uEolX001FnHpURZllbajxu3uHL9yqw2fK1BLMaNLwDTw5wk 10 | Yg/UZYVY+gBF0CimPm0nNqrglxFwoQ4npSMNoN4alLTqELiVd4qmBbp++UoGS62q 11 | dJeHy4VyuBleUTyDs6g5iiwjyPHY39FzPVGcMLR7K50gKpp3u8KUhtXzkVOh2N7r 12 | B25rRgszUFXlPlPDhjwREoCmjZsn8Rhnv/CTS1Fy2/xFvt6XSHwSf+Rnu0UkPBqu 13 | /KW+3skCgYEA/Ne00cubD12wUHE1EhVp7aXZ6Mj99HpyUdNZPiYCk7RmaZralKxN 14 | tu5/lQlqMnOiDNkEKS101TA0YQCBrfWWT2iyuAXJYUXX95ljEOLJ3iL9aWP7JxZz 15 | 3L5wy8Czuo3RS9x2jIYSwg9K9GxU7XbZ+MA/QK//uDCUfP3/TtyED3UCgYEA570S 16 | amy66jo7PFDDQpe2/0suNT3kzBFahwERt13PNUWJXGxdFKtrxP5iNRRDyRFMaNQK 17 | 44an4JAdkEixmNjwvvpJNwi0elWGqnhg5zJqBGYMQ4A3gxY6Xb14wkKneN6BY55R 18 | 5lgPIdrywSjXgCEBwzsUE2oT8iCzYhiDAUr8yI8CgYEAnzNuzh5mXvF939i4Ms+6 19 | 6ADiyTks9i/XJYBvE7u5KamQRnRTpwMq18EqIfxQmr3GTlKi1Q6jHs0AXgeEn7Uf 20 | 1JY22boDB7WDe4pgHzS9KJpdd2uVqxHvGBHtUc3fHNrI6vxAxNBypTAd4PMJMpAA 21 | RSk/aoqm+CHWjTEc/VnJ6TUCgYAOj6zWjxp3mU0bjx+V0Z6oD/tJUShNQlHj5cdN 22 | NFHO0R2+dviqUdMlv65AE5Pm0HVyqNA+V7m4vJV++XJfXlJSTbvH/34HqdQaZhIA 23 | tQRAXoEqxKW4UO898Kfj3PhU+fY7YjlXNfVNdUqHpJ9V570KnW23gpTaQ//BjDS/ 24 | Ig0cNQKBgQDANW1GIXJC0LaNLm7E03vVgRzE4Ww2zHZbxJE309PSsL4zkHkSwLHX 25 | WOnesAYGgItB/oxyb4ySVtE+WyqCGxEeyefjPbylUDqBSaf3/A++dwkB+VaEtZ/C 26 | H9nK6uVAcp1Pw55Rtaooe+oPv5j9+RFw+ctb5J4MZTR2+izprsQN1Q== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/server_root_cert.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/s2a-go/fbd6033e0eb8ff67810a4ee603284b541f03ac71/internal/v2/certverifier/testdata/server_root_cert.der -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/server_root_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID8TCCAtmgAwIBAgIUKCoDuLtiZXvhsBY2RoDm0ugizJ8wDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNTMxMjAwODI1WhcNNDIwNTI2MjAwODI1WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAKK1++PXQ+M3hjYH/v0K4UEYl5ljzpNM1i52eQM+gFooojT87PDSaphT 11 | fs0PXy/PTAjHBEvPhWpOpmQXfJNYzjwcCvg66hbqkv++/VTZiFLAsHagzkEz+FRJ 12 | qT5Eq7G5FLyw1izX1uxyPN7tAEWEEg7eqsiaXD3Cq8+TYN9cjirPeF7RZF8yFCYE 13 | xqvbo+Yc6RL6xw19iXVTfctRgQe581KQuIY5/LXo3dWDEilFdsADAe8XAEcO64es 14 | Ow0g1UvXLnpXSE151kXBFb3sKH/ZjCecDYMCIMEb4sWLSblkSxJ5sNSmXIG4wtr2 15 | Qnii7CXZgnVYraQE/Jyh+NMQANuoSdMCAwEAAaNTMFEwHQYDVR0OBBYEFAyQQQuM 16 | ab+YUQqjK8dVVOoHVFmXMB8GA1UdIwQYMBaAFAyQQQuMab+YUQqjK8dVVOoHVFmX 17 | MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADj0vQ6ykWhicoqR 18 | e6VZMwlEJV7/DSvWWKBd9MUjfKye0A4565ya5lmnzP3DiD3nqGe3miqmLsXKDs+X 19 | POqlPXTWIamP7D4MJ32XtSLwZB4ru+I+Ao/P/VngPepoRPQoBnzHe7jww0rokqxl 20 | AZERjlbTUwUAy/BPWPSzSJZ2j0tcs6ZLDNyYzpK4ao8R9/1VmQ92Tcp3feJs1QTg 21 | odRQc3om/AkWOwsll+oyX0UbJeHkFHiLanUPXbdh+/BkSvZJ8ynL+feSDdaurPe+ 22 | PSfnqLtQft9/neecGRdEaQzzzSFVQUVQzTdK1Q7hA7b55b2HvIa3ktDiks+sJsYN 23 | Dhm6uZM= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /internal/v2/certverifier/testdata/server_root_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAorX749dD4zeGNgf+/QrhQRiXmWPOk0zWLnZ5Az6AWiiiNPzs 3 | 8NJqmFN+zQ9fL89MCMcES8+Fak6mZBd8k1jOPBwK+DrqFuqS/779VNmIUsCwdqDO 4 | QTP4VEmpPkSrsbkUvLDWLNfW7HI83u0ARYQSDt6qyJpcPcKrz5Ng31yOKs94XtFk 5 | XzIUJgTGq9uj5hzpEvrHDX2JdVN9y1GBB7nzUpC4hjn8tejd1YMSKUV2wAMB7xcA 6 | Rw7rh6w7DSDVS9cueldITXnWRcEVvewof9mMJ5wNgwIgwRvixYtJuWRLEnmw1KZc 7 | gbjC2vZCeKLsJdmCdVitpAT8nKH40xAA26hJ0wIDAQABAoIBACaNR+lsD8G+XiZf 8 | LqN1+HkcAo9tfnyYMAdCOtnx7SdviT9Uzi8hK/B7mAeuJLeHPlS2EuaDfPD7QaFl 9 | jza6S+MiIdc+3kgfvESsVAnOoOY6kZUJ9NSuI6CU82y1iJjLaYZrv9NQMLRFPPb0 10 | 4KOX709mosB1EnXvshW0rbc+jtDFhrm1SxMt+k9TuzmMxjbOeW4LOLXPgU8X1T3Q 11 | Xy0hMZZtcgBs9wFIo8yCtmOixax9pnFE8rRltgDxTodn9LLdz1FieyntNgDksZ0P 12 | nt4kV7Mqly7ELaea+Foaj244mKsesic2e3GhAlMRLun/VSunSf7mOCxfpITB8dp1 13 | drDhOYECgYEA19151dVxRcviuovN6Dar+QszMTnU8pDJ8BjLFjXjP/hNBBwMTHDE 14 | duMuWk2qnwZqMooI/shxrF/ufmTgS0CFrh2+ANBZu27vWConJNXcyNtdigI4wt50 15 | L0Y2qcZn2mg67qFXHwoR3QNwrwnPwEjRXA09at9CSRZzcwDQ0ETXhYsCgYEAwPaG 16 | 06QdK8Zyly7TTzZJwxzv9uGiqzodmGtX6NEKjgij2JaCxHpukqZBJoqa0jKeK1cm 17 | eNVkOvT5ff9TMzarSHQLr3pZen2/oVLb5gaFkbcJt/klv9Fd+ZRilHY3i6QwS6pD 18 | uMiPOWS4DrLHDRVoVlAZTDjT1RVwwTs+P2NhJdkCgYEAsriXysbxBYyMp05gqEW7 19 | lHIFbFgpSrs9th+Q5U6wW6JEgYaHWDJ1NslY80MiZI93FWjbkbZ7BvBWESeL3EIL 20 | a+EMErht0pVCbIhZ6FF4foPAqia0wAJVx14mm+G80kNBp5jE/NnleEsE3KcO7nBb 21 | hg8gLn+x7bk81JZ0TDrzBYkCgYEAuQKluv47SeF3tSScTfKLPpvcKCWmxe1uutkQ 22 | 7JShPhVioyOMNb39jnYBOWbjkm4d4QgqRuiytSR0oi3QI+Ziy5EYMyNn713qAk9j 23 | r2TJZDDPDKnBW+zt4YI4EohWMXk3JRUW4XDKggjjwJQA7bZ812TtHHvP/xoThfG7 24 | eSNb3eECgYBw6ssgCtMrdvQiEmjKVX/9yI38mvC2kSGyzbrQnGUfgqRGomRpeZuD 25 | B5E3kysA4td5pT5lvcLgSW0TbOz+YbiriXjwOihPIelCvc9gE2eOUI71/byUWPFz 26 | 7u5F/xQ4NaGr5suLF+lBC6h7pSbM4El9lIHQAQadpuEdzHqrw+hs3g== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /internal/v2/fakes2av2/testdata/client_root_cert.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/s2a-go/fbd6033e0eb8ff67810a4ee603284b541f03ac71/internal/v2/fakes2av2/testdata/client_root_cert.der -------------------------------------------------------------------------------- /internal/v2/fakes2av2/testdata/client_root_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID8TCCAtmgAwIBAgIUKXNlBRVe6UepjQUijIFPZBd/4qYwDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNTMxMjAwMzE1WhcNNDIwNTI2MjAwMzE1WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAOOFuIucH7XXfohGxKd3uR/ihUA/LdduR9I8kfpUEbq5BOt8xZe5/Yn9 11 | a1ozEHVW6cOAbHbnwAR8tkSgZ/t42QIA2k77HWU1Jh2xiEIsJivo3imm4/kZWuR0 12 | OqPh7MhzxpR/hvNwpI5mJsAVBWFMa5KtecFZLnyZtwHylrRN1QXzuLrOxuKFufK3 13 | RKbTABScn5RbZL976H/jgfSeXrbt242NrIoBnVe6fRbekbq2DQ6zFArbQMUgHjHK 14 | P0UqBgdr1QmHfi9KytFyx9BTP3gXWnWIu+bY7/v7qKJMHFwGETo+dCLWYevJL316 15 | HnLfhApDMfP8U+Yv/y1N/YvgaSOSlEcCAwEAAaNTMFEwHQYDVR0OBBYEFKhAU4nu 16 | 0h/lrnggbIGvx4ej0WklMB8GA1UdIwQYMBaAFKhAU4nu0h/lrnggbIGvx4ej0Wkl 17 | MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAE/6NghzQ5fu6yR6 18 | EHKbj/YMrFdT7aGn5n2sAf7wJ33LIhiFHkpWBsVlm7rDtZtwhe891ZK/P60anlg9 19 | /P0Ua53tSRVRmCvTnEbXWOVMN4is6MsR7BlmzUxl4AtIn7jbeifEwRL7B4xDYmdA 20 | QrQnsqoz45dLgS5xK4WDqXATP09Q91xQDuhud/b+A4jrvgwFASmL7rMIZbp4f1JQ 21 | nlnl/9VoTBQBvJiWkDUtQDMpRLtauddEkv4AGz75p5IspXWD6cOemuh2iQec11xD 22 | X20rs2WZbAcAiUa3nmy8OKYw435vmpj8gp39WYbX/Yx9TymrFFbVY92wYn+quTco 23 | pKklVz0= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /internal/v2/fakes2av2/testdata/client_root_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEA44W4i5wftdd+iEbEp3e5H+KFQD8t125H0jyR+lQRurkE63zF 3 | l7n9if1rWjMQdVbpw4BsdufABHy2RKBn+3jZAgDaTvsdZTUmHbGIQiwmK+jeKabj 4 | +Rla5HQ6o+HsyHPGlH+G83CkjmYmwBUFYUxrkq15wVkufJm3AfKWtE3VBfO4us7G 5 | 4oW58rdEptMAFJyflFtkv3vof+OB9J5etu3bjY2sigGdV7p9Ft6RurYNDrMUCttA 6 | xSAeMco/RSoGB2vVCYd+L0rK0XLH0FM/eBdadYi75tjv+/uookwcXAYROj50ItZh 7 | 68kvfXoect+ECkMx8/xT5i//LU39i+BpI5KURwIDAQABAoIBABgyjo/6iLzUMFbZ 8 | /+w3pW6orrdIgN2akvTfED9pVYFgUA+jc3hRhY95bkNnjuaL2cy7Cc4Tk65mfRQL 9 | Y0OxdJLr+EvSFSxAXM9npDA1ddHRsF8JqtFBSxNk8R+g1Yf0GDiO35Fgd3/ViWWA 10 | VtQkRoSRApP3oiQKTRZd8H04keFR+PvmDk/Lq11l3Kc24A1PevKIPX1oI990ggw9 11 | 9i4uSV+cnuMxmcI9xxJtgwdDFdjr39l2arLOHr4s6LGoV2IOdXHNlv5xRqWUZ0FH 12 | MDHowkLgwDrdSTnNeaVNkce14Gqx+bd4hNaLCdKXMpedBTEmrut3f3hdV1kKjaKt 13 | aqRYr8ECgYEA/YDGZY2jvFoHHBywlqmEMFrrCvQGH51m5R1Ntpkzr+Rh3YCmrpvq 14 | xgwJXING0PUw3dz+xrH5lJICrfNE5Kt3fPu1rAEy+13mYsNowghtUq2Rtu0Hsjjx 15 | 2E3Bf8vEB6RNBMmGkUpTTIAroGF5tpJoRvfnWax+k4pFdrKYFtyZdNcCgYEA5cNv 16 | EPltvOobjTXlUmtVP3n27KZN2aXexTcagLzRxE9CV4cYySENl3KuOMmccaZpIl6z 17 | aHk6BT4X+M0LqElNUczrInfVqI+SGAFLGy7W6CJaqSr6cpyFUP/fosKpm6wKGgLq 18 | udHfpvz5rckhKd8kJxFLvhGOK9yN5qpzih0gfhECgYAJfwRvk3G5wYmYpP58dlcs 19 | VIuPenqsPoI3PPTHTU/hW+XKnWIhElgmGRdUrto9Q6IT/Y5RtSMLTLjq+Tzwb/fm 20 | 56rziYv2XJsfwgAvnI8z1Kqrto9ePsHYf3krJ1/thVsZPc9bq/QY3ohD1sLvcuaT 21 | GgBBnLOVJU3a12/ZE2RwOwKBgF0csWMAoj8/5IB6if+3ral2xOGsl7oPZVMo/J2V 22 | Z7EVqb4M6rd/pKFugTpUQgkwtkSOekhpcGD1hAN5HTNK2YG/+L5UMAsKe9sskwJm 23 | HgOfAHy0BSDzW3ey6i9skg2bT9Cww+0gJ3Hl7U1HSCBO5LjMYpSZSrNtwzfqdb5Q 24 | BX3xAoGARZdR28Ej3+/+0+fz47Yu2h4z0EI/EbrudLOWY936jIeAVwHckI3+BuqH 25 | qR4poj1gfbnMxNuI9UzIXzjEmGewx9kDZ7IYnvloZKqoVQODO5GlKF2ja6IcMNlh 26 | GCNdD6PSAS6HcmalmWo9sj+1YMkrl+GJikKZqVBHrHNwMGAG67w= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /internal/v2/fakes2av2/testdata/server_root_cert.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/s2a-go/fbd6033e0eb8ff67810a4ee603284b541f03ac71/internal/v2/fakes2av2/testdata/server_root_cert.der -------------------------------------------------------------------------------- /internal/v2/fakes2av2/testdata/server_root_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID8TCCAtmgAwIBAgIUKCoDuLtiZXvhsBY2RoDm0ugizJ8wDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNTMxMjAwODI1WhcNNDIwNTI2MjAwODI1WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAKK1++PXQ+M3hjYH/v0K4UEYl5ljzpNM1i52eQM+gFooojT87PDSaphT 11 | fs0PXy/PTAjHBEvPhWpOpmQXfJNYzjwcCvg66hbqkv++/VTZiFLAsHagzkEz+FRJ 12 | qT5Eq7G5FLyw1izX1uxyPN7tAEWEEg7eqsiaXD3Cq8+TYN9cjirPeF7RZF8yFCYE 13 | xqvbo+Yc6RL6xw19iXVTfctRgQe581KQuIY5/LXo3dWDEilFdsADAe8XAEcO64es 14 | Ow0g1UvXLnpXSE151kXBFb3sKH/ZjCecDYMCIMEb4sWLSblkSxJ5sNSmXIG4wtr2 15 | Qnii7CXZgnVYraQE/Jyh+NMQANuoSdMCAwEAAaNTMFEwHQYDVR0OBBYEFAyQQQuM 16 | ab+YUQqjK8dVVOoHVFmXMB8GA1UdIwQYMBaAFAyQQQuMab+YUQqjK8dVVOoHVFmX 17 | MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADj0vQ6ykWhicoqR 18 | e6VZMwlEJV7/DSvWWKBd9MUjfKye0A4565ya5lmnzP3DiD3nqGe3miqmLsXKDs+X 19 | POqlPXTWIamP7D4MJ32XtSLwZB4ru+I+Ao/P/VngPepoRPQoBnzHe7jww0rokqxl 20 | AZERjlbTUwUAy/BPWPSzSJZ2j0tcs6ZLDNyYzpK4ao8R9/1VmQ92Tcp3feJs1QTg 21 | odRQc3om/AkWOwsll+oyX0UbJeHkFHiLanUPXbdh+/BkSvZJ8ynL+feSDdaurPe+ 22 | PSfnqLtQft9/neecGRdEaQzzzSFVQUVQzTdK1Q7hA7b55b2HvIa3ktDiks+sJsYN 23 | Dhm6uZM= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /internal/v2/fakes2av2/testdata/server_root_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAorX749dD4zeGNgf+/QrhQRiXmWPOk0zWLnZ5Az6AWiiiNPzs 3 | 8NJqmFN+zQ9fL89MCMcES8+Fak6mZBd8k1jOPBwK+DrqFuqS/779VNmIUsCwdqDO 4 | QTP4VEmpPkSrsbkUvLDWLNfW7HI83u0ARYQSDt6qyJpcPcKrz5Ng31yOKs94XtFk 5 | XzIUJgTGq9uj5hzpEvrHDX2JdVN9y1GBB7nzUpC4hjn8tejd1YMSKUV2wAMB7xcA 6 | Rw7rh6w7DSDVS9cueldITXnWRcEVvewof9mMJ5wNgwIgwRvixYtJuWRLEnmw1KZc 7 | gbjC2vZCeKLsJdmCdVitpAT8nKH40xAA26hJ0wIDAQABAoIBACaNR+lsD8G+XiZf 8 | LqN1+HkcAo9tfnyYMAdCOtnx7SdviT9Uzi8hK/B7mAeuJLeHPlS2EuaDfPD7QaFl 9 | jza6S+MiIdc+3kgfvESsVAnOoOY6kZUJ9NSuI6CU82y1iJjLaYZrv9NQMLRFPPb0 10 | 4KOX709mosB1EnXvshW0rbc+jtDFhrm1SxMt+k9TuzmMxjbOeW4LOLXPgU8X1T3Q 11 | Xy0hMZZtcgBs9wFIo8yCtmOixax9pnFE8rRltgDxTodn9LLdz1FieyntNgDksZ0P 12 | nt4kV7Mqly7ELaea+Foaj244mKsesic2e3GhAlMRLun/VSunSf7mOCxfpITB8dp1 13 | drDhOYECgYEA19151dVxRcviuovN6Dar+QszMTnU8pDJ8BjLFjXjP/hNBBwMTHDE 14 | duMuWk2qnwZqMooI/shxrF/ufmTgS0CFrh2+ANBZu27vWConJNXcyNtdigI4wt50 15 | L0Y2qcZn2mg67qFXHwoR3QNwrwnPwEjRXA09at9CSRZzcwDQ0ETXhYsCgYEAwPaG 16 | 06QdK8Zyly7TTzZJwxzv9uGiqzodmGtX6NEKjgij2JaCxHpukqZBJoqa0jKeK1cm 17 | eNVkOvT5ff9TMzarSHQLr3pZen2/oVLb5gaFkbcJt/klv9Fd+ZRilHY3i6QwS6pD 18 | uMiPOWS4DrLHDRVoVlAZTDjT1RVwwTs+P2NhJdkCgYEAsriXysbxBYyMp05gqEW7 19 | lHIFbFgpSrs9th+Q5U6wW6JEgYaHWDJ1NslY80MiZI93FWjbkbZ7BvBWESeL3EIL 20 | a+EMErht0pVCbIhZ6FF4foPAqia0wAJVx14mm+G80kNBp5jE/NnleEsE3KcO7nBb 21 | hg8gLn+x7bk81JZ0TDrzBYkCgYEAuQKluv47SeF3tSScTfKLPpvcKCWmxe1uutkQ 22 | 7JShPhVioyOMNb39jnYBOWbjkm4d4QgqRuiytSR0oi3QI+Ziy5EYMyNn713qAk9j 23 | r2TJZDDPDKnBW+zt4YI4EohWMXk3JRUW4XDKggjjwJQA7bZ812TtHHvP/xoThfG7 24 | eSNb3eECgYBw6ssgCtMrdvQiEmjKVX/9yI38mvC2kSGyzbrQnGUfgqRGomRpeZuD 25 | B5E3kysA4td5pT5lvcLgSW0TbOz+YbiriXjwOihPIelCvc9gE2eOUI71/byUWPFz 26 | 7u5F/xQ4NaGr5suLF+lBC6h7pSbM4El9lIHQAQadpuEdzHqrw+hs3g== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /internal/v2/fakes2av2_server/fakes2av2_server.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2022 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | // Package main runs an S2Av2 service. 20 | package main 21 | 22 | import ( 23 | "flag" 24 | "log" 25 | "net" 26 | 27 | "github.com/google/s2a-go/internal/v2/fakes2av2" 28 | "google.golang.org/grpc" 29 | 30 | s2av2pb "github.com/google/s2a-go/internal/proto/v2/s2a_go_proto" 31 | ) 32 | 33 | var ( 34 | port = flag.String("port", ":8008", "Fake S2Av2 server address port.") 35 | ) 36 | 37 | func runFakeS2Av2Server(listenPort *string) { 38 | listener, err := net.Listen("tcp", *port) 39 | if err != nil { 40 | log.Fatalf("Failed to listen on port %s: %v", listener.Addr().String(), err) 41 | } 42 | s := grpc.NewServer() 43 | log.Printf("Server: started gRPC Fake S2Av2 Server at port: %s", listener.Addr()) 44 | s2av2pb.RegisterS2AServiceServer(s, &fakes2av2.Server{}) 45 | if err := s.Serve(listener); err != nil { 46 | log.Fatalf("Failed to serve: %v", err) 47 | } 48 | } 49 | 50 | func main() { 51 | runFakeS2Av2Server(port) 52 | } 53 | -------------------------------------------------------------------------------- /internal/v2/remotesigner/testdata/client_cert.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/s2a-go/fbd6033e0eb8ff67810a4ee603284b541f03ac71/internal/v2/remotesigner/testdata/client_cert.der -------------------------------------------------------------------------------- /internal/v2/remotesigner/testdata/client_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID8TCCAtmgAwIBAgIUKXNlBRVe6UepjQUijIFPZBd/4qYwDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNTMxMjAwMzE1WhcNNDIwNTI2MjAwMzE1WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAOOFuIucH7XXfohGxKd3uR/ihUA/LdduR9I8kfpUEbq5BOt8xZe5/Yn9 11 | a1ozEHVW6cOAbHbnwAR8tkSgZ/t42QIA2k77HWU1Jh2xiEIsJivo3imm4/kZWuR0 12 | OqPh7MhzxpR/hvNwpI5mJsAVBWFMa5KtecFZLnyZtwHylrRN1QXzuLrOxuKFufK3 13 | RKbTABScn5RbZL976H/jgfSeXrbt242NrIoBnVe6fRbekbq2DQ6zFArbQMUgHjHK 14 | P0UqBgdr1QmHfi9KytFyx9BTP3gXWnWIu+bY7/v7qKJMHFwGETo+dCLWYevJL316 15 | HnLfhApDMfP8U+Yv/y1N/YvgaSOSlEcCAwEAAaNTMFEwHQYDVR0OBBYEFKhAU4nu 16 | 0h/lrnggbIGvx4ej0WklMB8GA1UdIwQYMBaAFKhAU4nu0h/lrnggbIGvx4ej0Wkl 17 | MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAE/6NghzQ5fu6yR6 18 | EHKbj/YMrFdT7aGn5n2sAf7wJ33LIhiFHkpWBsVlm7rDtZtwhe891ZK/P60anlg9 19 | /P0Ua53tSRVRmCvTnEbXWOVMN4is6MsR7BlmzUxl4AtIn7jbeifEwRL7B4xDYmdA 20 | QrQnsqoz45dLgS5xK4WDqXATP09Q91xQDuhud/b+A4jrvgwFASmL7rMIZbp4f1JQ 21 | nlnl/9VoTBQBvJiWkDUtQDMpRLtauddEkv4AGz75p5IspXWD6cOemuh2iQec11xD 22 | X20rs2WZbAcAiUa3nmy8OKYw435vmpj8gp39WYbX/Yx9TymrFFbVY92wYn+quTco 23 | pKklVz0= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /internal/v2/remotesigner/testdata/client_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEA44W4i5wftdd+iEbEp3e5H+KFQD8t125H0jyR+lQRurkE63zF 3 | l7n9if1rWjMQdVbpw4BsdufABHy2RKBn+3jZAgDaTvsdZTUmHbGIQiwmK+jeKabj 4 | +Rla5HQ6o+HsyHPGlH+G83CkjmYmwBUFYUxrkq15wVkufJm3AfKWtE3VBfO4us7G 5 | 4oW58rdEptMAFJyflFtkv3vof+OB9J5etu3bjY2sigGdV7p9Ft6RurYNDrMUCttA 6 | xSAeMco/RSoGB2vVCYd+L0rK0XLH0FM/eBdadYi75tjv+/uookwcXAYROj50ItZh 7 | 68kvfXoect+ECkMx8/xT5i//LU39i+BpI5KURwIDAQABAoIBABgyjo/6iLzUMFbZ 8 | /+w3pW6orrdIgN2akvTfED9pVYFgUA+jc3hRhY95bkNnjuaL2cy7Cc4Tk65mfRQL 9 | Y0OxdJLr+EvSFSxAXM9npDA1ddHRsF8JqtFBSxNk8R+g1Yf0GDiO35Fgd3/ViWWA 10 | VtQkRoSRApP3oiQKTRZd8H04keFR+PvmDk/Lq11l3Kc24A1PevKIPX1oI990ggw9 11 | 9i4uSV+cnuMxmcI9xxJtgwdDFdjr39l2arLOHr4s6LGoV2IOdXHNlv5xRqWUZ0FH 12 | MDHowkLgwDrdSTnNeaVNkce14Gqx+bd4hNaLCdKXMpedBTEmrut3f3hdV1kKjaKt 13 | aqRYr8ECgYEA/YDGZY2jvFoHHBywlqmEMFrrCvQGH51m5R1Ntpkzr+Rh3YCmrpvq 14 | xgwJXING0PUw3dz+xrH5lJICrfNE5Kt3fPu1rAEy+13mYsNowghtUq2Rtu0Hsjjx 15 | 2E3Bf8vEB6RNBMmGkUpTTIAroGF5tpJoRvfnWax+k4pFdrKYFtyZdNcCgYEA5cNv 16 | EPltvOobjTXlUmtVP3n27KZN2aXexTcagLzRxE9CV4cYySENl3KuOMmccaZpIl6z 17 | aHk6BT4X+M0LqElNUczrInfVqI+SGAFLGy7W6CJaqSr6cpyFUP/fosKpm6wKGgLq 18 | udHfpvz5rckhKd8kJxFLvhGOK9yN5qpzih0gfhECgYAJfwRvk3G5wYmYpP58dlcs 19 | VIuPenqsPoI3PPTHTU/hW+XKnWIhElgmGRdUrto9Q6IT/Y5RtSMLTLjq+Tzwb/fm 20 | 56rziYv2XJsfwgAvnI8z1Kqrto9ePsHYf3krJ1/thVsZPc9bq/QY3ohD1sLvcuaT 21 | GgBBnLOVJU3a12/ZE2RwOwKBgF0csWMAoj8/5IB6if+3ral2xOGsl7oPZVMo/J2V 22 | Z7EVqb4M6rd/pKFugTpUQgkwtkSOekhpcGD1hAN5HTNK2YG/+L5UMAsKe9sskwJm 23 | HgOfAHy0BSDzW3ey6i9skg2bT9Cww+0gJ3Hl7U1HSCBO5LjMYpSZSrNtwzfqdb5Q 24 | BX3xAoGARZdR28Ej3+/+0+fz47Yu2h4z0EI/EbrudLOWY936jIeAVwHckI3+BuqH 25 | qR4poj1gfbnMxNuI9UzIXzjEmGewx9kDZ7IYnvloZKqoVQODO5GlKF2ja6IcMNlh 26 | GCNdD6PSAS6HcmalmWo9sj+1YMkrl+GJikKZqVBHrHNwMGAG67w= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /internal/v2/remotesigner/testdata/server_cert.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/s2a-go/fbd6033e0eb8ff67810a4ee603284b541f03ac71/internal/v2/remotesigner/testdata/server_cert.der -------------------------------------------------------------------------------- /internal/v2/remotesigner/testdata/server_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID8TCCAtmgAwIBAgIUKCoDuLtiZXvhsBY2RoDm0ugizJ8wDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNTMxMjAwODI1WhcNNDIwNTI2MjAwODI1WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAKK1++PXQ+M3hjYH/v0K4UEYl5ljzpNM1i52eQM+gFooojT87PDSaphT 11 | fs0PXy/PTAjHBEvPhWpOpmQXfJNYzjwcCvg66hbqkv++/VTZiFLAsHagzkEz+FRJ 12 | qT5Eq7G5FLyw1izX1uxyPN7tAEWEEg7eqsiaXD3Cq8+TYN9cjirPeF7RZF8yFCYE 13 | xqvbo+Yc6RL6xw19iXVTfctRgQe581KQuIY5/LXo3dWDEilFdsADAe8XAEcO64es 14 | Ow0g1UvXLnpXSE151kXBFb3sKH/ZjCecDYMCIMEb4sWLSblkSxJ5sNSmXIG4wtr2 15 | Qnii7CXZgnVYraQE/Jyh+NMQANuoSdMCAwEAAaNTMFEwHQYDVR0OBBYEFAyQQQuM 16 | ab+YUQqjK8dVVOoHVFmXMB8GA1UdIwQYMBaAFAyQQQuMab+YUQqjK8dVVOoHVFmX 17 | MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADj0vQ6ykWhicoqR 18 | e6VZMwlEJV7/DSvWWKBd9MUjfKye0A4565ya5lmnzP3DiD3nqGe3miqmLsXKDs+X 19 | POqlPXTWIamP7D4MJ32XtSLwZB4ru+I+Ao/P/VngPepoRPQoBnzHe7jww0rokqxl 20 | AZERjlbTUwUAy/BPWPSzSJZ2j0tcs6ZLDNyYzpK4ao8R9/1VmQ92Tcp3feJs1QTg 21 | odRQc3om/AkWOwsll+oyX0UbJeHkFHiLanUPXbdh+/BkSvZJ8ynL+feSDdaurPe+ 22 | PSfnqLtQft9/neecGRdEaQzzzSFVQUVQzTdK1Q7hA7b55b2HvIa3ktDiks+sJsYN 23 | Dhm6uZM= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /internal/v2/remotesigner/testdata/server_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAorX749dD4zeGNgf+/QrhQRiXmWPOk0zWLnZ5Az6AWiiiNPzs 3 | 8NJqmFN+zQ9fL89MCMcES8+Fak6mZBd8k1jOPBwK+DrqFuqS/779VNmIUsCwdqDO 4 | QTP4VEmpPkSrsbkUvLDWLNfW7HI83u0ARYQSDt6qyJpcPcKrz5Ng31yOKs94XtFk 5 | XzIUJgTGq9uj5hzpEvrHDX2JdVN9y1GBB7nzUpC4hjn8tejd1YMSKUV2wAMB7xcA 6 | Rw7rh6w7DSDVS9cueldITXnWRcEVvewof9mMJ5wNgwIgwRvixYtJuWRLEnmw1KZc 7 | gbjC2vZCeKLsJdmCdVitpAT8nKH40xAA26hJ0wIDAQABAoIBACaNR+lsD8G+XiZf 8 | LqN1+HkcAo9tfnyYMAdCOtnx7SdviT9Uzi8hK/B7mAeuJLeHPlS2EuaDfPD7QaFl 9 | jza6S+MiIdc+3kgfvESsVAnOoOY6kZUJ9NSuI6CU82y1iJjLaYZrv9NQMLRFPPb0 10 | 4KOX709mosB1EnXvshW0rbc+jtDFhrm1SxMt+k9TuzmMxjbOeW4LOLXPgU8X1T3Q 11 | Xy0hMZZtcgBs9wFIo8yCtmOixax9pnFE8rRltgDxTodn9LLdz1FieyntNgDksZ0P 12 | nt4kV7Mqly7ELaea+Foaj244mKsesic2e3GhAlMRLun/VSunSf7mOCxfpITB8dp1 13 | drDhOYECgYEA19151dVxRcviuovN6Dar+QszMTnU8pDJ8BjLFjXjP/hNBBwMTHDE 14 | duMuWk2qnwZqMooI/shxrF/ufmTgS0CFrh2+ANBZu27vWConJNXcyNtdigI4wt50 15 | L0Y2qcZn2mg67qFXHwoR3QNwrwnPwEjRXA09at9CSRZzcwDQ0ETXhYsCgYEAwPaG 16 | 06QdK8Zyly7TTzZJwxzv9uGiqzodmGtX6NEKjgij2JaCxHpukqZBJoqa0jKeK1cm 17 | eNVkOvT5ff9TMzarSHQLr3pZen2/oVLb5gaFkbcJt/klv9Fd+ZRilHY3i6QwS6pD 18 | uMiPOWS4DrLHDRVoVlAZTDjT1RVwwTs+P2NhJdkCgYEAsriXysbxBYyMp05gqEW7 19 | lHIFbFgpSrs9th+Q5U6wW6JEgYaHWDJ1NslY80MiZI93FWjbkbZ7BvBWESeL3EIL 20 | a+EMErht0pVCbIhZ6FF4foPAqia0wAJVx14mm+G80kNBp5jE/NnleEsE3KcO7nBb 21 | hg8gLn+x7bk81JZ0TDrzBYkCgYEAuQKluv47SeF3tSScTfKLPpvcKCWmxe1uutkQ 22 | 7JShPhVioyOMNb39jnYBOWbjkm4d4QgqRuiytSR0oi3QI+Ziy5EYMyNn713qAk9j 23 | r2TJZDDPDKnBW+zt4YI4EohWMXk3JRUW4XDKggjjwJQA7bZ812TtHHvP/xoThfG7 24 | eSNb3eECgYBw6ssgCtMrdvQiEmjKVX/9yI38mvC2kSGyzbrQnGUfgqRGomRpeZuD 25 | B5E3kysA4td5pT5lvcLgSW0TbOz+YbiriXjwOihPIelCvc9gE2eOUI71/byUWPFz 26 | 7u5F/xQ4NaGr5suLF+lBC6h7pSbM4El9lIHQAQadpuEdzHqrw+hs3g== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /internal/v2/testdata/README.md: -------------------------------------------------------------------------------- 1 | **How example certificates and keys generated in this directory:** 2 | 3 | To create a self signed cert(and private key), Run the following commands using openssl: 4 | ``` 5 | openssl req -x509 -sha256 -days 7305 -newkey rsa:2048 -keyout root_key.pem -out 6 | root_cert.pem 7 | ``` 8 | To create a chain of certs: 9 | 10 | ```leafCert.pem``` < ```intermediateCert.pem``` < ```rootCert.pem``` 11 | 12 | Run the following commands using openssl: 13 | 14 | Create a self signed root: 15 | ``` 16 | openssl req -x509 -sha256 -days 7305 -newkey rsa:2048 -keyout root_key.pem -out root_cert.pem 17 | ``` 18 | Create a configuration file config.cnf: 19 | ``` 20 | basicConstraints=CA:TRUE 21 | ``` 22 | Create the intermediate cert private key: 23 | ``` 24 | openssl genrsa -out intermediate_key.pem 2048 25 | ``` 26 | Create a certificate signing request: 27 | ``` 28 | openssl req -key intermediate_key.pem -new -out intermediate.csr 29 | ``` 30 | Sign the CSR with the root: 31 | ``` 32 | openssl x509 -req -CA root_cert.pem -CAkey root_key.pem -in intermediate.csr 33 | -out intermediate_cert.pem -days 7305 -CAcreateserial -extfile config.cnf 34 | ``` 35 | Create the leaf cert private key: 36 | ``` 37 | openssl genrsa -out leaf_key.pem 2048 38 | ``` 39 | Create a certificate signing request: 40 | ``` 41 | openssl req -key leaf_key.pem -new -out leaf.csr 42 | ``` 43 | Sign the CSR with the intermediate 44 | ``` 45 | openssl x509 -req -CA intermediate_cert.pem -CAkey intermediate_key.pem -in 46 | leaf.csr -out leaf_cert.pem -days 7305 -CAcreateserial -extfile config 47 | ``` 48 | TODO(rmehta19): Perhaps put these commands together into a script to make 49 | generation of example certs/keys and cert chains simpler. 50 | -------------------------------------------------------------------------------- /internal/v2/testdata/client_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID8TCCAtmgAwIBAgIUKXNlBRVe6UepjQUijIFPZBd/4qYwDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNTMxMjAwMzE1WhcNNDIwNTI2MjAwMzE1WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAOOFuIucH7XXfohGxKd3uR/ihUA/LdduR9I8kfpUEbq5BOt8xZe5/Yn9 11 | a1ozEHVW6cOAbHbnwAR8tkSgZ/t42QIA2k77HWU1Jh2xiEIsJivo3imm4/kZWuR0 12 | OqPh7MhzxpR/hvNwpI5mJsAVBWFMa5KtecFZLnyZtwHylrRN1QXzuLrOxuKFufK3 13 | RKbTABScn5RbZL976H/jgfSeXrbt242NrIoBnVe6fRbekbq2DQ6zFArbQMUgHjHK 14 | P0UqBgdr1QmHfi9KytFyx9BTP3gXWnWIu+bY7/v7qKJMHFwGETo+dCLWYevJL316 15 | HnLfhApDMfP8U+Yv/y1N/YvgaSOSlEcCAwEAAaNTMFEwHQYDVR0OBBYEFKhAU4nu 16 | 0h/lrnggbIGvx4ej0WklMB8GA1UdIwQYMBaAFKhAU4nu0h/lrnggbIGvx4ej0Wkl 17 | MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAE/6NghzQ5fu6yR6 18 | EHKbj/YMrFdT7aGn5n2sAf7wJ33LIhiFHkpWBsVlm7rDtZtwhe891ZK/P60anlg9 19 | /P0Ua53tSRVRmCvTnEbXWOVMN4is6MsR7BlmzUxl4AtIn7jbeifEwRL7B4xDYmdA 20 | QrQnsqoz45dLgS5xK4WDqXATP09Q91xQDuhud/b+A4jrvgwFASmL7rMIZbp4f1JQ 21 | nlnl/9VoTBQBvJiWkDUtQDMpRLtauddEkv4AGz75p5IspXWD6cOemuh2iQec11xD 22 | X20rs2WZbAcAiUa3nmy8OKYw435vmpj8gp39WYbX/Yx9TymrFFbVY92wYn+quTco 23 | pKklVz0= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /internal/v2/testdata/client_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEA44W4i5wftdd+iEbEp3e5H+KFQD8t125H0jyR+lQRurkE63zF 3 | l7n9if1rWjMQdVbpw4BsdufABHy2RKBn+3jZAgDaTvsdZTUmHbGIQiwmK+jeKabj 4 | +Rla5HQ6o+HsyHPGlH+G83CkjmYmwBUFYUxrkq15wVkufJm3AfKWtE3VBfO4us7G 5 | 4oW58rdEptMAFJyflFtkv3vof+OB9J5etu3bjY2sigGdV7p9Ft6RurYNDrMUCttA 6 | xSAeMco/RSoGB2vVCYd+L0rK0XLH0FM/eBdadYi75tjv+/uookwcXAYROj50ItZh 7 | 68kvfXoect+ECkMx8/xT5i//LU39i+BpI5KURwIDAQABAoIBABgyjo/6iLzUMFbZ 8 | /+w3pW6orrdIgN2akvTfED9pVYFgUA+jc3hRhY95bkNnjuaL2cy7Cc4Tk65mfRQL 9 | Y0OxdJLr+EvSFSxAXM9npDA1ddHRsF8JqtFBSxNk8R+g1Yf0GDiO35Fgd3/ViWWA 10 | VtQkRoSRApP3oiQKTRZd8H04keFR+PvmDk/Lq11l3Kc24A1PevKIPX1oI990ggw9 11 | 9i4uSV+cnuMxmcI9xxJtgwdDFdjr39l2arLOHr4s6LGoV2IOdXHNlv5xRqWUZ0FH 12 | MDHowkLgwDrdSTnNeaVNkce14Gqx+bd4hNaLCdKXMpedBTEmrut3f3hdV1kKjaKt 13 | aqRYr8ECgYEA/YDGZY2jvFoHHBywlqmEMFrrCvQGH51m5R1Ntpkzr+Rh3YCmrpvq 14 | xgwJXING0PUw3dz+xrH5lJICrfNE5Kt3fPu1rAEy+13mYsNowghtUq2Rtu0Hsjjx 15 | 2E3Bf8vEB6RNBMmGkUpTTIAroGF5tpJoRvfnWax+k4pFdrKYFtyZdNcCgYEA5cNv 16 | EPltvOobjTXlUmtVP3n27KZN2aXexTcagLzRxE9CV4cYySENl3KuOMmccaZpIl6z 17 | aHk6BT4X+M0LqElNUczrInfVqI+SGAFLGy7W6CJaqSr6cpyFUP/fosKpm6wKGgLq 18 | udHfpvz5rckhKd8kJxFLvhGOK9yN5qpzih0gfhECgYAJfwRvk3G5wYmYpP58dlcs 19 | VIuPenqsPoI3PPTHTU/hW+XKnWIhElgmGRdUrto9Q6IT/Y5RtSMLTLjq+Tzwb/fm 20 | 56rziYv2XJsfwgAvnI8z1Kqrto9ePsHYf3krJ1/thVsZPc9bq/QY3ohD1sLvcuaT 21 | GgBBnLOVJU3a12/ZE2RwOwKBgF0csWMAoj8/5IB6if+3ral2xOGsl7oPZVMo/J2V 22 | Z7EVqb4M6rd/pKFugTpUQgkwtkSOekhpcGD1hAN5HTNK2YG/+L5UMAsKe9sskwJm 23 | HgOfAHy0BSDzW3ey6i9skg2bT9Cww+0gJ3Hl7U1HSCBO5LjMYpSZSrNtwzfqdb5Q 24 | BX3xAoGARZdR28Ej3+/+0+fz47Yu2h4z0EI/EbrudLOWY936jIeAVwHckI3+BuqH 25 | qR4poj1gfbnMxNuI9UzIXzjEmGewx9kDZ7IYnvloZKqoVQODO5GlKF2ja6IcMNlh 26 | GCNdD6PSAS6HcmalmWo9sj+1YMkrl+GJikKZqVBHrHNwMGAG67w= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /internal/v2/testdata/server_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID8TCCAtmgAwIBAgIUKCoDuLtiZXvhsBY2RoDm0ugizJ8wDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNTMxMjAwODI1WhcNNDIwNTI2MjAwODI1WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAKK1++PXQ+M3hjYH/v0K4UEYl5ljzpNM1i52eQM+gFooojT87PDSaphT 11 | fs0PXy/PTAjHBEvPhWpOpmQXfJNYzjwcCvg66hbqkv++/VTZiFLAsHagzkEz+FRJ 12 | qT5Eq7G5FLyw1izX1uxyPN7tAEWEEg7eqsiaXD3Cq8+TYN9cjirPeF7RZF8yFCYE 13 | xqvbo+Yc6RL6xw19iXVTfctRgQe581KQuIY5/LXo3dWDEilFdsADAe8XAEcO64es 14 | Ow0g1UvXLnpXSE151kXBFb3sKH/ZjCecDYMCIMEb4sWLSblkSxJ5sNSmXIG4wtr2 15 | Qnii7CXZgnVYraQE/Jyh+NMQANuoSdMCAwEAAaNTMFEwHQYDVR0OBBYEFAyQQQuM 16 | ab+YUQqjK8dVVOoHVFmXMB8GA1UdIwQYMBaAFAyQQQuMab+YUQqjK8dVVOoHVFmX 17 | MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADj0vQ6ykWhicoqR 18 | e6VZMwlEJV7/DSvWWKBd9MUjfKye0A4565ya5lmnzP3DiD3nqGe3miqmLsXKDs+X 19 | POqlPXTWIamP7D4MJ32XtSLwZB4ru+I+Ao/P/VngPepoRPQoBnzHe7jww0rokqxl 20 | AZERjlbTUwUAy/BPWPSzSJZ2j0tcs6ZLDNyYzpK4ao8R9/1VmQ92Tcp3feJs1QTg 21 | odRQc3om/AkWOwsll+oyX0UbJeHkFHiLanUPXbdh+/BkSvZJ8ynL+feSDdaurPe+ 22 | PSfnqLtQft9/neecGRdEaQzzzSFVQUVQzTdK1Q7hA7b55b2HvIa3ktDiks+sJsYN 23 | Dhm6uZM= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /internal/v2/testdata/server_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAorX749dD4zeGNgf+/QrhQRiXmWPOk0zWLnZ5Az6AWiiiNPzs 3 | 8NJqmFN+zQ9fL89MCMcES8+Fak6mZBd8k1jOPBwK+DrqFuqS/779VNmIUsCwdqDO 4 | QTP4VEmpPkSrsbkUvLDWLNfW7HI83u0ARYQSDt6qyJpcPcKrz5Ng31yOKs94XtFk 5 | XzIUJgTGq9uj5hzpEvrHDX2JdVN9y1GBB7nzUpC4hjn8tejd1YMSKUV2wAMB7xcA 6 | Rw7rh6w7DSDVS9cueldITXnWRcEVvewof9mMJ5wNgwIgwRvixYtJuWRLEnmw1KZc 7 | gbjC2vZCeKLsJdmCdVitpAT8nKH40xAA26hJ0wIDAQABAoIBACaNR+lsD8G+XiZf 8 | LqN1+HkcAo9tfnyYMAdCOtnx7SdviT9Uzi8hK/B7mAeuJLeHPlS2EuaDfPD7QaFl 9 | jza6S+MiIdc+3kgfvESsVAnOoOY6kZUJ9NSuI6CU82y1iJjLaYZrv9NQMLRFPPb0 10 | 4KOX709mosB1EnXvshW0rbc+jtDFhrm1SxMt+k9TuzmMxjbOeW4LOLXPgU8X1T3Q 11 | Xy0hMZZtcgBs9wFIo8yCtmOixax9pnFE8rRltgDxTodn9LLdz1FieyntNgDksZ0P 12 | nt4kV7Mqly7ELaea+Foaj244mKsesic2e3GhAlMRLun/VSunSf7mOCxfpITB8dp1 13 | drDhOYECgYEA19151dVxRcviuovN6Dar+QszMTnU8pDJ8BjLFjXjP/hNBBwMTHDE 14 | duMuWk2qnwZqMooI/shxrF/ufmTgS0CFrh2+ANBZu27vWConJNXcyNtdigI4wt50 15 | L0Y2qcZn2mg67qFXHwoR3QNwrwnPwEjRXA09at9CSRZzcwDQ0ETXhYsCgYEAwPaG 16 | 06QdK8Zyly7TTzZJwxzv9uGiqzodmGtX6NEKjgij2JaCxHpukqZBJoqa0jKeK1cm 17 | eNVkOvT5ff9TMzarSHQLr3pZen2/oVLb5gaFkbcJt/klv9Fd+ZRilHY3i6QwS6pD 18 | uMiPOWS4DrLHDRVoVlAZTDjT1RVwwTs+P2NhJdkCgYEAsriXysbxBYyMp05gqEW7 19 | lHIFbFgpSrs9th+Q5U6wW6JEgYaHWDJ1NslY80MiZI93FWjbkbZ7BvBWESeL3EIL 20 | a+EMErht0pVCbIhZ6FF4foPAqia0wAJVx14mm+G80kNBp5jE/NnleEsE3KcO7nBb 21 | hg8gLn+x7bk81JZ0TDrzBYkCgYEAuQKluv47SeF3tSScTfKLPpvcKCWmxe1uutkQ 22 | 7JShPhVioyOMNb39jnYBOWbjkm4d4QgqRuiytSR0oi3QI+Ziy5EYMyNn713qAk9j 23 | r2TJZDDPDKnBW+zt4YI4EohWMXk3JRUW4XDKggjjwJQA7bZ812TtHHvP/xoThfG7 24 | eSNb3eECgYBw6ssgCtMrdvQiEmjKVX/9yI38mvC2kSGyzbrQnGUfgqRGomRpeZuD 25 | B5E3kysA4td5pT5lvcLgSW0TbOz+YbiriXjwOihPIelCvc9gE2eOUI71/byUWPFz 26 | 7u5F/xQ4NaGr5suLF+lBC6h7pSbM4El9lIHQAQadpuEdzHqrw+hs3g== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /internal/v2/tlsconfigstore/testdata/client_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID8TCCAtmgAwIBAgIUKXNlBRVe6UepjQUijIFPZBd/4qYwDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNTMxMjAwMzE1WhcNNDIwNTI2MjAwMzE1WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAOOFuIucH7XXfohGxKd3uR/ihUA/LdduR9I8kfpUEbq5BOt8xZe5/Yn9 11 | a1ozEHVW6cOAbHbnwAR8tkSgZ/t42QIA2k77HWU1Jh2xiEIsJivo3imm4/kZWuR0 12 | OqPh7MhzxpR/hvNwpI5mJsAVBWFMa5KtecFZLnyZtwHylrRN1QXzuLrOxuKFufK3 13 | RKbTABScn5RbZL976H/jgfSeXrbt242NrIoBnVe6fRbekbq2DQ6zFArbQMUgHjHK 14 | P0UqBgdr1QmHfi9KytFyx9BTP3gXWnWIu+bY7/v7qKJMHFwGETo+dCLWYevJL316 15 | HnLfhApDMfP8U+Yv/y1N/YvgaSOSlEcCAwEAAaNTMFEwHQYDVR0OBBYEFKhAU4nu 16 | 0h/lrnggbIGvx4ej0WklMB8GA1UdIwQYMBaAFKhAU4nu0h/lrnggbIGvx4ej0Wkl 17 | MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAE/6NghzQ5fu6yR6 18 | EHKbj/YMrFdT7aGn5n2sAf7wJ33LIhiFHkpWBsVlm7rDtZtwhe891ZK/P60anlg9 19 | /P0Ua53tSRVRmCvTnEbXWOVMN4is6MsR7BlmzUxl4AtIn7jbeifEwRL7B4xDYmdA 20 | QrQnsqoz45dLgS5xK4WDqXATP09Q91xQDuhud/b+A4jrvgwFASmL7rMIZbp4f1JQ 21 | nlnl/9VoTBQBvJiWkDUtQDMpRLtauddEkv4AGz75p5IspXWD6cOemuh2iQec11xD 22 | X20rs2WZbAcAiUa3nmy8OKYw435vmpj8gp39WYbX/Yx9TymrFFbVY92wYn+quTco 23 | pKklVz0= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /internal/v2/tlsconfigstore/testdata/client_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEA44W4i5wftdd+iEbEp3e5H+KFQD8t125H0jyR+lQRurkE63zF 3 | l7n9if1rWjMQdVbpw4BsdufABHy2RKBn+3jZAgDaTvsdZTUmHbGIQiwmK+jeKabj 4 | +Rla5HQ6o+HsyHPGlH+G83CkjmYmwBUFYUxrkq15wVkufJm3AfKWtE3VBfO4us7G 5 | 4oW58rdEptMAFJyflFtkv3vof+OB9J5etu3bjY2sigGdV7p9Ft6RurYNDrMUCttA 6 | xSAeMco/RSoGB2vVCYd+L0rK0XLH0FM/eBdadYi75tjv+/uookwcXAYROj50ItZh 7 | 68kvfXoect+ECkMx8/xT5i//LU39i+BpI5KURwIDAQABAoIBABgyjo/6iLzUMFbZ 8 | /+w3pW6orrdIgN2akvTfED9pVYFgUA+jc3hRhY95bkNnjuaL2cy7Cc4Tk65mfRQL 9 | Y0OxdJLr+EvSFSxAXM9npDA1ddHRsF8JqtFBSxNk8R+g1Yf0GDiO35Fgd3/ViWWA 10 | VtQkRoSRApP3oiQKTRZd8H04keFR+PvmDk/Lq11l3Kc24A1PevKIPX1oI990ggw9 11 | 9i4uSV+cnuMxmcI9xxJtgwdDFdjr39l2arLOHr4s6LGoV2IOdXHNlv5xRqWUZ0FH 12 | MDHowkLgwDrdSTnNeaVNkce14Gqx+bd4hNaLCdKXMpedBTEmrut3f3hdV1kKjaKt 13 | aqRYr8ECgYEA/YDGZY2jvFoHHBywlqmEMFrrCvQGH51m5R1Ntpkzr+Rh3YCmrpvq 14 | xgwJXING0PUw3dz+xrH5lJICrfNE5Kt3fPu1rAEy+13mYsNowghtUq2Rtu0Hsjjx 15 | 2E3Bf8vEB6RNBMmGkUpTTIAroGF5tpJoRvfnWax+k4pFdrKYFtyZdNcCgYEA5cNv 16 | EPltvOobjTXlUmtVP3n27KZN2aXexTcagLzRxE9CV4cYySENl3KuOMmccaZpIl6z 17 | aHk6BT4X+M0LqElNUczrInfVqI+SGAFLGy7W6CJaqSr6cpyFUP/fosKpm6wKGgLq 18 | udHfpvz5rckhKd8kJxFLvhGOK9yN5qpzih0gfhECgYAJfwRvk3G5wYmYpP58dlcs 19 | VIuPenqsPoI3PPTHTU/hW+XKnWIhElgmGRdUrto9Q6IT/Y5RtSMLTLjq+Tzwb/fm 20 | 56rziYv2XJsfwgAvnI8z1Kqrto9ePsHYf3krJ1/thVsZPc9bq/QY3ohD1sLvcuaT 21 | GgBBnLOVJU3a12/ZE2RwOwKBgF0csWMAoj8/5IB6if+3ral2xOGsl7oPZVMo/J2V 22 | Z7EVqb4M6rd/pKFugTpUQgkwtkSOekhpcGD1hAN5HTNK2YG/+L5UMAsKe9sskwJm 23 | HgOfAHy0BSDzW3ey6i9skg2bT9Cww+0gJ3Hl7U1HSCBO5LjMYpSZSrNtwzfqdb5Q 24 | BX3xAoGARZdR28Ej3+/+0+fz47Yu2h4z0EI/EbrudLOWY936jIeAVwHckI3+BuqH 25 | qR4poj1gfbnMxNuI9UzIXzjEmGewx9kDZ7IYnvloZKqoVQODO5GlKF2ja6IcMNlh 26 | GCNdD6PSAS6HcmalmWo9sj+1YMkrl+GJikKZqVBHrHNwMGAG67w= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /internal/v2/tlsconfigstore/testdata/server_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID8TCCAtmgAwIBAgIUKCoDuLtiZXvhsBY2RoDm0ugizJ8wDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNTMxMjAwODI1WhcNNDIwNTI2MjAwODI1WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAKK1++PXQ+M3hjYH/v0K4UEYl5ljzpNM1i52eQM+gFooojT87PDSaphT 11 | fs0PXy/PTAjHBEvPhWpOpmQXfJNYzjwcCvg66hbqkv++/VTZiFLAsHagzkEz+FRJ 12 | qT5Eq7G5FLyw1izX1uxyPN7tAEWEEg7eqsiaXD3Cq8+TYN9cjirPeF7RZF8yFCYE 13 | xqvbo+Yc6RL6xw19iXVTfctRgQe581KQuIY5/LXo3dWDEilFdsADAe8XAEcO64es 14 | Ow0g1UvXLnpXSE151kXBFb3sKH/ZjCecDYMCIMEb4sWLSblkSxJ5sNSmXIG4wtr2 15 | Qnii7CXZgnVYraQE/Jyh+NMQANuoSdMCAwEAAaNTMFEwHQYDVR0OBBYEFAyQQQuM 16 | ab+YUQqjK8dVVOoHVFmXMB8GA1UdIwQYMBaAFAyQQQuMab+YUQqjK8dVVOoHVFmX 17 | MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADj0vQ6ykWhicoqR 18 | e6VZMwlEJV7/DSvWWKBd9MUjfKye0A4565ya5lmnzP3DiD3nqGe3miqmLsXKDs+X 19 | POqlPXTWIamP7D4MJ32XtSLwZB4ru+I+Ao/P/VngPepoRPQoBnzHe7jww0rokqxl 20 | AZERjlbTUwUAy/BPWPSzSJZ2j0tcs6ZLDNyYzpK4ao8R9/1VmQ92Tcp3feJs1QTg 21 | odRQc3om/AkWOwsll+oyX0UbJeHkFHiLanUPXbdh+/BkSvZJ8ynL+feSDdaurPe+ 22 | PSfnqLtQft9/neecGRdEaQzzzSFVQUVQzTdK1Q7hA7b55b2HvIa3ktDiks+sJsYN 23 | Dhm6uZM= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /internal/v2/tlsconfigstore/testdata/server_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAorX749dD4zeGNgf+/QrhQRiXmWPOk0zWLnZ5Az6AWiiiNPzs 3 | 8NJqmFN+zQ9fL89MCMcES8+Fak6mZBd8k1jOPBwK+DrqFuqS/779VNmIUsCwdqDO 4 | QTP4VEmpPkSrsbkUvLDWLNfW7HI83u0ARYQSDt6qyJpcPcKrz5Ng31yOKs94XtFk 5 | XzIUJgTGq9uj5hzpEvrHDX2JdVN9y1GBB7nzUpC4hjn8tejd1YMSKUV2wAMB7xcA 6 | Rw7rh6w7DSDVS9cueldITXnWRcEVvewof9mMJ5wNgwIgwRvixYtJuWRLEnmw1KZc 7 | gbjC2vZCeKLsJdmCdVitpAT8nKH40xAA26hJ0wIDAQABAoIBACaNR+lsD8G+XiZf 8 | LqN1+HkcAo9tfnyYMAdCOtnx7SdviT9Uzi8hK/B7mAeuJLeHPlS2EuaDfPD7QaFl 9 | jza6S+MiIdc+3kgfvESsVAnOoOY6kZUJ9NSuI6CU82y1iJjLaYZrv9NQMLRFPPb0 10 | 4KOX709mosB1EnXvshW0rbc+jtDFhrm1SxMt+k9TuzmMxjbOeW4LOLXPgU8X1T3Q 11 | Xy0hMZZtcgBs9wFIo8yCtmOixax9pnFE8rRltgDxTodn9LLdz1FieyntNgDksZ0P 12 | nt4kV7Mqly7ELaea+Foaj244mKsesic2e3GhAlMRLun/VSunSf7mOCxfpITB8dp1 13 | drDhOYECgYEA19151dVxRcviuovN6Dar+QszMTnU8pDJ8BjLFjXjP/hNBBwMTHDE 14 | duMuWk2qnwZqMooI/shxrF/ufmTgS0CFrh2+ANBZu27vWConJNXcyNtdigI4wt50 15 | L0Y2qcZn2mg67qFXHwoR3QNwrwnPwEjRXA09at9CSRZzcwDQ0ETXhYsCgYEAwPaG 16 | 06QdK8Zyly7TTzZJwxzv9uGiqzodmGtX6NEKjgij2JaCxHpukqZBJoqa0jKeK1cm 17 | eNVkOvT5ff9TMzarSHQLr3pZen2/oVLb5gaFkbcJt/klv9Fd+ZRilHY3i6QwS6pD 18 | uMiPOWS4DrLHDRVoVlAZTDjT1RVwwTs+P2NhJdkCgYEAsriXysbxBYyMp05gqEW7 19 | lHIFbFgpSrs9th+Q5U6wW6JEgYaHWDJ1NslY80MiZI93FWjbkbZ7BvBWESeL3EIL 20 | a+EMErht0pVCbIhZ6FF4foPAqia0wAJVx14mm+G80kNBp5jE/NnleEsE3KcO7nBb 21 | hg8gLn+x7bk81JZ0TDrzBYkCgYEAuQKluv47SeF3tSScTfKLPpvcKCWmxe1uutkQ 22 | 7JShPhVioyOMNb39jnYBOWbjkm4d4QgqRuiytSR0oi3QI+Ziy5EYMyNn713qAk9j 23 | r2TJZDDPDKnBW+zt4YI4EohWMXk3JRUW4XDKggjjwJQA7bZ812TtHHvP/xoThfG7 24 | eSNb3eECgYBw6ssgCtMrdvQiEmjKVX/9yI38mvC2kSGyzbrQnGUfgqRGomRpeZuD 25 | B5E3kysA4td5pT5lvcLgSW0TbOz+YbiriXjwOihPIelCvc9gE2eOUI71/byUWPFz 26 | 7u5F/xQ4NaGr5suLF+lBC6h7pSbM4El9lIHQAQadpuEdzHqrw+hs3g== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /kokoro/gcp_ubuntu/continuous_gae_test.cfg: -------------------------------------------------------------------------------- 1 | build_file: "s2a-go/kokoro/gcp_ubuntu/kokoro_gae_test.sh" -------------------------------------------------------------------------------- /kokoro/gcp_ubuntu/continuous_golang.cfg: -------------------------------------------------------------------------------- 1 | build_file: "s2a-go/kokoro/gcp_ubuntu/kokoro_golang_build.sh" 2 | -------------------------------------------------------------------------------- /kokoro/gcp_ubuntu/continuous_hygiene.cfg: -------------------------------------------------------------------------------- 1 | build_file: "s2a-go/kokoro/gcp_ubuntu/kokoro_hygiene.sh" 2 | -------------------------------------------------------------------------------- /kokoro/gcp_ubuntu/kokoro_gae_test.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #!/bin/bash 16 | 17 | # Fail on any error. 18 | set -e 19 | 20 | # Display commands being run. 21 | set -x 22 | 23 | cd "${KOKORO_ARTIFACTS_DIR}/github/s2a-go" 24 | chmod a+rwx tools/internal_ci/run_gae_test.sh 25 | ./tools/internal_ci/run_gae_test.sh -------------------------------------------------------------------------------- /kokoro/gcp_ubuntu/kokoro_golang_build.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #!/bin/bash 16 | 17 | # Fail on any error. 18 | set -e 19 | 20 | # Display commands being run. 21 | set -x 22 | 23 | cd "${KOKORO_ARTIFACTS_DIR}/github/s2a-go" 24 | ./tools/internal_ci/run_golang_tests.sh 25 | -------------------------------------------------------------------------------- /kokoro/gcp_ubuntu/kokoro_hygiene.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #!/bin/bash 16 | 17 | # Fail on any error. 18 | set -e 19 | 20 | # Display commands being run. 21 | set -x 22 | 23 | cd "${KOKORO_ARTIFACTS_DIR}/github/s2a-go" 24 | ./tools/internal_ci/run_hygiene_tests.sh 25 | -------------------------------------------------------------------------------- /kokoro/gcp_ubuntu/presubmit_golang.cfg: -------------------------------------------------------------------------------- 1 | build_file: "s2a-go/kokoro/gcp_ubuntu/kokoro_golang_build.sh" 2 | -------------------------------------------------------------------------------- /kokoro/gcp_ubuntu/presubmit_hygiene.cfg: -------------------------------------------------------------------------------- 1 | build_file: "s2a-go/kokoro/gcp_ubuntu/kokoro_hygiene.sh" 2 | -------------------------------------------------------------------------------- /kokoro/macos_external/continuous_golang.cfg: -------------------------------------------------------------------------------- 1 | build_file: "s2a-go/kokoro/macos_external/kokoro_golang_build.sh" 2 | -------------------------------------------------------------------------------- /kokoro/macos_external/kokoro_golang_build.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #!/bin/bash 16 | 17 | # Fail on any error. 18 | set -e 19 | 20 | # Display commands being run. 21 | set -x 22 | 23 | cd "${KOKORO_ARTIFACTS_DIR}/github/s2a-go" 24 | ./tools/internal_ci/run_golang_tests.sh 25 | -------------------------------------------------------------------------------- /kokoro/macos_external/presubmit_golang.cfg: -------------------------------------------------------------------------------- 1 | build_file: "s2a-go/kokoro/macos_external/kokoro_golang_build.sh" 2 | -------------------------------------------------------------------------------- /retry/retry.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2023 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | // Package retry provides a retry helper for talking to S2A gRPC server. 20 | // The implementation is modeled after 21 | // https://github.com/googleapis/google-cloud-go/blob/main/compute/metadata/retry.go 22 | package retry 23 | 24 | import ( 25 | "context" 26 | "math/rand" 27 | "time" 28 | 29 | "google.golang.org/grpc/grpclog" 30 | ) 31 | 32 | const ( 33 | maxRetryAttempts = 5 34 | maxRetryForLoops = 10 35 | ) 36 | 37 | type defaultBackoff struct { 38 | max time.Duration 39 | mul float64 40 | cur time.Duration 41 | } 42 | 43 | // Pause returns a duration, which is used as the backoff wait time 44 | // before the next retry. 45 | func (b *defaultBackoff) Pause() time.Duration { 46 | d := time.Duration(1 + rand.Int63n(int64(b.cur))) 47 | b.cur = time.Duration(float64(b.cur) * b.mul) 48 | if b.cur > b.max { 49 | b.cur = b.max 50 | } 51 | return d 52 | } 53 | 54 | // Sleep will wait for the specified duration or return on context 55 | // expiration. 56 | func Sleep(ctx context.Context, d time.Duration) error { 57 | t := time.NewTimer(d) 58 | select { 59 | case <-ctx.Done(): 60 | t.Stop() 61 | return ctx.Err() 62 | case <-t.C: 63 | return nil 64 | } 65 | } 66 | 67 | // NewRetryer creates an instance of S2ARetryer using the defaultBackoff 68 | // implementation. 69 | var NewRetryer = func() *S2ARetryer { 70 | return &S2ARetryer{bo: &defaultBackoff{ 71 | cur: 100 * time.Millisecond, 72 | max: 30 * time.Second, 73 | mul: 2, 74 | }} 75 | } 76 | 77 | type backoff interface { 78 | Pause() time.Duration 79 | } 80 | 81 | // S2ARetryer implements a retry helper for talking to S2A gRPC server. 82 | type S2ARetryer struct { 83 | bo backoff 84 | attempts int 85 | } 86 | 87 | // Attempts return the number of retries attempted. 88 | func (r *S2ARetryer) Attempts() int { 89 | return r.attempts 90 | } 91 | 92 | // Retry returns a boolean indicating whether retry should be performed 93 | // and the backoff duration. 94 | func (r *S2ARetryer) Retry(err error) (time.Duration, bool) { 95 | if err == nil { 96 | return 0, false 97 | } 98 | if r.attempts >= maxRetryAttempts { 99 | return 0, false 100 | } 101 | r.attempts++ 102 | return r.bo.Pause(), true 103 | } 104 | 105 | // Run uses S2ARetryer to execute the function passed in, until success or reaching 106 | // max number of retry attempts. 107 | func Run(ctx context.Context, f func() error) { 108 | retryer := NewRetryer() 109 | forLoopCnt := 0 110 | var err error 111 | for { 112 | err = f() 113 | if bo, shouldRetry := retryer.Retry(err); shouldRetry { 114 | if grpclog.V(1) { 115 | grpclog.Infof("will attempt retry: %v", err) 116 | } 117 | if ctx.Err() != nil { 118 | if grpclog.V(1) { 119 | grpclog.Infof("exit retry loop due to context error: %v", ctx.Err()) 120 | } 121 | break 122 | } 123 | if errSleep := Sleep(ctx, bo); errSleep != nil { 124 | if grpclog.V(1) { 125 | grpclog.Infof("exit retry loop due to sleep error: %v", errSleep) 126 | } 127 | break 128 | } 129 | // This shouldn't happen, just make sure we are not stuck in the for loops. 130 | forLoopCnt++ 131 | if forLoopCnt > maxRetryForLoops { 132 | if grpclog.V(1) { 133 | grpclog.Infof("exit the for loop after too many retries") 134 | } 135 | break 136 | } 137 | continue 138 | } 139 | if grpclog.V(1) { 140 | grpclog.Infof("retry conditions not met, exit the loop") 141 | } 142 | break 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /retry/retry_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2023 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package retry 20 | 21 | import ( 22 | "context" 23 | "errors" 24 | "testing" 25 | "time" 26 | ) 27 | 28 | var errTest error = errors.New("test error") 29 | 30 | type constantBackoff struct{} 31 | 32 | func (b constantBackoff) Pause() time.Duration { return 100 } 33 | 34 | func TestS2ARetryer(t *testing.T) { 35 | tests := []struct { 36 | name string 37 | err error 38 | wantDelay time.Duration 39 | wantShouldRetry bool 40 | }{ 41 | { 42 | name: "retry on err", 43 | err: errTest, 44 | wantDelay: 100, 45 | wantShouldRetry: true, 46 | }, 47 | { 48 | name: "don't retry if err is nil", 49 | err: nil, 50 | wantDelay: 0, 51 | wantShouldRetry: false, 52 | }, 53 | } 54 | 55 | for _, tc := range tests { 56 | t.Run(tc.name, func(t *testing.T) { 57 | retryer := S2ARetryer{bo: constantBackoff{}} 58 | delay, shouldRetry := retryer.Retry(tc.err) 59 | if delay != tc.wantDelay { 60 | t.Fatalf("retryer.Retry(%v) = %v, want %v", tc.err, delay, tc.wantDelay) 61 | } 62 | if shouldRetry != tc.wantShouldRetry { 63 | t.Fatalf("retryer.Retry(%v) = %v, want %v", tc.err, shouldRetry, tc.wantShouldRetry) 64 | } 65 | }) 66 | } 67 | } 68 | 69 | func TestS2ARetryerAttempts(t *testing.T) { 70 | retryer := S2ARetryer{bo: constantBackoff{}} 71 | for i := 1; i <= 5; i++ { 72 | _, shouldRetry := retryer.Retry(errTest) 73 | if !shouldRetry { 74 | t.Fatalf("retryer.Retry(errTest) = false, want true") 75 | } 76 | } 77 | _, shouldRetry := retryer.Retry(errTest) 78 | if shouldRetry { 79 | t.Fatal("an error should only be retried 5 times") 80 | } 81 | } 82 | 83 | func TestDefaultBackoff(t *testing.T) { 84 | bo := defaultBackoff{ 85 | cur: 100 * time.Millisecond, 86 | max: 30 * time.Second, 87 | mul: 2, 88 | } 89 | pauseOne := bo.Pause() 90 | pauseTwo := bo.Pause() 91 | if pauseOne > 100*time.Millisecond { 92 | t.Fatal("first backoff should be less than 100 milli seconds") 93 | } 94 | if pauseTwo > 2*100*time.Millisecond { 95 | t.Fatal("second backoff should be less than 200 milli seconds") 96 | } 97 | } 98 | 99 | func TestSuccessAfterRetry(t *testing.T) { 100 | oldRetry := NewRetryer 101 | defer func() { NewRetryer = oldRetry }() 102 | testRetryer := NewRetryer() 103 | NewRetryer = func() *S2ARetryer { 104 | return testRetryer 105 | } 106 | 107 | cnt := 1 108 | f := func() error { 109 | if cnt == 1 { 110 | cnt++ 111 | return errTest 112 | } 113 | return nil 114 | } 115 | if testRetryer.Attempts() != 0 { 116 | t.Fatal("before execution, retry attempt count should be 0") 117 | } 118 | 119 | Run(context.Background(), f) 120 | 121 | if testRetryer.Attempts() != 1 { 122 | t.Fatal("execution should've succeeded after 1 retry") 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /s2a_options_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package s2a 20 | 21 | import ( 22 | "testing" 23 | 24 | "github.com/google/go-cmp/cmp" 25 | s2apb "github.com/google/s2a-go/internal/proto/common_go_proto" 26 | s2av2pb "github.com/google/s2a-go/internal/proto/v2/common_go_proto" 27 | "google.golang.org/protobuf/testing/protocmp" 28 | ) 29 | 30 | func TestToProtoIdentity(t *testing.T) { 31 | for _, tc := range []struct { 32 | identity Identity 33 | outIdentity *s2apb.Identity 34 | }{ 35 | { 36 | identity: NewSpiffeID("test_spiffe_id"), 37 | outIdentity: &s2apb.Identity{ 38 | IdentityOneof: &s2apb.Identity_SpiffeId{SpiffeId: "test_spiffe_id"}, 39 | }, 40 | }, 41 | { 42 | identity: NewHostname("test_hostname"), 43 | outIdentity: &s2apb.Identity{ 44 | IdentityOneof: &s2apb.Identity_Hostname{Hostname: "test_hostname"}, 45 | }, 46 | }, 47 | { 48 | identity: NewUID("test_uid"), 49 | outIdentity: &s2apb.Identity{ 50 | IdentityOneof: &s2apb.Identity_Uid{Uid: "test_uid"}, 51 | }, 52 | }, 53 | { 54 | identity: nil, 55 | outIdentity: nil, 56 | }, 57 | } { 58 | t.Run(tc.outIdentity.String(), func(t *testing.T) { 59 | protoSpiffeID, err := toProtoIdentity(tc.identity) 60 | if err != nil { 61 | t.Errorf("toProtoIdentity(%v) failed: %v", tc.identity, err) 62 | } 63 | if got, want := protoSpiffeID, tc.outIdentity; !cmp.Equal(got, want, protocmp.Transform()) { 64 | t.Errorf("toProtoIdentity(%v) = %v, want %v", tc.outIdentity, got, want) 65 | } 66 | }) 67 | } 68 | } 69 | 70 | func TestToV2ProtoIdentity(t *testing.T) { 71 | for _, tc := range []struct { 72 | identity Identity 73 | outIdentity *s2av2pb.Identity 74 | }{ 75 | { 76 | identity: NewSpiffeID("test_spiffe_id"), 77 | outIdentity: &s2av2pb.Identity{ 78 | IdentityOneof: &s2av2pb.Identity_SpiffeId{SpiffeId: "test_spiffe_id"}, 79 | }, 80 | }, 81 | { 82 | identity: NewHostname("test_hostname"), 83 | outIdentity: &s2av2pb.Identity{ 84 | IdentityOneof: &s2av2pb.Identity_Hostname{Hostname: "test_hostname"}, 85 | }, 86 | }, 87 | { 88 | identity: NewUID("test_uid"), 89 | outIdentity: &s2av2pb.Identity{ 90 | IdentityOneof: &s2av2pb.Identity_Uid{Uid: "test_uid"}, 91 | }, 92 | }, 93 | { 94 | identity: &UnspecifiedID{ 95 | Attr: map[string]string{"key": "value"}, 96 | }, 97 | outIdentity: &s2av2pb.Identity{ 98 | Attributes: map[string]string{"key": "value"}, 99 | }, 100 | }, 101 | { 102 | identity: nil, 103 | outIdentity: nil, 104 | }, 105 | } { 106 | t.Run(tc.outIdentity.String(), func(t *testing.T) { 107 | protoSpiffeID, err := toV2ProtoIdentity(tc.identity) 108 | if err != nil { 109 | t.Errorf("toV2ProtoIdentity(%v) failed: %v", tc.identity, err) 110 | } 111 | if got, want := protoSpiffeID, tc.outIdentity; !cmp.Equal(got, want, protocmp.Transform()) { 112 | t.Errorf("toV2ProtoIdentity(%v) = %v, want %v", tc.outIdentity, got, want) 113 | } 114 | }) 115 | } 116 | } 117 | 118 | // Implements the Identity interface and is used to get an error from toV2ProtoIdentity. 119 | type UnsupportedIdentity struct{} 120 | 121 | func (u *UnsupportedIdentity) Name() string { return "" } 122 | func (u *UnsupportedIdentity) Attributes() map[string]string { return map[string]string{} } 123 | 124 | func TestToV2ProtoIdentityError(t *testing.T) { 125 | if _, err := toV2ProtoIdentity(&UnsupportedIdentity{}); err == nil { 126 | t.Errorf("toV2ProtoIdentity(&UnsupportedIdentity{}) err = nil, want err != nil") 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /s2a_utils.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package s2a 20 | 21 | import ( 22 | "context" 23 | "errors" 24 | 25 | commonpb "github.com/google/s2a-go/internal/proto/common_go_proto" 26 | "google.golang.org/grpc/credentials" 27 | "google.golang.org/grpc/peer" 28 | ) 29 | 30 | // AuthInfo exposes security information from the S2A to the application. 31 | type AuthInfo interface { 32 | // AuthType returns the authentication type. 33 | AuthType() string 34 | // ApplicationProtocol returns the application protocol, e.g. "grpc". 35 | ApplicationProtocol() string 36 | // TLSVersion returns the TLS version negotiated during the handshake. 37 | TLSVersion() commonpb.TLSVersion 38 | // Ciphersuite returns the ciphersuite negotiated during the handshake. 39 | Ciphersuite() commonpb.Ciphersuite 40 | // PeerIdentity returns the authenticated identity of the peer. 41 | PeerIdentity() *commonpb.Identity 42 | // LocalIdentity returns the local identity of the application used during 43 | // session setup. 44 | LocalIdentity() *commonpb.Identity 45 | // PeerCertFingerprint returns the SHA256 hash of the peer certificate used in 46 | // the S2A handshake. 47 | PeerCertFingerprint() []byte 48 | // LocalCertFingerprint returns the SHA256 hash of the local certificate used 49 | // in the S2A handshake. 50 | LocalCertFingerprint() []byte 51 | // IsHandshakeResumed returns true if a cached session was used to resume 52 | // the handshake. 53 | IsHandshakeResumed() bool 54 | // SecurityLevel returns the security level of the connection. 55 | SecurityLevel() credentials.SecurityLevel 56 | } 57 | 58 | // AuthInfoFromPeer extracts the authinfo.S2AAuthInfo object from the given 59 | // peer, if it exists. This API should be used by gRPC clients after 60 | // obtaining a peer object using the grpc.Peer() CallOption. 61 | func AuthInfoFromPeer(p *peer.Peer) (AuthInfo, error) { 62 | s2aAuthInfo, ok := p.AuthInfo.(AuthInfo) 63 | if !ok { 64 | return nil, errors.New("no S2AAuthInfo found in Peer") 65 | } 66 | return s2aAuthInfo, nil 67 | } 68 | 69 | // AuthInfoFromContext extracts the authinfo.S2AAuthInfo object from the given 70 | // context, if it exists. This API should be used by gRPC server RPC handlers 71 | // to get information about the peer. On the client-side, use the grpc.Peer() 72 | // CallOption and the AuthInfoFromPeer function. 73 | func AuthInfoFromContext(ctx context.Context) (AuthInfo, error) { 74 | p, ok := peer.FromContext(ctx) 75 | if !ok { 76 | return nil, errors.New("no Peer found in Context") 77 | } 78 | return AuthInfoFromPeer(p) 79 | } 80 | -------------------------------------------------------------------------------- /s2a_utils_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2021 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | package s2a 20 | 21 | import ( 22 | "context" 23 | "testing" 24 | 25 | commonpb "github.com/google/s2a-go/internal/proto/common_go_proto" 26 | "google.golang.org/grpc/credentials" 27 | "google.golang.org/grpc/peer" 28 | ) 29 | 30 | func TestAuthInfoFromContext(t *testing.T) { 31 | ctx := context.Background() 32 | s2aAuthInfo := &fakeS2AAuthInfo{} 33 | p := &peer.Peer{ 34 | AuthInfo: s2aAuthInfo, 35 | } 36 | for _, tc := range []struct { 37 | desc string 38 | ctx context.Context 39 | success bool 40 | out AuthInfo 41 | }{ 42 | { 43 | "working case", 44 | peer.NewContext(ctx, p), 45 | true, 46 | s2aAuthInfo, 47 | }, 48 | } { 49 | authInfo, err := AuthInfoFromContext(tc.ctx) 50 | if got, want := (err == nil), tc.success; got != want { 51 | t.Errorf("%v: AuthInfoFromContext(_)=(err=nil)=%v, want %v", tc.desc, got, want) 52 | } 53 | if got, want := authInfo, tc.out; got != want { 54 | t.Errorf("%v:, AuthInfoFromContext(_)=(%v, _), want (%v, _)", tc.desc, got, want) 55 | } 56 | } 57 | } 58 | 59 | func TestAuthInfoFromPeer(t *testing.T) { 60 | s2aAuthInfo := &fakeS2AAuthInfo{} 61 | p := &peer.Peer{ 62 | AuthInfo: s2aAuthInfo, 63 | } 64 | for _, tc := range []struct { 65 | desc string 66 | p *peer.Peer 67 | success bool 68 | out AuthInfo 69 | }{ 70 | { 71 | "working case", 72 | p, 73 | true, 74 | s2aAuthInfo, 75 | }, 76 | } { 77 | authInfo, err := AuthInfoFromPeer(tc.p) 78 | if got, want := (err == nil), tc.success; got != want { 79 | t.Errorf("%v: AuthInfoFromPeer(_)=(err=nil)=%v, want %v", tc.desc, got, want) 80 | } 81 | if got, want := authInfo, tc.out; got != want { 82 | t.Errorf("%v:, AuthInfoFromPeer(_)=(%v, _), want (%v, _)", tc.desc, got, want) 83 | } 84 | } 85 | } 86 | 87 | type fakeS2AAuthInfo struct{} 88 | 89 | func (*fakeS2AAuthInfo) AuthType() string { return "" } 90 | func (*fakeS2AAuthInfo) ApplicationProtocol() string { return "" } 91 | func (*fakeS2AAuthInfo) TLSVersion() commonpb.TLSVersion { return commonpb.TLSVersion_TLS1_3 } 92 | func (*fakeS2AAuthInfo) Ciphersuite() commonpb.Ciphersuite { 93 | return commonpb.Ciphersuite_AES_128_GCM_SHA256 94 | } 95 | func (*fakeS2AAuthInfo) PeerIdentity() *commonpb.Identity { return nil } 96 | func (*fakeS2AAuthInfo) LocalIdentity() *commonpb.Identity { return nil } 97 | func (*fakeS2AAuthInfo) PeerCertFingerprint() []byte { return nil } 98 | func (*fakeS2AAuthInfo) LocalCertFingerprint() []byte { return nil } 99 | func (*fakeS2AAuthInfo) IsHandshakeResumed() bool { return false } 100 | func (*fakeS2AAuthInfo) SecurityLevel() credentials.SecurityLevel { 101 | return credentials.PrivacyAndIntegrity 102 | } 103 | -------------------------------------------------------------------------------- /stream/s2a_stream.go: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright 2023 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | 19 | // Package stream provides an interface for bidirectional streaming to the S2A server. 20 | package stream 21 | 22 | import ( 23 | "context" 24 | 25 | s2av2pb "github.com/google/s2a-go/internal/proto/v2/s2a_go_proto" 26 | ) 27 | 28 | // S2AStream defines the operation for communicating with the S2A server over a bidirectional stream. 29 | type S2AStream interface { 30 | // Send sends the message to the S2A server. 31 | Send(*s2av2pb.SessionReq) error 32 | // Recv receives the message from the S2A server. 33 | Recv() (*s2av2pb.SessionResp, error) 34 | // Closes the channel to the S2A server. 35 | CloseSend() error 36 | } 37 | 38 | // GetS2AStream type is for generating an S2AStream interface for talking to the S2A server. 39 | type GetS2AStream func(ctx context.Context, s2av2Address string, opts ...string) (S2AStream, error) 40 | -------------------------------------------------------------------------------- /testdata/README.md: -------------------------------------------------------------------------------- 1 | **Generating certificates and keys for testing mTLS-S2A** 2 | 3 | Create root CA 4 | ``` 5 | openssl req -x509 -sha256 -days 7305 -newkey rsa:2048 -keyout mds_root_key.pem -out mds_root_cert.pem 6 | ``` 7 | 8 | Generate private keys for server and client 9 | ``` 10 | openssl genrsa -out mds_server_key.pem 2048 11 | openssl genrsa -out mds_client_key.pem 2048 12 | ``` 13 | 14 | Generate CSRs for server and client 15 | ``` 16 | openssl req -key mds_server_key.pem -new -out mds_server.csr -config config.cnf 17 | openssl req -key mds_client_key.pem -new -out mds_client.csr -config config.cnf 18 | ``` 19 | 20 | Look at CSR 21 | ``` 22 | openssl req -noout -text -in mds_server.csr 23 | openssl req -noout -text -in mds_client.csr 24 | ``` 25 | 26 | Sign CSRs for server and client 27 | ``` 28 | openssl x509 -req -CA mds_root_cert.pem -CAkey mds_root_key.pem -in mds_server.csr -out mds_server_cert.pem -days 7305 -extfile config.cnf -extensions req_ext 29 | openssl x509 -req -CA mds_root_cert.pem -CAkey mds_root_key.pem -in mds_client.csr -out mds_client_cert.pem -days 7305 30 | ``` 31 | 32 | Look at signed certs 33 | ``` 34 | openssl x509 -in mds_server_cert.pem -noout -text 35 | openssl x509 -in mds_client_cert.pem -noout -text 36 | ``` 37 | 38 | Verify server and client certs using root CA 39 | ``` 40 | openssl verify -CAfile mds_root_cert.pem mds_server_cert.pem 41 | openssl verify -CAfile mds_root_cert.pem mds_client_cert.pem 42 | ``` 43 | 44 | Create self-signed key/cert to test failure case 45 | ``` 46 | openssl genrsa -out self_signed_key.pem 2048 47 | openssl req -new -key self_signed_key.pem -out self_signed.csr 48 | openssl x509 -req -in self_signed.csr -signkey self_signed_key.pem -out self_signed_cert.pem -days 7305 49 | ``` 50 | -------------------------------------------------------------------------------- /testdata/client_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID8TCCAtmgAwIBAgIUKXNlBRVe6UepjQUijIFPZBd/4qYwDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNTMxMjAwMzE1WhcNNDIwNTI2MjAwMzE1WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAOOFuIucH7XXfohGxKd3uR/ihUA/LdduR9I8kfpUEbq5BOt8xZe5/Yn9 11 | a1ozEHVW6cOAbHbnwAR8tkSgZ/t42QIA2k77HWU1Jh2xiEIsJivo3imm4/kZWuR0 12 | OqPh7MhzxpR/hvNwpI5mJsAVBWFMa5KtecFZLnyZtwHylrRN1QXzuLrOxuKFufK3 13 | RKbTABScn5RbZL976H/jgfSeXrbt242NrIoBnVe6fRbekbq2DQ6zFArbQMUgHjHK 14 | P0UqBgdr1QmHfi9KytFyx9BTP3gXWnWIu+bY7/v7qKJMHFwGETo+dCLWYevJL316 15 | HnLfhApDMfP8U+Yv/y1N/YvgaSOSlEcCAwEAAaNTMFEwHQYDVR0OBBYEFKhAU4nu 16 | 0h/lrnggbIGvx4ej0WklMB8GA1UdIwQYMBaAFKhAU4nu0h/lrnggbIGvx4ej0Wkl 17 | MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAE/6NghzQ5fu6yR6 18 | EHKbj/YMrFdT7aGn5n2sAf7wJ33LIhiFHkpWBsVlm7rDtZtwhe891ZK/P60anlg9 19 | /P0Ua53tSRVRmCvTnEbXWOVMN4is6MsR7BlmzUxl4AtIn7jbeifEwRL7B4xDYmdA 20 | QrQnsqoz45dLgS5xK4WDqXATP09Q91xQDuhud/b+A4jrvgwFASmL7rMIZbp4f1JQ 21 | nlnl/9VoTBQBvJiWkDUtQDMpRLtauddEkv4AGz75p5IspXWD6cOemuh2iQec11xD 22 | X20rs2WZbAcAiUa3nmy8OKYw435vmpj8gp39WYbX/Yx9TymrFFbVY92wYn+quTco 23 | pKklVz0= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /testdata/client_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEA44W4i5wftdd+iEbEp3e5H+KFQD8t125H0jyR+lQRurkE63zF 3 | l7n9if1rWjMQdVbpw4BsdufABHy2RKBn+3jZAgDaTvsdZTUmHbGIQiwmK+jeKabj 4 | +Rla5HQ6o+HsyHPGlH+G83CkjmYmwBUFYUxrkq15wVkufJm3AfKWtE3VBfO4us7G 5 | 4oW58rdEptMAFJyflFtkv3vof+OB9J5etu3bjY2sigGdV7p9Ft6RurYNDrMUCttA 6 | xSAeMco/RSoGB2vVCYd+L0rK0XLH0FM/eBdadYi75tjv+/uookwcXAYROj50ItZh 7 | 68kvfXoect+ECkMx8/xT5i//LU39i+BpI5KURwIDAQABAoIBABgyjo/6iLzUMFbZ 8 | /+w3pW6orrdIgN2akvTfED9pVYFgUA+jc3hRhY95bkNnjuaL2cy7Cc4Tk65mfRQL 9 | Y0OxdJLr+EvSFSxAXM9npDA1ddHRsF8JqtFBSxNk8R+g1Yf0GDiO35Fgd3/ViWWA 10 | VtQkRoSRApP3oiQKTRZd8H04keFR+PvmDk/Lq11l3Kc24A1PevKIPX1oI990ggw9 11 | 9i4uSV+cnuMxmcI9xxJtgwdDFdjr39l2arLOHr4s6LGoV2IOdXHNlv5xRqWUZ0FH 12 | MDHowkLgwDrdSTnNeaVNkce14Gqx+bd4hNaLCdKXMpedBTEmrut3f3hdV1kKjaKt 13 | aqRYr8ECgYEA/YDGZY2jvFoHHBywlqmEMFrrCvQGH51m5R1Ntpkzr+Rh3YCmrpvq 14 | xgwJXING0PUw3dz+xrH5lJICrfNE5Kt3fPu1rAEy+13mYsNowghtUq2Rtu0Hsjjx 15 | 2E3Bf8vEB6RNBMmGkUpTTIAroGF5tpJoRvfnWax+k4pFdrKYFtyZdNcCgYEA5cNv 16 | EPltvOobjTXlUmtVP3n27KZN2aXexTcagLzRxE9CV4cYySENl3KuOMmccaZpIl6z 17 | aHk6BT4X+M0LqElNUczrInfVqI+SGAFLGy7W6CJaqSr6cpyFUP/fosKpm6wKGgLq 18 | udHfpvz5rckhKd8kJxFLvhGOK9yN5qpzih0gfhECgYAJfwRvk3G5wYmYpP58dlcs 19 | VIuPenqsPoI3PPTHTU/hW+XKnWIhElgmGRdUrto9Q6IT/Y5RtSMLTLjq+Tzwb/fm 20 | 56rziYv2XJsfwgAvnI8z1Kqrto9ePsHYf3krJ1/thVsZPc9bq/QY3ohD1sLvcuaT 21 | GgBBnLOVJU3a12/ZE2RwOwKBgF0csWMAoj8/5IB6if+3ral2xOGsl7oPZVMo/J2V 22 | Z7EVqb4M6rd/pKFugTpUQgkwtkSOekhpcGD1hAN5HTNK2YG/+L5UMAsKe9sskwJm 23 | HgOfAHy0BSDzW3ey6i9skg2bT9Cww+0gJ3Hl7U1HSCBO5LjMYpSZSrNtwzfqdb5Q 24 | BX3xAoGARZdR28Ej3+/+0+fz47Yu2h4z0EI/EbrudLOWY936jIeAVwHckI3+BuqH 25 | qR4poj1gfbnMxNuI9UzIXzjEmGewx9kDZ7IYnvloZKqoVQODO5GlKF2ja6IcMNlh 26 | GCNdD6PSAS6HcmalmWo9sj+1YMkrl+GJikKZqVBHrHNwMGAG67w= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /testdata/config.cnf: -------------------------------------------------------------------------------- 1 | [req] 2 | distinguished_name = req_distinguished_name 3 | req_extensions = req_ext 4 | 5 | [req_distinguished_name] 6 | countryName = Country Name (2 letter code) 7 | stateOrProvinceName = State or Province Name (full name) 8 | localityName = Locality Name (eg, city) 9 | organizationalUnitName = Organizational Unit Name (eg, section) 10 | commonName = Common Name (eg, your name or your server\'s hostname) 11 | emailAddress = Email Address 12 | 13 | [req_ext] 14 | subjectAltName = @alt_names 15 | 16 | [alt_names] 17 | IP.1 = :: 18 | -------------------------------------------------------------------------------- /testdata/mds_client.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICrDCCAZQCAQAwOTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMR0wGwYDVQQD 3 | DBR0ZXN0LXMyYS1tdGxzLWNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 4 | AQoCggEBAKq0EDMsTbZnQgfrmN7M4EbHz6ygvk1fRbrJ3fD32glbhkxnEgSjNNfJ 5 | 1dkw59yGBUNR4C6RsBsDhQwW98tKPYtv5dlSckq4l9RkjV+pw5lWrEJTtcLjiwj+ 6 | /y0Zju2+iorHuVtCBYWGqbSslp3pJ9qUtLQI4pqqX59sNFOhQxrUFKoP7a0EJhrU 7 | 0iR42wPjhXdBBQtfChj/EPozjGjJCUZqXhIgD8hzw6DIakDU9ukQKb/Y9lM6OErl 8 | 8xx+k3AHZtfsxvhF2P1GSl/aA5Em8CCbzfoApjcjkS2pSddoLBmDgozHfCtJpVwa 9 | q5pmzlR1W1JvdOtpYRO8efQAPAyuA6ECAwEAAaAuMCwGCSqGSIb3DQEJDjEfMB0w 10 | GwYDVR0RBBQwEocQAAAAAAAAAAAAAAAAAAAAADANBgkqhkiG9w0BAQsFAAOCAQEA 11 | i3A/Evfcv87UG1Egp9IDvhYZ6ieWsbxzmcgAWJmYT7jWpxA7tO6UsS2i7ZZHHMK/ 12 | 6hROqLRSWgK/Br5LVw83WT40CdC0A5sQRm2LhYisZfMWX3wZ7NjIH+AuK/4s517b 13 | V46WQ/WcIks1Wd6IKRJec7R0C3RPWMfS8Ucu8xWHWkup0qP2OHX5k47pxpl8xCoS 14 | YNeeVyX2D6pOV/sEP0HKBQZ9VsufoN+hojfQDn5fH31rutV3yK5LeVRXZFQLAW8I 15 | 1Ep7+t6Y1NTjnfUr9ennf4JeQWdloDOF4OLoyWIX6zSNEPZV6eaWQpur+qkmZo19 16 | 8xeGpL7742J/sx0JREXTMg== 17 | -----END CERTIFICATE REQUEST----- 18 | -------------------------------------------------------------------------------- /testdata/mds_client_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDCDCCAfACFFlYsYCFit01ZpYmfjxpo7/6wMEbMA0GCSqGSIb3DQEBCwUAMEgx 3 | CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEPMA0GA1UECgwGR29vZ2xlMRswGQYD 4 | VQQDDBJ0ZXN0LXMyYS1tdGxzLXJvb3QwHhcNMjMwODIyMTY0NTE4WhcNNDMwODIy 5 | MTY0NTE4WjA5MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExHTAbBgNVBAMMFHRl 6 | c3QtczJhLW10bHMtY2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC 7 | AQEAqrQQMyxNtmdCB+uY3szgRsfPrKC+TV9Fusnd8PfaCVuGTGcSBKM018nV2TDn 8 | 3IYFQ1HgLpGwGwOFDBb3y0o9i2/l2VJySriX1GSNX6nDmVasQlO1wuOLCP7/LRmO 9 | 7b6Kise5W0IFhYaptKyWnekn2pS0tAjimqpfn2w0U6FDGtQUqg/trQQmGtTSJHjb 10 | A+OFd0EFC18KGP8Q+jOMaMkJRmpeEiAPyHPDoMhqQNT26RApv9j2Uzo4SuXzHH6T 11 | cAdm1+zG+EXY/UZKX9oDkSbwIJvN+gCmNyORLalJ12gsGYOCjMd8K0mlXBqrmmbO 12 | VHVbUm9062lhE7x59AA8DK4DoQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCPOvtL 13 | dq2hxFHlIy0YUK8jp/DtwJZPwzx1id5FtWwd0CxBS1StIgmkHMxtkJGz1iyQLplI 14 | je+Msd4sTsb5zZi/8kGKehi8Wj4lghp4oP30cpob41OvM68M9RC/wSOVk9igSww+ 15 | l3zof6wKRIswsi5VHrL16ruIVVoDlyFbKr8yk+cp9OPOV8hNNN7ewY9xC8OgnTt8 16 | YtdaLe6uTplKBLW+j3GtshigRhyfkGJyPFYL4LAeDJCHlC1qmBnkyP0ijMp6vneM 17 | E8TLavnMTMcpihWTWpyKeRkO6HDRsP4AofQAp7VAiAdSOplga+w2qgrVICV+m8MK 18 | BTq2PBvc59T6OFLq 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /testdata/mds_client_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCqtBAzLE22Z0IH 3 | 65jezOBGx8+soL5NX0W6yd3w99oJW4ZMZxIEozTXydXZMOfchgVDUeAukbAbA4UM 4 | FvfLSj2Lb+XZUnJKuJfUZI1fqcOZVqxCU7XC44sI/v8tGY7tvoqKx7lbQgWFhqm0 5 | rJad6SfalLS0COKaql+fbDRToUMa1BSqD+2tBCYa1NIkeNsD44V3QQULXwoY/xD6 6 | M4xoyQlGal4SIA/Ic8OgyGpA1PbpECm/2PZTOjhK5fMcfpNwB2bX7Mb4Rdj9Rkpf 7 | 2gORJvAgm836AKY3I5EtqUnXaCwZg4KMx3wrSaVcGquaZs5UdVtSb3TraWETvHn0 8 | ADwMrgOhAgMBAAECggEAUccupZ1ZY4OHTi0PkNk8rpwFwTFGyeFVEf2ofkr24RnA 9 | NnUAXEllxOUUNlcoFOz9s3kTeavg3qgqgpa0QmdAIb9LMXg+ec6CKkW7trMpGho8 10 | LxBUWNfSoU4sKEqAvyPT0lWJVo9D/up6/avbAi6TIbOw+Djzel4ZrlHTpabxc3WT 11 | EilXzn4q54b3MzxCQeQjcnzTieW4Q5semG2kLiXFToHIY2di01P/O8awUjgrD+uW 12 | /Cb6H49MnHm9VPkqea1iwZeMQd6Gh5FrC7RezsBjdB1JBcfsv6PFt2ySInjB8SF+ 13 | XR5Gr3Cc5sh9s0LfprZ9Dq0rlSWmwasPMI1COK6SswKBgQDczgeWd3erQ1JX9LEI 14 | wollawqC9y7uJhEsw1hrPqA3uqZYiLUc7Nmi4laZ12mcGoXNDS3R3XmD58qGmGaU 15 | lxEVTb8KDVWBgw450VoBKzSMQnCP6zn4nZxTYxeqMKjDGf6TRB6TZc843qsG3eRC 16 | k91yxrCQ/0HV6PT48C+lieDzLwKBgQDF6aNKiyrswr457undBnM1H8q/Y6xC5ZlK 17 | UtiQdhuyBnicvz0U8WPxBY/8gha0OXWuSnBqq/z77iFVNv/zT6p9K7kM7nBGd8cB 18 | 8KO6FNbyaHWFrhCI5zNzRTH4oha0hfvUOoti09vqavCtWD4L+D/63ba1wNLKPO9o 19 | 4gWbCnUCLwKBgQC/vus372csgrnvR761LLrEJ8BpGt7WUJh5luoht7DKtHvgRleB 20 | Vu1oVcV+s2Iy/ZVUDC3OIdZ0hcWKPK5YOxfKuEk+IXYvke+4peTTPwHTC59UW6Fs 21 | FPK8N0FFuhvT0a8RlAY5WiAp8rPysp6WcnHMSl7qi8BQUozp4Sp/RsziYQKBgBXv 22 | r4mzoy5a53rEYGd/L4XT4EUWZyGDEVqLlDVu4eL5lKTLDZokp08vrqXuRVX0iHap 23 | CYzJQ2EpI8iuL/BoBB2bmwcz5n3pCMXORld5t9lmeqA2it6hwbIlGUTVsm6P6zm6 24 | w3hQwy9YaxTLkxUAjxbfPEEo/jQsTNzzMGve3NlBAoGAbgJExpDyMDnaD2Vi5eyr 25 | 63b54BsqeLHqxJmADifyRCj7G1SJMm3zMKkNNOS0vsXgoiId973STFf1XQiojiv8 26 | Slbxyv5rczcY0n3LOuQYcM5OzsjzpNFZsT2dDnMfNRUF3rx3Geu/FuJ9scF1b00r 27 | fVMrcL3jSf/W1Xh4TgtyoU8= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /testdata/mds_root_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDcTCCAlmgAwIBAgIUDUkgI+2FZtuUHyUUi0ZBH7JvN00wDQYJKoZIhvcNAQEL 3 | BQAwSDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ8wDQYDVQQKDAZHb29nbGUx 4 | GzAZBgNVBAMMEnRlc3QtczJhLW10bHMtcm9vdDAeFw0yMzA4MjEyMTI5MTVaFw00 5 | MzA4MjEyMTI5MTVaMEgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEPMA0GA1UE 6 | CgwGR29vZ2xlMRswGQYDVQQDDBJ0ZXN0LXMyYS1tdGxzLXJvb3QwggEiMA0GCSqG 7 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbFEQfpvla27bATedrN4BAWsI9GSwSnJLW 8 | QWzXcnAk6cKxQBAhnaKHRxHY8ttLhNTtxQeub894CLzJvHE/0xDhuMzjtCCCZ7i2 9 | r08tKZ1KcEzPJCPNlxlzAXPA45XU3LRlbGvju/PBPhm6n1hCEKTNI/KETJ5DEaYg 10 | Cf2LcXVsl/zW20MwDZ+e2w/9a2a6n6DdpW1ekOR550hXAUOIxvmXRBeYeGLFvp1n 11 | rQgZBhRaxP03UB+PQD2oMi/4mfsS96uGCXdzzX8qV46O8m132HUbnA/wagIwboEe 12 | d7Bx237dERDyHw5GFnll7orgA0FOtoEufXdeQxWVvTjO0+PVPgsvAgMBAAGjUzBR 13 | MB0GA1UdDgQWBBRyMtg/yutV8hw8vOq0i8x0eBQi7DAfBgNVHSMEGDAWgBRyMtg/ 14 | yutV8hw8vOq0i8x0eBQi7DAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA 15 | A4IBAQArN/gdqWMxd5Rvq2eJMTp6I4RepJOT7Go4sMsRsy1caJqqcoS2EvREDZMN 16 | XNEBcyQBB5kYd6TCcZGoLnEtWYXQ4jjEiXG1g7/+rWxyqw0ZYuP7FWzuHg3Uor/x 17 | fApbEKwptP5ywVc+33h4qreGcqXkVCCn+sAcstGgrqubdGZW2T5gazUMyammOOuN 18 | 9IWL1PbvXmgEKD+80NUIrk09zanYyrElGdU/zw/kUbZ3Jf6WUBtJGhTzRQ1qZeKa 19 | VnpCbLoG3vObEB8mxDUAlIzwAtfvw4U32BVIZA8xrocz6OOoAnSW1bTlo3EOIo/G 20 | MTV7jmY9TBPtfhRuO/cG650+F+cw 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /testdata/mds_root_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIIxtHqH4HVrACAggA 3 | MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECFjU1fjS/n59BIIEyNzJwdg/x5JP 4 | dZFh+k6NWaaomXf9yurqA9fZtw8LrjMWiFdL/FjpWUVoxk+75BZdtwXGOnGHV1Ks 5 | nPj+1dcc3Vlnli2LhtJVtZbjHWwJUtSMXT4s1aBS9r1gUHA9toxsWBqnRKcjJpFd 6 | rnt12WdrEmPPJdz1pZyi3TM7q0XWS75OvFW9WdA+FJwyidlG4Y/doGmRYb7ObqHv 7 | PLadtlC7WtZOuNswDxZAyMgGAS10Kk3pohMZ1RCaa/7J625zlmx3Ps1U3PzchvPI 8 | MEv+Y8g5hkEbRP8tIpcuOrzwNsmQ5VkNeQmD6CAgKAyqwwmJAlKzCvJnXLJa+nsD 9 | iSMXPk7tJasLLHFYO4InZO1zuk8WL+AajnYYaipiC1sOxOfegaxjMAjV2qiqrDrE 10 | TwIEk/SbDOFd80dEQgVz++5BYhxdCiplL2aO5s8Cw9slhfEXb/XohIbEKvO5oeFD 11 | fqdQLkEZ0IEEg/0d5jO4bdNiXIsGTV6WlVbQXmihqpDiP8GHabGBDWI1Ov1fj4e6 12 | Vx22bQucRM/IdkSebNZguL4PFBVBKZAC+uM1sxO8h5HRfquI5TjuAnbvp7PQ1a94 13 | un5LCWN3ydMrzC9jdm3pzVb+Rt+J2JzhOJfJSHuAFhUnSWsCrNS/+QFH+/QffQ0r 14 | Ki6XBydmhKelJo0m+T5RbodKDlEVRbExDdQe6k7SZiYhyF/FEB1NjVwLHFUr02cj 15 | URilU5WEoJF85T07zh1hzZHP+grsKgmVE8b7qsA51OVyac0TW58qWXdm5UaYvGqJ 16 | gRYA7EuvFHlfqgxRsupNlCO95vk8Dz2LbHwgt/Q0rXcDXLwC10ycbo0JIRF2zMW5 17 | 2DuCEYweByFv8x8FwIYj/ForlCWXLQjXkiB/nkyjzGOiNG3PQzy61BceYfhkAs49 18 | ZYt/BseXwNOgizgXKY7jyWU7g6R29isq90sg3sYp/y2MHh/OsHHWC3nSSHoBRa23 19 | FUkB0hogd7RJCXrNo/s9QfEuRZlQLfj1iogGuOK4vrne15WMU3Yu7Bi5is/KuzIj 20 | xm/mjq3GMaENk2Mz4FyCy77H2w/coQuki5FjiYwXFRHyhpkYl7ePyfLT19t7b4Mt 21 | 3w1cfq1hrY37UbFGJM5mzKzcjFGSzcIxyGhHNGqrYKJSKfSOJAroD8v4l0cJLQ2M 22 | alEPpDvT5/Nkvzvwd3tH6Rqli6AHlYy4OxJXTr567bpjclZHGOq+7wWjPRalRDiY 23 | Gqj1ARE8+Qa/WLVAZM2GRZ2uZ/eQ12rS28gofSUr8Ur4ELdiFKHw+b9Nz9bIGquM 24 | M8EW0GutSJvqJ+q9Xn722C5SkQp/oMSImL2lmHWZeHr5mgoNH5AqwBm1r01GRnVt 25 | jNO8Poi+ncPSRP0Peq/qQ5kXEx5phCPNm6ZFcCrEipv798xm7eebUM474RICMRFC 26 | +XKVLlT8er4jZ1HSncvvtTx17OiyYh2PaPRH8GQW8t0nfs/YclH+qcQCAmIsEBCo 27 | 391KjCKYXeKR9bigZWErphjxDFK+m0vXUtW2jGAVj05XLddTc0oeCH2gyzRZx1gy 28 | iHzL0mRJXFaBAcoOb78L/0mWwfn7CP4klYenhingE7lQXB30Rzr/rr54I4+sofnF 29 | T6/FrKRlfUmczNYDQIixHw== 30 | -----END ENCRYPTED PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /testdata/mds_server.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICrDCCAZQCAQAwOTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMR0wGwYDVQQD 3 | DBR0ZXN0LXMyYS1tdGxzLXNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 4 | AQoCggEBAIwTPJuwY+p+H3YYvDLjea3yRAMXfO2vzLTpHBTWFWdjtCpgrihum+Ee 5 | QlWdPP2DA0EXefmdRqWpHNpy2V/Y8LJ032hJg0I7yy9Waju/DUKV4oAoUCJXlCcf 6 | vpCWoPXmgmt6HudIzxHiqPkq6Qge+3Rw3SAPoIlDMhREO2wonCRbfJCNjJP8UAoZ 7 | i0WsHpu4OfcSDcezDrPu6PsLMsGxKXsEgatAgtulsj2cU1PetRNSFdkpj/dS0kA5 8 | vroCNOYxsPXpEZhlHgmw/HoKy2F6J8nphIjv2vkqAPfvNfSMxcVaKa9vZKZmYV4u 9 | iiG0Lwru5PKOb91E7Hqcdd0O3lNBhccCAwEAAaAuMCwGCSqGSIb3DQEJDjEfMB0w 10 | GwYDVR0RBBQwEocQAAAAAAAAAAAAAAAAAAAAADANBgkqhkiG9w0BAQsFAAOCAQEA 11 | glGG7pd5jffzc7qJfSl5WlglTFkBSVYNz/6nZ33GfAfm2O/SZYYW4+XbGZUsLkzm 12 | ifeNB3i/C9yu4C8EMmU3o2nlAVGhoKnwqC5PO/vnnvo8EKtNiqg5eJMnMulZgpc9 13 | QmL+gQ0715UnVhAIhivftpFqaDhAwyubicQ7AC4W/x2KXaJ36UU4ehXI1xr33m1+ 14 | 48p+lVyR8UUuCVKVoqndAaebE4c9lqhTfM6cL8Pruve1/IJ/xdxcAW+KKIr4uzcp 15 | 30Pd/Ts6XEeVY9i++yMypl7BNemw4mQQ1i3bpvzN+tgb5AtmbyD72bC2nJn0HlLd 16 | umOUQ3HqOVMYgx+3jJTO5g== 17 | -----END CERTIFICATE REQUEST----- 18 | -------------------------------------------------------------------------------- /testdata/mds_server_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDbjCCAlagAwIBAgIUbexZ5sZl86Al9dsI2PkOgtqKnkgwDQYJKoZIhvcNAQEL 3 | BQAwSDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ8wDQYDVQQKDAZHb29nbGUx 4 | GzAZBgNVBAMMEnRlc3QtczJhLW10bHMtcm9vdDAeFw0yMzA4MjIwMDMyMDRaFw00 5 | MzA4MjIwMDMyMDRaMDkxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEdMBsGA1UE 6 | AwwUdGVzdC1zMmEtbXRscy1zZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw 7 | ggEKAoIBAQCMEzybsGPqfh92GLwy43mt8kQDF3ztr8y06RwU1hVnY7QqYK4obpvh 8 | HkJVnTz9gwNBF3n5nUalqRzactlf2PCydN9oSYNCO8svVmo7vw1CleKAKFAiV5Qn 9 | H76QlqD15oJreh7nSM8R4qj5KukIHvt0cN0gD6CJQzIURDtsKJwkW3yQjYyT/FAK 10 | GYtFrB6buDn3Eg3Hsw6z7uj7CzLBsSl7BIGrQILbpbI9nFNT3rUTUhXZKY/3UtJA 11 | Ob66AjTmMbD16RGYZR4JsPx6CstheifJ6YSI79r5KgD37zX0jMXFWimvb2SmZmFe 12 | LoohtC8K7uTyjm/dROx6nHXdDt5TQYXHAgMBAAGjXzBdMBsGA1UdEQQUMBKHEAAA 13 | AAAAAAAAAAAAAAAAAAAwHQYDVR0OBBYEFI3i2+tIk6YYn0MIxC0q93jk1VsUMB8G 14 | A1UdIwQYMBaAFHIy2D/K61XyHDy86rSLzHR4FCLsMA0GCSqGSIb3DQEBCwUAA4IB 15 | AQAUhk+s/lrIAULBbU7E22C8f93AzTxE1mhyHGNlfPPJP3t1Dl+h4X4WkFpkz5gT 16 | EcNXB//Vvoq99HbEK5/92sxsIPexKdJBdcggeHXIgLDkOrEZEb0Nnh9eaAuU2QDn 17 | JW44hMB+aF6mEaJvOHE6DRkQw3hwFYFisFKKHtlQ3TyOhw5CHGzSExPZusdSFNIe 18 | 2E7V/0QzGPJEFnEFUNe9N8nTH2P385Paoi+5+Iizlp/nztVXfzv0Cj/i+qGgtDUs 19 | HB+gBU2wxMw8eYyuNzACH70wqGR1Parj8/JoyYhx0S4+Gjzy3JH3CcAMaxyfH/dI 20 | 4Wcvfz/isxgmH1UqIt3oc6ad 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /testdata/mds_server_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCMEzybsGPqfh92 3 | GLwy43mt8kQDF3ztr8y06RwU1hVnY7QqYK4obpvhHkJVnTz9gwNBF3n5nUalqRza 4 | ctlf2PCydN9oSYNCO8svVmo7vw1CleKAKFAiV5QnH76QlqD15oJreh7nSM8R4qj5 5 | KukIHvt0cN0gD6CJQzIURDtsKJwkW3yQjYyT/FAKGYtFrB6buDn3Eg3Hsw6z7uj7 6 | CzLBsSl7BIGrQILbpbI9nFNT3rUTUhXZKY/3UtJAOb66AjTmMbD16RGYZR4JsPx6 7 | CstheifJ6YSI79r5KgD37zX0jMXFWimvb2SmZmFeLoohtC8K7uTyjm/dROx6nHXd 8 | Dt5TQYXHAgMBAAECggEAIB5zGdIG/yh/Z1GBqfuOFaxFGx5iJ5BVlLAVH9P9IXFz 9 | yPnVRXEjbinFlSMSbqEBeIX9EpcVMXxHIPIP1RIGEy2IYr3kiqXyT771ahDDZh6/ 10 | Spqz0UQatSPqyvW3H9uE0Uc12dvQm23JSCUmPRX5m7gbhDQBIChXzdzdcU4Yi59V 11 | 4xmJUvbsAcLw5CBM6kwV+1NGVH9+3mUdhrr9M6B6+sVB/xnaqMGEDfQGiwL8U7EY 12 | QOuc46KXu3Pd/qCdVLn60IrdjSzDJKeC5UZZ+ejNAo+DfbtOovBj3qu3OCUg4XVy 13 | 0CDBJ1sTdLvUfF4Gb+crjPsd+qBbXcjVfqdadwhsoQKBgQDBF1Pys/NitW8okJwp 14 | 2fiDIASP3TiI+MthWHGyuoZGPvmXQ3H6iuLSm8c/iYI2WPTf53Xff1VcFm1GmQms 15 | GCsYM8Ax94zCeO6Ei1sYYxwcBloEZfOeV37MPA4pjJF4Lt+n5nveNxP+lrsjksJz 16 | wToSEgWPDT1b/xcdt4/5j9J85wKBgQC5tiLx+33mwH4DoaFRmSl0+VuSNYFw6DTQ 17 | SQ+kWqWGH4NENc9wf4Dj2VUZQhpXNhXVSxj+aP2d/ck1NrTJAWqYEXCDtFQOGSa2 18 | cGPRr+Fhy5NIEaEvR7IXcMBZzx3koYmWVBHricyrXs5FvHrT3N14mGDUG8n24U3f 19 | R799bau0IQKBgQC97UM+lHCPJCWNggiJRgSifcje9VtZp1btjoBvq/bNe74nYkjn 20 | htsrC91Fiu1Qpdlfr50K1IXSyaB886VG6JLjAGxI+dUzqJ38M9LLvxj0G+9JKjsi 21 | AbAQFfZcOg8QZxLJZPVsE0MQhZTXndC06VhEVAOxvPUg214Sde8hK61/+wKBgCRw 22 | O10VhnePT2pw/VEgZ0T/ZFtEylgYB7zSiRIrgwzVBBGPKVueePC8BPmGwdpYz2Hh 23 | cU8B1Ll6QU+Co2hJMdwSl+wPpup5PuJPHRbYlrV0lzpt0x2OyL/WrLcyb2Ab3f40 24 | EqwPhqwdVwXR3JvTW1U9OMqFhVQ+kuP7lPQMX8NhAoGBAJOgZ7Tokipc4Mi68Olw 25 | SCaOPvjjy4sW2rTRuKyjc1wTAzy7SJ3vXHfGkkN99nTLJFwAyJhWUpnRdwAXGi+x 26 | gyOa95ImsEfRSwEjbluWfF8/P0IU8GR+ZTqT4NnNCOsi8T/xst4Szd1ECJNnnZDe 27 | 1ChfPP1AH+/75MJCvu6wQBQv 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /testdata/self_signed.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICkjCCAXoCAQAwTTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ0wCwYDVQQK 3 | DARUZXN0MSIwIAYDVQQDDBl0ZXN0LXMyYS1tdGxzLXNlbGYtc2lnbmVkMIIBIjAN 4 | BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoUU+xhqwpl4IUsReXdGkT9k5cV7a 5 | WG60hqVKlm8Kayj6ZAahnhwcrsC36QOMGLkKudeRhzDuq5ACEeBTR+uFZ2Pu2xYd 6 | RS2rtPx5oZYoGdUP1+X4yO0CXUGaFfBX2pEFuPgR6xIoYNIakp/rp063PDzclsFx 7 | TteU8AfVzXOjYZcLWGKZxn5JUYdWs6Ofg2Z4WzyD3j8OR7x1aQfC/lhMxW6AUrjk 8 | rEqBI4qSviRrs8IHODEKdbjBhJk1EdzGuqSICs7YcBCrQAKvu759UNgf//2Y/ZkA 9 | Oj/NyHs7nKGSI1uNckhGum0NYS5VgxGWhgOFPvveHttX9DRajQ1Aa1qwnwIDAQAB 10 | oAAwDQYJKoZIhvcNAQELBQADggEBAHKusdAj6/hNNSZIPQhUpm+eMYWZrLLQMSGq 11 | bXzh4uibrqMcQIPTopf4HrMt5mKrBqssUf4siWionE0FySHxqIWs6nBx+L+3Zpz6 12 | 5c5bGILLI5o4j9v9XXFBPk+M0dmlzs33Fm/qJleeu57zZnjRp5D00gfDr2wNfOFU 13 | pjJIlws73riz7zP474411u0J9Hx0sph3PNfjvD+tWW2Ver4gLdgH9fHQlWh7JZPw 14 | iW7qYFYbh6bvq6Q8Y8Nbub+vYDCRT87qqd0EAnf9nepaiUennnqzH7jVmdLrcyHg 15 | 7X5AORVWOEOzutLftJ4QTROOyte4OIuEdB5P5G+BNBseGon2OeY= 16 | -----END CERTIFICATE REQUEST----- 17 | -------------------------------------------------------------------------------- /testdata/self_signed_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDITCCAgkCFBS8mLoytMpMWBwpAtnRaq3eIKnsMA0GCSqGSIb3DQEBCwUAME0x 3 | CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTENMAsGA1UECgwEVGVzdDEiMCAGA1UE 4 | AwwZdGVzdC1zMmEtbXRscy1zZWxmLXNpZ25lZDAeFw0yMzA4MjIyMTE2MDFaFw00 5 | MzA4MjIyMTE2MDFaME0xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTENMAsGA1UE 6 | CgwEVGVzdDEiMCAGA1UEAwwZdGVzdC1zMmEtbXRscy1zZWxmLXNpZ25lZDCCASIw 7 | DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKFFPsYasKZeCFLEXl3RpE/ZOXFe 8 | 2lhutIalSpZvCmso+mQGoZ4cHK7At+kDjBi5CrnXkYcw7quQAhHgU0frhWdj7tsW 9 | HUUtq7T8eaGWKBnVD9fl+MjtAl1BmhXwV9qRBbj4EesSKGDSGpKf66dOtzw83JbB 10 | cU7XlPAH1c1zo2GXC1himcZ+SVGHVrOjn4NmeFs8g94/Dke8dWkHwv5YTMVugFK4 11 | 5KxKgSOKkr4ka7PCBzgxCnW4wYSZNRHcxrqkiArO2HAQq0ACr7u+fVDYH//9mP2Z 12 | ADo/zch7O5yhkiNbjXJIRrptDWEuVYMRloYDhT773h7bV/Q0Wo0NQGtasJ8CAwEA 13 | ATANBgkqhkiG9w0BAQsFAAOCAQEAPjbH0TMyegF/MDvglkc0sXr6DqlmTxDCZZmG 14 | lYPZ5Xy062+rxIHghMARbvO4BxepiG37KsP2agvOldm4TtU8nQ8LyswmSIFm4BQ+ 15 | XQWwdsWyYyd8l0d5sXAdaN6AXwy50fvqCepmEqyreMY6dtLzlwo9gVCBFB7QuAPt 16 | Nc14phpEUZt/KPNuY6cUlB7bz3tmnFbwxUrWj1p0KBEYsr7+KEVZxR+z0wtlU7S9 17 | ZBrmUvx0fq5Ef7JWtHW0w4ofg1op742sdYl+53C26GZ76ts4MmqVz2/94DScgRaU 18 | gT0GLVuuCZXRDVeTXqTb4mditRCfzFPe9cCegYhGhSqBs8yh5A== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /testdata/self_signed_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQChRT7GGrCmXghS 3 | xF5d0aRP2TlxXtpYbrSGpUqWbwprKPpkBqGeHByuwLfpA4wYuQq515GHMO6rkAIR 4 | 4FNH64VnY+7bFh1FLau0/HmhligZ1Q/X5fjI7QJdQZoV8FfakQW4+BHrEihg0hqS 5 | n+unTrc8PNyWwXFO15TwB9XNc6NhlwtYYpnGfklRh1azo5+DZnhbPIPePw5HvHVp 6 | B8L+WEzFboBSuOSsSoEjipK+JGuzwgc4MQp1uMGEmTUR3Ma6pIgKzthwEKtAAq+7 7 | vn1Q2B///Zj9mQA6P83IezucoZIjW41ySEa6bQ1hLlWDEZaGA4U++94e21f0NFqN 8 | DUBrWrCfAgMBAAECggEAR8e8YwyqJ8KezcgdgIC5M9kp2i4v3UCZFX0or8CI0J2S 9 | pUbWVLuKgLXCpfIwPyjNf15Vpei/spkMcsx4BQDthdFTFSzIpmvni0z9DlD5VFYj 10 | ESOJElV7wepbHPy2/c+izmuL/ic81aturGiFyRgeMq+cN3WuaztFTXkPTrzzsZGF 11 | p/Mx3gqm7Hoc3d2xlv+8L5GjCtEJPlQgZJV+s3ennBjOAd8CC7d9qJetE3Er46pn 12 | r5jedV3bQRZYBzmooYNHjbAs26++wYac/jTE0/U6nKS17eWq4BQZUtlMXUw5N81B 13 | 7LKn7C03rj2KCn+Nf5uin9ALmoy888LXCDdvL/NZkQKBgQDduv1Heu+tOZuNYUdQ 14 | Hswmd8sVNAAWGZxdxixHMv58zrgbLFXSX6K89X2l5Sj9XON8TH46MuSFdjSwwWw5 15 | fBrhVEhA5srcqpvVWIBE05yqPpt0s1NQktMWJKELWlG8jOhVKwM5OYDpdxtwehpz 16 | 1g70XJz+nF/LTV8RdTK+OWDDpQKBgQC6MhdbGHUz/56dY3gZpE5TXnN2hkNbZCgk 17 | emr6z85VHhQflZbedhCzB9PUnZnCKWOGQHQdxRTtRfd46LVboZqCdYO1ZNQv6toP 18 | ysS7dTpZZFy7CpQaW0Y6/jS65jW6xIDKR1W40vgltZ3sfpG37JaowpzWdw2WuOnw 19 | Bg0rcJAf8wKBgQCqE+p/z97UwuF8eufWnyj9QNo382E1koOMspv4KTdnyLETtthF 20 | vDH6O1wbykG8xmmASLRyM+NyNA+KnXNETNvZh2q8zctBpGRQK8iIAsGjHM7ln0AD 21 | B/x+ea5GJQuZU4RK/+lDFca6TjBwAFkWDVX/PqL18kDQkxKfM4SuwRhmOQKBgDGh 22 | eoJIsa0LnP787Z2AI3Srf4F/ZmLs/ppCm1OBotEjdF+64v0nYWonUvqgi8SqfaHi 23 | elEZIGvis4ViGj1zhRjzNAlc+AZRxpBhDzGcnNIJI4Kj3jhsTfsZmXqcNIQ1LtM8 24 | Uogyi/yZPaA1WKg7Aym2vlGYaGHdplXZdxc2KOSrAoGABRkD9l2OVcwK7RyNgFxo 25 | mjxx0tfUdDBhHIi2igih1FiHpeP9E+4/kE/K7PnU9DoDrL1jW1MTpXaYV4seOylk 26 | k9z/9QfcRa9ePD2N4FqbHWSYp5n3aLoIcGq/9jyjTwayZbbIhWO+vNuHE9wIvecZ 27 | 8x3gNkxJRb4NaLIoNzAhCoo= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /testdata/server_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID8TCCAtmgAwIBAgIUKCoDuLtiZXvhsBY2RoDm0ugizJ8wDQYJKoZIhvcNAQEL 3 | BQAwgYcxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU3Vubnl2 4 | YWxlMRAwDgYDVQQKDAdDb21wYW55MREwDwYDVQQLDAhEaXZpc2lvbjEWMBQGA1UE 5 | AwwNczJhX3Rlc3RfY2VydDEaMBgGCSqGSIb3DQEJARYLeHl6QHh5ei5jb20wHhcN 6 | MjIwNTMxMjAwODI1WhcNNDIwNTI2MjAwODI1WjCBhzELMAkGA1UEBhMCVVMxCzAJ 7 | BgNVBAgMAkNBMRIwEAYDVQQHDAlTdW5ueXZhbGUxEDAOBgNVBAoMB0NvbXBhbnkx 8 | ETAPBgNVBAsMCERpdmlzaW9uMRYwFAYDVQQDDA1zMmFfdGVzdF9jZXJ0MRowGAYJ 9 | KoZIhvcNAQkBFgt4eXpAeHl6LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC 10 | AQoCggEBAKK1++PXQ+M3hjYH/v0K4UEYl5ljzpNM1i52eQM+gFooojT87PDSaphT 11 | fs0PXy/PTAjHBEvPhWpOpmQXfJNYzjwcCvg66hbqkv++/VTZiFLAsHagzkEz+FRJ 12 | qT5Eq7G5FLyw1izX1uxyPN7tAEWEEg7eqsiaXD3Cq8+TYN9cjirPeF7RZF8yFCYE 13 | xqvbo+Yc6RL6xw19iXVTfctRgQe581KQuIY5/LXo3dWDEilFdsADAe8XAEcO64es 14 | Ow0g1UvXLnpXSE151kXBFb3sKH/ZjCecDYMCIMEb4sWLSblkSxJ5sNSmXIG4wtr2 15 | Qnii7CXZgnVYraQE/Jyh+NMQANuoSdMCAwEAAaNTMFEwHQYDVR0OBBYEFAyQQQuM 16 | ab+YUQqjK8dVVOoHVFmXMB8GA1UdIwQYMBaAFAyQQQuMab+YUQqjK8dVVOoHVFmX 17 | MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADj0vQ6ykWhicoqR 18 | e6VZMwlEJV7/DSvWWKBd9MUjfKye0A4565ya5lmnzP3DiD3nqGe3miqmLsXKDs+X 19 | POqlPXTWIamP7D4MJ32XtSLwZB4ru+I+Ao/P/VngPepoRPQoBnzHe7jww0rokqxl 20 | AZERjlbTUwUAy/BPWPSzSJZ2j0tcs6ZLDNyYzpK4ao8R9/1VmQ92Tcp3feJs1QTg 21 | odRQc3om/AkWOwsll+oyX0UbJeHkFHiLanUPXbdh+/BkSvZJ8ynL+feSDdaurPe+ 22 | PSfnqLtQft9/neecGRdEaQzzzSFVQUVQzTdK1Q7hA7b55b2HvIa3ktDiks+sJsYN 23 | Dhm6uZM= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /testdata/server_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAorX749dD4zeGNgf+/QrhQRiXmWPOk0zWLnZ5Az6AWiiiNPzs 3 | 8NJqmFN+zQ9fL89MCMcES8+Fak6mZBd8k1jOPBwK+DrqFuqS/779VNmIUsCwdqDO 4 | QTP4VEmpPkSrsbkUvLDWLNfW7HI83u0ARYQSDt6qyJpcPcKrz5Ng31yOKs94XtFk 5 | XzIUJgTGq9uj5hzpEvrHDX2JdVN9y1GBB7nzUpC4hjn8tejd1YMSKUV2wAMB7xcA 6 | Rw7rh6w7DSDVS9cueldITXnWRcEVvewof9mMJ5wNgwIgwRvixYtJuWRLEnmw1KZc 7 | gbjC2vZCeKLsJdmCdVitpAT8nKH40xAA26hJ0wIDAQABAoIBACaNR+lsD8G+XiZf 8 | LqN1+HkcAo9tfnyYMAdCOtnx7SdviT9Uzi8hK/B7mAeuJLeHPlS2EuaDfPD7QaFl 9 | jza6S+MiIdc+3kgfvESsVAnOoOY6kZUJ9NSuI6CU82y1iJjLaYZrv9NQMLRFPPb0 10 | 4KOX709mosB1EnXvshW0rbc+jtDFhrm1SxMt+k9TuzmMxjbOeW4LOLXPgU8X1T3Q 11 | Xy0hMZZtcgBs9wFIo8yCtmOixax9pnFE8rRltgDxTodn9LLdz1FieyntNgDksZ0P 12 | nt4kV7Mqly7ELaea+Foaj244mKsesic2e3GhAlMRLun/VSunSf7mOCxfpITB8dp1 13 | drDhOYECgYEA19151dVxRcviuovN6Dar+QszMTnU8pDJ8BjLFjXjP/hNBBwMTHDE 14 | duMuWk2qnwZqMooI/shxrF/ufmTgS0CFrh2+ANBZu27vWConJNXcyNtdigI4wt50 15 | L0Y2qcZn2mg67qFXHwoR3QNwrwnPwEjRXA09at9CSRZzcwDQ0ETXhYsCgYEAwPaG 16 | 06QdK8Zyly7TTzZJwxzv9uGiqzodmGtX6NEKjgij2JaCxHpukqZBJoqa0jKeK1cm 17 | eNVkOvT5ff9TMzarSHQLr3pZen2/oVLb5gaFkbcJt/klv9Fd+ZRilHY3i6QwS6pD 18 | uMiPOWS4DrLHDRVoVlAZTDjT1RVwwTs+P2NhJdkCgYEAsriXysbxBYyMp05gqEW7 19 | lHIFbFgpSrs9th+Q5U6wW6JEgYaHWDJ1NslY80MiZI93FWjbkbZ7BvBWESeL3EIL 20 | a+EMErht0pVCbIhZ6FF4foPAqia0wAJVx14mm+G80kNBp5jE/NnleEsE3KcO7nBb 21 | hg8gLn+x7bk81JZ0TDrzBYkCgYEAuQKluv47SeF3tSScTfKLPpvcKCWmxe1uutkQ 22 | 7JShPhVioyOMNb39jnYBOWbjkm4d4QgqRuiytSR0oi3QI+Ziy5EYMyNn713qAk9j 23 | r2TJZDDPDKnBW+zt4YI4EohWMXk3JRUW4XDKggjjwJQA7bZ812TtHHvP/xoThfG7 24 | eSNb3eECgYBw6ssgCtMrdvQiEmjKVX/9yI38mvC2kSGyzbrQnGUfgqRGomRpeZuD 25 | B5E3kysA4td5pT5lvcLgSW0TbOz+YbiriXjwOihPIelCvc9gE2eOUI71/byUWPFz 26 | 7u5F/xQ4NaGr5suLF+lBC6h7pSbM4El9lIHQAQadpuEdzHqrw+hs3g== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tools/internal_ci/run_gae_test.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #!/bin/bash 16 | 17 | # inspired by https://github.com/grpc/grpc-java/blob/master/buildscripts/kokoro/gae-interop.sh 18 | 19 | # Fail on any error. 20 | set -e 21 | 22 | # Display commands being run. 23 | set -x 24 | 25 | KOKORO_GAE_DEFAULT_APP_VERSION="default" 26 | PROJECT_ID=$(curl "http://metadata.google.internal/computeMetadata/v1/project/project-id" -H "Metadata-Flavor: Google") 27 | 28 | # Setup app. 29 | cd "tools/internal_ci/test_gae" 30 | go mod edit -go=1.22 31 | export CLOUDSDK_CORE_DISABLE_PROMPTS=1 32 | 33 | # Deploy the app. 34 | gcloud app deploy --version=$KOKORO_GAE_DEFAULT_APP_VERSION 35 | APP_URL=$(gcloud app browse --no-launch-browser --version="$KOKORO_GAE_DEFAULT_APP_VERSION" --project="$PROJECT_ID") 36 | 37 | if curl -s $APP_URL | grep "success" 38 | then 39 | exit 0 40 | else 41 | exit 1 42 | fi 43 | -------------------------------------------------------------------------------- /tools/internal_ci/run_golang_tests.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #!/bin/bash 16 | 17 | # Fail on any error. 18 | set -e 19 | 20 | # Display commands being run. 21 | set -x 22 | 23 | readonly PLATFORM="$(uname | tr '[:upper:]' '[:lower:]')" 24 | 25 | fail_with_debug_output() { 26 | ls -l 27 | df -h / 28 | exit 1 29 | } 30 | 31 | run_tests() { 32 | time go build -buildvcs=false ./... || fail_with_debug_output 33 | time go test -buildvcs=false ./... || fail_with_debug_output 34 | } 35 | 36 | main() { 37 | # Install a newer Golang version on GCP Ubuntu VMs. 38 | which go 39 | sudo rm -rf /usr/local/go 40 | case "${PLATFORM}" in 41 | 'linux') 42 | sudo rm -rf /usr/local/go 43 | curl -O https://dl.google.com/go/go1.21.12.linux-amd64.tar.gz 44 | tar -xvf go1.21.12.linux-amd64.tar.gz 45 | sudo mv go /usr/local 46 | export GOROOT=/usr/local/go 47 | export PATH=$PATH:$GOROOT/bin 48 | ;; 49 | 'darwin') 50 | sudo rm -rf /usr/local/go 51 | curl -O https://dl.google.com/go/go1.21.12.darwin-amd64.tar.gz 52 | tar -xvf go1.21.12.darwin-amd64.tar.gz 53 | sudo mv go /usr/local 54 | export GOROOT=/usr/local/go 55 | export PATH="${GOROOT}/bin:${PATH}" 56 | ;; 57 | *) 58 | echo "Using existing Go installation." 59 | ;; 60 | esac 61 | go version 62 | 63 | run_tests 64 | } 65 | 66 | main "$@" 67 | -------------------------------------------------------------------------------- /tools/internal_ci/run_hygiene_tests.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #!/bin/bash 16 | 17 | set -ex 18 | set -o pipefail 19 | 20 | readonly PLATFORM="$(uname | tr '[:upper:]' '[:lower:]')" 21 | 22 | not() { 23 | ! "$@" 24 | } 25 | 26 | fail_on_output() { 27 | tee /dev/stderr | not read 28 | } 29 | 30 | which go 31 | sudo rm -rf /usr/local/go 32 | case "${PLATFORM}" in 33 | 'linux') 34 | sudo rm -rf /usr/local/go 35 | curl -O https://dl.google.com/go/go1.21.12.linux-amd64.tar.gz 36 | tar -xvf go1.21.12.linux-amd64.tar.gz 37 | sudo mv go /usr/local 38 | export GOROOT=/usr/local/go 39 | export PATH=$PATH:$GOROOT/bin 40 | ;; 41 | 'darwin') 42 | sudo rm -rf /usr/local/go 43 | curl -O https://dl.google.com/go/go1.21.12.darwin-amd64.tar.gz 44 | tar -xvf go1.21.12.darwin-amd64.tar.gz 45 | sudo mv go /usr/local 46 | export GOROOT=/usr/local/go 47 | export PATH="${GOROOT}/bin:${PATH}" 48 | ;; 49 | *) 50 | echo "Using existing Go installation." 51 | ;; 52 | esac 53 | 54 | go version 55 | 56 | # TODO(mattstev): Install goimports and run: 57 | # goimports -l . 2>&1 | not grep -vE "\.pb\.go" 58 | 59 | go vet -all ./... | fail_on_output 60 | gofmt -s -d -l . 2>&1 | fail_on_output 61 | go mod tidy 62 | 63 | echo SUCCESS 64 | 65 | -------------------------------------------------------------------------------- /tools/internal_ci/test_gae/app.yaml: -------------------------------------------------------------------------------- 1 | runtime: go122 2 | app_engine_apis: true -------------------------------------------------------------------------------- /tools/internal_ci/test_gae/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/google/s2a-go" 10 | "google.golang.org/api/option" 11 | "google.golang.org/appengine" 12 | "google.golang.org/grpc" 13 | "google.golang.org/grpc/credentials/oauth" 14 | 15 | translate "cloud.google.com/go/translate/apiv3" 16 | translatepb "cloud.google.com/go/translate/apiv3/translatepb" 17 | ) 18 | 19 | const serverAddr = "translate.mtls.googleapis.com:443" 20 | 21 | func indexHandler(w http.ResponseWriter, r *http.Request) { 22 | if r.URL.Path != "/" { 23 | http.NotFound(w, r) 24 | return 25 | } 26 | ctx := appengine.NewContext(r) 27 | creds, err := s2a.NewClientCreds(&s2a.ClientOptions{S2AAddress: "metadata.google.internal:80"}) 28 | if err != nil { 29 | errorMessage := "Failed to create S2A client credentials: %v" + err.Error() 30 | log.Fatalf("%v", errorMessage) 31 | http.Error(w, errorMessage, http.StatusBadRequest) 32 | return 33 | } 34 | perRPCCreds, err := oauth.NewApplicationDefault(ctx, 35 | "https://www.googleapis.com/auth/cloud-platform") 36 | if err != nil { 37 | errorMessage := "Failed to get per-RPC credentials: %v" + err.Error() 38 | log.Fatalf("%v", errorMessage) 39 | http.Error(w, errorMessage, http.StatusBadRequest) 40 | return 41 | } 42 | opts := []grpc.DialOption{ 43 | grpc.WithTransportCredentials(creds), 44 | grpc.WithPerRPCCredentials(perRPCCreds), 45 | grpc.WithBlock(), 46 | grpc.WithReturnConnectionError(), 47 | } 48 | conn, err := grpc.DialContext(ctx, serverAddr, opts...) 49 | if err != nil { 50 | errorMessage := "Client: failed to connect: %v" + err.Error() 51 | log.Fatalf("%v", errorMessage) 52 | http.Error(w, errorMessage, http.StatusBadRequest) 53 | return 54 | } 55 | defer conn.Close() 56 | cliOpts := []option.ClientOption{option.WithGRPCConn(conn)} 57 | client, err := translate.NewTranslationClient(ctx, cliOpts...) 58 | if err != nil { 59 | errorMessage := "Failed to create client: %v" + err.Error() 60 | log.Fatalf("%v", errorMessage) 61 | http.Error(w, errorMessage, http.StatusBadRequest) 62 | } 63 | req := &translatepb.TranslateTextRequest{ 64 | Contents: []string{"Hello World!"}, 65 | SourceLanguageCode: "en", 66 | TargetLanguageCode: "es", 67 | Parent: fmt.Sprintf("projects/%s", os.Getenv("GOOGLE_CLOUD_PROJECT")), 68 | } 69 | _, err = client.TranslateText(ctx, req) 70 | if err != nil { 71 | errorMessage := "Failed to translate: %v" + err.Error() 72 | log.Fatalf("%v", errorMessage) 73 | http.Error(w, errorMessage, http.StatusBadRequest) 74 | } 75 | fmt.Fprintf(w, "success") 76 | } 77 | 78 | func main() { 79 | http.HandleFunc("/", indexHandler) 80 | 81 | port := os.Getenv("PORT") 82 | if port == "" { 83 | port = "8080" 84 | log.Printf("Defaulting to port %s", port) 85 | } 86 | 87 | log.Printf("Listening on port %s", port) 88 | if err := http.ListenAndServe(":"+port, nil); err != nil { 89 | log.Fatal(err) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /tools/proto/regenerate_proto.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #!/bin/bash 16 | 17 | go install google.golang.org/protobuf/cmd/protoc-gen-go@latest 18 | go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest 19 | export PATH="$PATH:$(go env GOPATH)/bin" 20 | 21 | # Regenerate the S2A protos. 22 | protoc --go_out=. --go_opt=paths=source_relative \ 23 | --go-grpc_out=. --go-grpc_opt=paths=source_relative \ 24 | internal/proto/common/common.proto internal/proto/s2a/s2a.proto internal/proto/s2a_context/s2a_context.proto 25 | 26 | mkdir -p internal/proto/common_go_proto 27 | mv internal/proto/common/common.pb.go internal/proto/common_go_proto/common.pb.go 28 | 29 | mkdir -p internal/proto/s2a_go_proto 30 | mv internal/proto/s2a/s2a.pb.go internal/proto/s2a_go_proto/s2a.pb.go 31 | mv internal/proto/s2a/s2a_grpc.pb.go internal/proto/s2a_go_proto/s2a_grpc.pb.go 32 | sed -i 's/common_go_proto \"github.com\/google\/s2a\/internal\/proto\/common_go_proto\"/common_go_proto \"github.com\/google\/s2a-go\/internal\/proto\/common_go_proto\"/g' internal/proto/s2a_go_proto/s2a.pb.go 33 | 34 | mkdir -p internal/proto/s2a_context_go_proto 35 | mv internal/proto/s2a_context/s2a_context.pb.go internal/proto/s2a_context_go_proto/s2a_context.pb.go 36 | sed -i 's/common_go_proto \"github.com\/google\/s2a\/internal\/proto\/common_go_proto\"/common_go_proto \"github.com\/google\/s2a-go\/internal\/proto\/common_go_proto\"/g' internal/proto/s2a_context_go_proto/s2a_context.pb.go 37 | 38 | # Regenerate the S2Av2 protos. 39 | protoc --go_out=. --go_opt=paths=source_relative \ 40 | --go-grpc_out=. --go-grpc_opt=paths=source_relative \ 41 | internal/proto/v2/common/common.proto internal/proto/v2/s2a_context/s2a_context.proto internal/proto/v2/s2a/s2a.proto 42 | 43 | mkdir -p internal/proto/v2/common_go_proto 44 | mv internal/proto/v2/common/common.pb.go internal/proto/v2/common_go_proto/common.pb.go 45 | 46 | mkdir -p internal/proto/v2/s2a_go_proto 47 | mv internal/proto/v2/s2a/s2a.pb.go internal/proto/v2/s2a_go_proto/s2a.pb.go 48 | mv internal/proto/v2/s2a/s2a_grpc.pb.go internal/proto/v2/s2a_go_proto/s2a_grpc.pb.go 49 | sed -i 's/common_go_proto1 \"github.com\/google\/s2a\/internal\/proto\/common_go_proto\"/common_go_proto1 \"github.com\/google\/s2a-go\/internal\/proto\/common_go_proto\"/g' internal/proto/v2/s2a_go_proto/s2a.pb.go 50 | sed -i 's/common_go_proto \"github.com\/google\/s2a\/internal\/proto\/v2\/common_go_proto\"/common_go_proto \"github.com\/google\/s2a-go\/internal\/proto\/v2\/common_go_proto\"/g' internal/proto/v2/s2a_go_proto/s2a.pb.go 51 | sed -i 's/s2a_context_go_proto \"github.com\/google\/s2a\/internal\/proto\/v2\/s2a_context_go_proto\"/s2a_context_go_proto \"github.com\/google\/s2a-go\/internal\/proto\/v2\/s2a_context_go_proto\"/g' internal/proto/v2/s2a_go_proto/s2a.pb.go 52 | 53 | mkdir -p internal/proto/v2/s2a_context_go_proto 54 | mv internal/proto/v2/s2a_context/s2a_context.pb.go internal/proto/v2/s2a_context_go_proto/s2a_context.pb.go 55 | sed -i 's/common_go_proto \"github.com\/google\/s2a\/internal\/proto\/v2\/common_go_proto\"/common_go_proto \"github.com\/google\/s2a-go\/internal\/proto\/v2\/common_go_proto\"/g' internal/proto/v2/s2a_context_go_proto/s2a_context.pb.go 56 | 57 | # Regenerate the example protos. 58 | protoc --go_out=. --go_opt=paths=source_relative \ 59 | --go-grpc_out=. --go-grpc_opt=paths=source_relative \ 60 | internal/proto/examples/helloworld.proto 61 | 62 | mkdir -p internal/proto/examples/helloworld_go_proto 63 | mv internal/proto/examples/helloworld.pb.go internal/proto/examples/helloworld_go_proto/helloworld.pb.go 64 | mv internal/proto/examples/helloworld_grpc.pb.go internal/proto/examples/helloworld_go_proto/helloworld_grpc.pb.go 65 | 66 | # Regenerate the echo example protos. 67 | protoc --go_out=. --go_opt=paths=source_relative \ 68 | --go-grpc_out=. --go-grpc_opt=paths=source_relative \ 69 | example/proto/echo.proto 70 | 71 | mkdir -p example/proto/echo_go_proto 72 | mv example/proto/echo.pb.go example/proto/echo_go_proto/echo.pb.go 73 | mv example/proto/echo_grpc.pb.go example/proto/echo_go_proto/echo_grpc.pb.go 74 | --------------------------------------------------------------------------------