-
Notifications
You must be signed in to change notification settings - Fork 200
added certz3.1 #3360
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
added certz3.1 #3360
Changes from all commits
d1d7565
8faeda2
1d6388a
c7a894a
0861011
8cff47c
ca5c17f
4262121
bab7239
1b74542
f153984
706d978
214a690
9194eea
d66833a
546b494
7ffbd0b
5384f15
7bcec00
a23257d
f8d55a6
93ce953
045cfe3
66a6820
248a099
a16194f
77e13a1
0fbe47b
e796a3c
9b626c0
b67b595
0110a8d
6c60550
f177e8b
8f9bc0c
60e89b8
9cc0aad
6d8646b
4d7d198
d2530c3
69c668a
c4fe8b5
3efbc73
75e4cde
7eaf25b
6381337
e0f1f19
926ee91
315ffdd
7917055
12a1378
cb157aa
919a23f
9a8ece4
32aca1a
2652703
0a96f5e
c77d11e
07b5372
7af9533
47e8a0e
61021e3
96a1d57
2d41950
600ffad
7352fb0
e6042f1
942dd0f
0aefcee
2ab3c4b
af6c215
74e9a32
9999487
5df887b
025a925
b433c6f
cdd9da3
c2d78d2
cdfb873
8522ae4
4ea07cd
39c7ba7
5bac8a1
161b28e
f8fc7f4
91861ee
da68fb9
de3688c
6d76d44
d36699a
c3ae494
849962e
db3a5f5
5c0c06e
d4828aa
54334d5
130ec9c
ec6c156
1b568ae
13c5a39
a060061
d428e27
49d0242
4eeae8b
65e21d9
fa4e06d
b9d36ac
23d659e
fde7e6b
15484b1
258f81a
6da0111
4114ba1
73e9259
c770e4a
021da42
8fa5832
cff88b3
f00a281
eec42de
8aa1d7e
d576edc
d2457cf
21ac2db
a46af8f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,245 @@ | ||
| // Copyright 2024 Google LLC | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| package server_certificate_rotation_test | ||
|
|
||
| import ( | ||
| "context" | ||
| "crypto/tls" | ||
| "crypto/x509" | ||
| "slices" | ||
| "testing" | ||
| "time" | ||
|
|
||
| setupService "github.com/openconfig/featureprofiles/feature/gnsi/certz/tests/internal/setup_service" | ||
| "github.com/openconfig/featureprofiles/internal/fptest" | ||
| "github.com/openconfig/gnmi/proto/gnmi" | ||
| certzpb "github.com/openconfig/gnsi/certz" | ||
| "github.com/openconfig/ondatra" | ||
| "github.com/openconfig/ondatra/binding" | ||
| ) | ||
|
|
||
| const ( | ||
| dirPath = "../../test_data/" | ||
| timeOutVar time.Duration = 2 * time.Minute | ||
| ) | ||
|
|
||
| // DUTCredentialer is an interface for getting credentials from | ||
| type DUTCredentialer interface { | ||
| RPCUsername() string | ||
| RPCPassword() string | ||
| } | ||
|
|
||
| var ( | ||
| serverAddr string | ||
| creds DUTCredentialer //an interface for getting credentials from a DUT binding | ||
| testProfile string = "newprofile" //sslProfileId name | ||
| prevClientCertFile string = "" | ||
| prevClientKeyFile string = "" | ||
| prevTrustBundleFile string = "" | ||
|
Comment on lines
+48
to
+50
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test cases in the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shared state here is going to be a problem, eventually. |
||
| logTime string = time.Now().String() //Timestamp | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The global variable
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you just need to move this logTime into each test loop so you get unique times per loop through in the logs. |
||
| expectedResult bool = true | ||
| success bool | ||
| ) | ||
|
|
||
| func TestMain(m *testing.M) { | ||
| fptest.RunTests(m) | ||
| } | ||
|
|
||
| // TestServerCertRotation tests a server certificate can be rotated by using the gNSI certz Rotate() rpc, | ||
| // if the certificate is requested without the device generated CSR. | ||
| func TestServerCertRotation(t *testing.T) { | ||
|
|
||
| dut := ondatra.DUT(t, "dut") | ||
| serverAddr = dut.Name() //returns the device name. | ||
| if err := binding.DUTAs(dut.RawAPIs().BindingDUT(), &creds); err != nil { | ||
| t.Fatalf("%s:STATUS:Failed to get DUT credentials using binding.DUTAs: %v. The binding for %s must implement the DUTCredentialer interface.", logTime, err, dut.Name()) | ||
| } | ||
| username := creds.RPCUsername() | ||
| password := creds.RPCPassword() | ||
| t.Logf("%s:STATUS:Validation of all services that are using gRPC before certz rotation.", logTime) | ||
| gnmiClient, gnsiC := setupService.PreInitCheck(context.Background(), t, dut) | ||
| //Generate testdata certificates. | ||
| t.Logf("%s:Creation of test data.", logTime) | ||
| if err := setupService.TestdataMakeCleanup(t, dirPath, timeOutVar, "./mk_cas.sh"); err != nil { | ||
| t.Fatalf("%s:STATUS:Generation of testdata certificates failed!: %v", logTime, err) | ||
| } | ||
morrowc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| //Create a certz client. | ||
| ctx := context.Background() | ||
| certzClient := gnsiC.Certz() | ||
| t.Logf("%s:STATUS:Precheck:checking baseline sslprofile list.", logTime) | ||
| //Get sslprofile list. | ||
| if getResp := setupService.GetSslProfilelist(ctx, t, certzClient, &certzpb.GetProfileListRequest{}); slices.Contains(getResp.SslProfileIds, testProfile) { | ||
| t.Fatalf("%s:STATUS:profileID %s already exists.", logTime, testProfile) | ||
| } | ||
| //Add new sslprofileID. | ||
| t.Logf("%s:Adding new empty sslprofile ID %s.", logTime, testProfile) | ||
| if addProfileResponse, err := certzClient.AddProfile(ctx, &certzpb.AddProfileRequest{SslProfileId: testProfile}); err != nil { | ||
| t.Fatalf("%s:STATUS:Add profile request failed with %v! ", logTime, err) | ||
| } else { | ||
| t.Logf("%s:STATUS:Received the AddProfileResponse %v.", logTime, addProfileResponse) | ||
| } | ||
| //Get sslprofile list after new sslprofile addition. | ||
| if getResp := setupService.GetSslProfilelist(ctx, t, certzClient, &certzpb.GetProfileListRequest{}); !slices.Contains(getResp.SslProfileIds, testProfile) { | ||
| t.Fatalf("%s:STATUS:newly added profileID is not seen.", logTime) | ||
| } else { | ||
| t.Logf("%s:STATUS:new profileID %s is seen in sslprofile list", logTime, testProfile) | ||
| } | ||
| cases := []struct { | ||
| desc string | ||
| serverCertFile string | ||
| serverKeyFile string | ||
| trustBundleFile string | ||
| clientCertFile string | ||
| clientKeyFile string | ||
| cversion string | ||
| bversion string | ||
| newTLScreds bool | ||
| serverCertOnlyRotate bool | ||
| mismatch bool | ||
| scale bool | ||
| }{ | ||
| { | ||
| desc: "Certz3.1:Rotate server-rsa-a certificate/key/trustbundle from ca-01", | ||
| serverCertFile: dirPath + "ca-01/server-rsa-a-cert.pem", | ||
| serverKeyFile: dirPath + "ca-01/server-rsa-a-key.pem", | ||
| trustBundleFile: dirPath + "ca-01/trust_bundle_01_rsa.p7b", | ||
| clientCertFile: dirPath + "ca-01/client-rsa-a-cert.pem", | ||
| clientKeyFile: dirPath + "ca-01/client-rsa-a-key.pem", | ||
| cversion: "v1", | ||
| bversion: "bundle1", | ||
| }, | ||
| { | ||
| desc: "Certz3.1:Rotate server-rsa-b certificate/key/trustbundle from ca-01", | ||
| serverCertFile: dirPath + "ca-01/server-rsa-b-cert.pem", | ||
| serverKeyFile: dirPath + "ca-01/server-rsa-b-key.pem", | ||
| trustBundleFile: dirPath + "ca-01/trust_bundle_01_rsa.p7b", | ||
| clientCertFile: dirPath + "ca-01/client-rsa-b-cert.pem", | ||
| clientKeyFile: dirPath + "ca-01/client-rsa-b-key.pem", | ||
| cversion: "v2", | ||
| bversion: "bundle1", | ||
| serverCertOnlyRotate: true, | ||
| newTLScreds: true, | ||
| }, | ||
| { | ||
| desc: "Certz3.1:Rotate server-ecdsa-a certificate/key/trustbundle from ca-01", | ||
| serverCertFile: dirPath + "ca-01/server-ecdsa-a-cert.pem", | ||
| serverKeyFile: dirPath + "ca-01/server-ecdsa-a-key.pem", | ||
| trustBundleFile: dirPath + "ca-01/trust_bundle_01_ecdsa.p7b", | ||
| clientCertFile: dirPath + "ca-01/client-ecdsa-a-cert.pem", | ||
| clientKeyFile: dirPath + "ca-01/client-ecdsa-a-key.pem", | ||
| cversion: "v3", | ||
| bversion: "bundle2", | ||
| newTLScreds: true, | ||
| }, | ||
| { | ||
| desc: "Certz3.1:Rotate server-ecdsa-b certificate/key/trustbundle from ca-01", | ||
| serverCertFile: dirPath + "ca-01/server-ecdsa-b-cert.pem", | ||
| serverKeyFile: dirPath + "ca-01/server-ecdsa-b-key.pem", | ||
| trustBundleFile: dirPath + "ca-01/trust_bundle_01_ecdsa.p7b", | ||
| clientCertFile: dirPath + "ca-01/client-ecdsa-b-cert.pem", | ||
| clientKeyFile: dirPath + "ca-01/client-ecdsa-b-key.pem", | ||
| cversion: "v4", | ||
| bversion: "bundle2", | ||
| serverCertOnlyRotate: true, | ||
| newTLScreds: true, | ||
| }, | ||
| } | ||
| for _, tc := range cases { | ||
| t.Run(tc.desc, func(t *testing.T) { | ||
| t.Logf("%s:STATUS:Starting test case: %s", logTime, tc.desc) | ||
| //Read the serverSAN (Subject Alternative Name) from the certificate used for TLS verification. | ||
| serverSAN := setupService.ReadDecodeServerCertificate(t, tc.serverCertFile) | ||
| //Build serverCertEntity for the server certificate rotation. | ||
| serverCert := setupService.CreateCertzChain(t, setupService.CertificateChainRequest{ | ||
| RequestType: setupService.EntityTypeCertificateChain, | ||
| ServerCertFile: tc.serverCertFile, | ||
| ServerKeyFile: tc.serverKeyFile}) | ||
| serverCertEntity := setupService.CreateCertzEntity(t, setupService.EntityTypeCertificateChain, &serverCert, tc.cversion) | ||
| //Create a new Cert Pool and add the certs from the trust bundle. | ||
| pkcs7certs, pkcs7data, err := setupService.Loadpkcs7TrustBundle(tc.trustBundleFile) | ||
| if err != nil { | ||
| t.Fatalf("%s:STATUS:failed to load trust bundle: %v", logTime, err) | ||
| } | ||
| newCaCert := x509.NewCertPool() | ||
| for _, c := range pkcs7certs { | ||
| newCaCert.AddCert(c) | ||
| } | ||
| //Build trustBundleEntity for the server certificate rotation. | ||
| trustBundleEntity := setupService.CreateCertzEntity(t, setupService.EntityTypeTrustBundle, string(pkcs7data), tc.bversion) | ||
| //Load Client certificate. | ||
| newClientCert, err := tls.LoadX509KeyPair(tc.clientCertFile, tc.clientKeyFile) | ||
| if err != nil { | ||
| t.Fatalf("%s:STATUS:Failed to load client cert:%v", logTime, err) | ||
| } | ||
| if tc.newTLScreds { | ||
| t.Logf("%s:STATUS:%s:Creating new TLS credentials for client connection.", logTime, tc.desc) | ||
| //Load the prior client keypair for new client TLS credentials. | ||
| prevClientCert, err := tls.LoadX509KeyPair(prevClientCertFile, prevClientKeyFile) | ||
| if err != nil { | ||
| t.Fatalf("%s:STATUS:%s:Failed to load previous client cert: %v", logTime, tc.desc, err) | ||
| } | ||
| oldPkcs7certs, oldPkcs7data, err := setupService.Loadpkcs7TrustBundle(prevTrustBundleFile) | ||
| if err != nil { | ||
| t.Fatalf("%s:STATUS:%sFailed to load previous trust bundle,data %v with %v", logTime, tc.desc, oldPkcs7data, err) | ||
| } | ||
| //Create a old set of Cert Pool and append the certs from previous trust bundle. | ||
| prevCaCert := x509.NewCertPool() | ||
| for _, c := range oldPkcs7certs { | ||
| prevCaCert.AddCert(c) | ||
| } | ||
| //Before rotation, validation of all services with existing certificates. | ||
| if result := setupService.ServicesValidationCheck(t, prevCaCert, expectedResult, serverSAN, serverAddr, username, password, prevClientCert, tc.mismatch); !result { | ||
| t.Fatalf("%s:STATUS:%s:service validation failed before rotate- got %v, want %v.", logTime, tc.desc, result, expectedResult) | ||
| } | ||
| //Retrieve the connection with previous TLS credentials for certz rotation. | ||
| conn := setupService.CreateNewDialOption(t, prevClientCert, prevCaCert, serverSAN, username, password, serverAddr) | ||
| defer conn.Close() | ||
| certzClient = certzpb.NewCertzClient(conn) | ||
| gnmiClient = gnmi.NewGNMIClient(conn) | ||
| } else { | ||
| t.Logf("%s:STATUS:%s:Using existing TLS credentials for client connection in first iteration.", logTime, tc.desc) | ||
| } | ||
| //Initiate server certitificate rotation. | ||
| if tc.serverCertOnlyRotate { | ||
| t.Logf("%s:STATUS:%s:Initiating server certificate rotation to server-${TYPE}-b.", logTime, tc.desc) | ||
| if success = setupService.CertzRotate(ctx, t, newCaCert, certzClient, gnmiClient, newClientCert, dut, username, password, serverSAN, serverAddr, testProfile, tc.newTLScreds, tc.mismatch, tc.scale, &serverCertEntity); !success { | ||
| t.Fatalf("%s STATUS %s:Server certificate rotation failed.", logTime, tc.desc) | ||
| } | ||
| } else { | ||
| t.Logf("%s:STATUS:%s Initiating Certz rotation with server cert: %s and trust bundle: %s", logTime, tc.desc, tc.serverCertFile, tc.trustBundleFile) | ||
| if success = setupService.CertzRotate(ctx, t, newCaCert, certzClient, gnmiClient, newClientCert, dut, username, password, serverSAN, serverAddr, testProfile, tc.newTLScreds, tc.mismatch, tc.scale, &serverCertEntity, &trustBundleEntity); !success { | ||
| t.Fatalf("%s STATUS %s:Server certificate rotation failed.", logTime, tc.desc) | ||
| } | ||
| } | ||
| t.Logf("%s:STATUS:%s:Server certificate rotation completed!", logTime, tc.desc) | ||
| t.Run("Verification of new connection after successful server certificate rotation", func(t *testing.T) { | ||
| if result := setupService.ServicesValidationCheck(t, newCaCert, expectedResult, serverSAN, serverAddr, username, password, newClientCert, tc.mismatch); !result { | ||
| t.Fatalf("%s:STATUS:%s:service validation failed after rotate- got %v, want %v.", logTime, tc.desc, result, expectedResult) | ||
| } | ||
| t.Logf("%s:STATUS:%s:service validation done!", logTime, tc.desc) | ||
| }) | ||
| //Archiving previous client cert/key and trustbundle. | ||
| prevClientCertFile = tc.clientCertFile | ||
| prevClientKeyFile = tc.clientKeyFile | ||
| prevTrustBundleFile = tc.trustBundleFile | ||
| }) | ||
| } | ||
| t.Logf("%s:STATUS:Cleanup of test data.", logTime) | ||
| //Cleanup of test data. | ||
| if err := setupService.TestdataMakeCleanup(t, dirPath, timeOutVar, "./cleanup.sh"); err != nil { | ||
| t.Logf("%s:STATUS:Cleanup of testdata certificates failed!: %v", logTime, err) | ||
| } | ||
| t.Logf("%s:STATUS: Testdata cleanup completed!", logTime) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happened to this part?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This testcase 3.2 is being removed based on discussion in b/311141278.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, we actually have devices which require this behavior (or which fail to use a cert that can't be validated by the local trustbundle)
I suppose "sure that's not REQUIRED"