├── .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 |
--------------------------------------------------------------------------------