From d1d7565345e5c1accb937121b7886003676a9599 Mon Sep 17 00:00:00 2001 From: priyacj Date: Fri, 2 Aug 2024 21:00:18 -0700 Subject: [PATCH 01/10] added certz3.1 --- .../internal/setup_service/setup_service.go | 645 ++++++++++++++++++ .../server_certificate_rotation/README.md | 115 ++++ .../server_certificate_rotation_test.go | 207 ++++++ 3 files changed, 967 insertions(+) create mode 100644 feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go create mode 100644 feature/security/gnsi/certz/tests/server_certificate_rotation/README.md create mode 100644 feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go diff --git a/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go b/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go new file mode 100644 index 00000000000..125f4ca2967 --- /dev/null +++ b/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go @@ -0,0 +1,645 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// 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 setupservice is scoped only to be used for scripts in path +// feature/security/gnsi/certz/tests/client_certificates +// Do not use elsewhere. +package setupservice + +import ( + context "context" + "crypto/tls" + "crypto/x509" + "encoding/pem" + "fmt" + "os" + "os/exec" + "testing" + "time" + + gnmipb "github.com/openconfig/gnmi/proto/gnmi" + spb "github.com/openconfig/gnoi/system" + authzpb "github.com/openconfig/gnsi/authz" + certzpb "github.com/openconfig/gnsi/certz" + gribipb "github.com/openconfig/gribi/v1/proto/service" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/knebind/creds" + p4rtpb "github.com/p4lang/p4runtime/go/p4/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/status" +) + +var ( + username = "certzuser" + password = "certzpasswd" + sn = "role001.pop55.net.example.com" + servers []string +) + +type rpcCredentials struct { + *creds.UserPass +} + +func (r *rpcCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { + return map[string]string{ + "username": r.UserPass.Username, + "password": r.UserPass.Password, + }, nil +} + +func (r *rpcCredentials) RequireTransportSecurity() bool { + return true +} + +type entityType int8 + +const ( + // EntityTypeCertificateChain is type of entity of the certificate chain. + EntityTypeCertificateChain entityType = 0 + // EntityTypeTrustBundle is type of entity of the trust bundle. + EntityTypeTrustBundle entityType = 1 + // EntityTypeCRL is type of entity of the CRL. + EntityTypeCRL entityType = 2 + // EntityTypeAuthPolicy is type of entity of the auth policy. + EntityTypeAuthPolicy entityType = 3 +) + +// CertificateChainRequest is an input argument for the type definition for the CreateCertzChain. +type CertificateChainRequest struct { + RequestType entityType + ServerCertFile string + ServerKeyFile string + TrustBundleFile string +} + +// CreateCertzEntity function to create certificate entity of type certificate chain/trust bundle/CRL/Authpolicy. +func CreateCertzEntity(t *testing.T, typeOfEntity entityType, entityContent any, entityVersion string) certzpb.Entity { + + createdOnTime := time.Now() + varClock := uint64(createdOnTime.Unix()) + + switch typeOfEntity { + case EntityTypeCertificateChain: + + return certzpb.Entity{ + Version: entityVersion, + CreatedOn: varClock, + Entity: &certzpb.Entity_CertificateChain{CertificateChain: entityContent.(*certzpb.CertificateChain)}} + + case EntityTypeTrustBundle: + + return certzpb.Entity{ + Version: entityVersion, + CreatedOn: varClock, + Entity: &certzpb.Entity_TrustBundle{TrustBundle: entityContent.(*certzpb.CertificateChain)}} + + case EntityTypeCRL: + + return certzpb.Entity{ + Version: entityVersion, + CreatedOn: varClock, + Entity: &certzpb.Entity_CertificateRevocationListBundle{CertificateRevocationListBundle: entityContent.(*certzpb.CertificateRevocationListBundle)}} + + case EntityTypeAuthPolicy: + + return certzpb.Entity{ + Version: entityVersion, + CreatedOn: varClock, + Entity: &certzpb.Entity_AuthenticationPolicy{AuthenticationPolicy: entityContent.(*certzpb.AuthenticationPolicy)}} + + default: + t.Fatalf("Invalid entity type") + } + return certzpb.Entity{} +} + +// CreateCertzChain function to get the certificate chain of type certificate chain/trust bundle. +func CreateCertzChain(t *testing.T, certData CertificateChainRequest) certzpb.CertificateChain { + + switch certData.RequestType { + case EntityTypeCertificateChain: + if len(certData.ServerCertFile) == 0 { + t.Fatalf("Missing server certificate file for creating certificate chain object.") + } + serverCertContent, err := os.ReadFile(certData.ServerCertFile) + if err != nil { + t.Fatalf("Error reading Server Certificate file at: %v with error: %v", certData.ServerCertFile, err) + + } + if len(certData.ServerKeyFile) != 0 { + serverKeyContent, err := os.ReadFile(certData.ServerKeyFile) + if err != nil { + t.Fatalf("Error reading Server Key file at: %v with error: %v", certData.ServerKeyFile, err) + } + return certzpb.CertificateChain{Certificate: &certzpb.Certificate{ + Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, + Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, + Certificate: serverCertContent, + PrivateKey: serverKeyContent}, Parent: nil} + } + return certzpb.CertificateChain{Certificate: &certzpb.Certificate{ + Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, + Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, + Certificate: serverCertContent, + PrivateKey: nil}, Parent: nil} + + case EntityTypeTrustBundle: + if len(certData.TrustBundleFile) == 0 { + t.Fatalf("Missing trust bundle file for creating certificate chain object.") + } + trustBundleContent, err := os.ReadFile(certData.TrustBundleFile) + if err != nil { + t.Fatalf("Error reading trust bundle file at: %v with error: %v", certData.TrustBundleFile, err) + } + return certzpb.CertificateChain{Certificate: &certzpb.Certificate{ + Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, + Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, + Certificate: trustBundleContent, + }, Parent: nil} + + default: + t.Fatalf("Invalid request type received.") + } + return certzpb.CertificateChain{} +} + +// CreateCertChainFromTrustBundle function to create the certificate chain from trust bundle. +func CreateCertChainFromTrustBundle(fileName string) *certzpb.CertificateChain { + pemData, err := os.ReadFile(fileName) + if err != nil { + return &certzpb.CertificateChain{} + } + var trust [][]byte + for { + var block *pem.Block + block, pemData = pem.Decode(pemData) + if block == nil { + break + } + if block.Type != "CERTIFICATE" { + continue + } + p := pem.EncodeToMemory(block) + if p == nil { + return &certzpb.CertificateChain{} + } + trust = append(trust, p) + } + //a valid check for trust not empty + if len(trust) == 0 { + return &certzpb.CertificateChain{} + } else { + var prevCert *certzpb.CertificateChain + var bundleToReturn *certzpb.CertificateChain + for i := len(trust) - 1; i >= 0; i-- { + if i == len(trust)-1 { + bundleToReturn = &certzpb.CertificateChain{Certificate: &certzpb.Certificate{ + Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, + Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, + Certificate: trust[i], + }, Parent: nil} + prevCert = bundleToReturn + } else { + prevCert = bundleToReturn + bundleToReturn = &certzpb.CertificateChain{Certificate: &certzpb.Certificate{ + Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, + Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, + Certificate: trust[i], + }, Parent: prevCert} + } + } + return bundleToReturn + } +} + +// CertzRotate function to request the client certificate rotation and returns true on successful rotation. +func CertzRotate(t *testing.T, caCert *x509.CertPool, certzClient certzpb.CertzClient, cert tls.Certificate, san, serverAddr, profileID string, entities ...*certzpb.Entity) bool { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + if len(entities) == 0 { + t.Logf("At least one entity required for Rotate request.") + return false + } + uploadRequest := &certzpb.UploadRequest{Entities: entities} + rotateRequest := &certzpb.RotateCertificateRequest_Certificates{Certificates: uploadRequest} + rotateCertRequest := &certzpb.RotateCertificateRequest{ + ForceOverwrite: false, + SslProfileId: profileID, + RotateRequest: rotateRequest} + //rotateRequestClient, err := certzClient.Rotate(context.Background()) + rotateRequestClient, err := certzClient.Rotate(ctx) + defer rotateRequestClient.CloseSend() + if err != nil { + t.Fatalf("Error creating rotate request client: %v", err) + } + err = rotateRequestClient.Send(rotateCertRequest) + if err != nil { + t.Fatalf("Error sending rotate request: %v", err) + } + rotateResponse := &certzpb.RotateCertificateResponse{} + for i := 0; i < 20; i++ { + rotateResponse, err = rotateRequestClient.Recv() + if err == nil { + break + } + t.Logf("Did not receive response ~ %vs after sending rotate request. Sleeping 10s to retry...", i*10) + time.Sleep(10 * time.Second) + } + if err != nil { + t.Logf("Error fetching rotate certificate response: %v", err) + return false + } + t.Logf("Received Rotate certificate response: %v", rotateResponse) + + finalizeRequest := &certzpb.RotateCertificateRequest_FinalizeRotation{FinalizeRotation: &certzpb.FinalizeRequest{}} + rotateCertRequest = &certzpb.RotateCertificateRequest{ + ForceOverwrite: false, + SslProfileId: profileID, + RotateRequest: finalizeRequest} + + err = rotateRequestClient.Send(rotateCertRequest) + if err != nil { + t.Fatalf("Error sending rotate finalize request: %v", err) + } + err = rotateRequestClient.CloseSend() + if err != nil { + t.Fatalf("Error sending rotate close send request: %v", err) + } + return true +} + +// ServerCertzRotate function to request the server certificate rotation and returns true on successful rotation. +func ServerCertzRotate(t *testing.T, caCert *x509.CertPool, certzClient certzpb.CertzClient, cert tls.Certificate, ctx context.Context, dut *ondatra.DUTDevice, san, serverAddr, profileID string, entities ...*certzpb.Entity) bool { + if len(entities) == 0 { + t.Logf("At least one entity required for Rotate request.") + return false + } + uploadRequest := &certzpb.UploadRequest{Entities: entities} + rotateRequest := &certzpb.RotateCertificateRequest_Certificates{Certificates: uploadRequest} + rotateCertRequest := &certzpb.RotateCertificateRequest{ + ForceOverwrite: false, + SslProfileId: profileID, + RotateRequest: rotateRequest} + rotateRequestClient, err := certzClient.Rotate(context.Background()) + defer rotateRequestClient.CloseSend() + if err != nil { + t.Fatalf("Error creating rotate request client: %v", err) + } + err = rotateRequestClient.Send(rotateCertRequest) + if err != nil { + t.Fatalf("Error sending rotate request: %v", err) + } + rotateResponse := &certzpb.RotateCertificateResponse{} + for i := 0; i < 6; i++ { + rotateResponse, err = rotateRequestClient.Recv() + if err == nil { + break + } + t.Logf("Did not receive response ~ %vs after sending rotate request. Sleeping 10s to retry...", i*10) + time.Sleep(10 * time.Second) + } + if err != nil { + t.Logf("Error fetching rotate certificate response: %v", err) + return false + } + t.Logf("Received Rotate certificate response: %v", rotateResponse) + + // Replace config with newly added ssl profile after successful rotate. + servers = gnmi.GetAll(t, dut, gnmi.OC().System().GrpcServerAny().Name().State()) + batch := gnmi.SetBatch{} + for _, server := range servers { + gnmi.BatchReplace(&batch, gnmi.OC().System().GrpcServer(server).CertificateId().Config(), profileID) + } + batch.Set(t, dut) + t.Logf("gNMI config is replaced with new ssl profile successfully.") + success := false + //Trying for 60s for the connection to succeed. + for i := 0; i < 6; i++ { + success = VerifyGnsi(t, caCert, san, serverAddr, username, password, cert) + if success { + break + } + if i != 10 { + t.Logf("gNSI service RPC did not succeed ~ %vs after rotate. Sleeping 10s to retry...", i*10) + } + time.Sleep(10 * time.Second) + } + if success { + finalizeRequest := &certzpb.RotateCertificateRequest_FinalizeRotation{FinalizeRotation: &certzpb.FinalizeRequest{}} + rotateCertRequest = &certzpb.RotateCertificateRequest{ + ForceOverwrite: false, + SslProfileId: profileID, + RotateRequest: finalizeRequest} + + err = rotateRequestClient.Send(rotateCertRequest) + if err != nil { + t.Fatalf("Error sending rotate finalize request: %v", err) + } + err = rotateRequestClient.CloseSend() + if err != nil { + t.Fatalf("Error sending rotate close send request: %v", err) + } + return true + } else { + t.Logf("gNSI service RPC did not succeed ~60s after rotate. Certz/Rotate failed. FinalizeRequest will not be sent") + return false + } +} + +// CertGeneration function to create test data for use in TLS tests. +func CertGeneration(t *testing.T, dirPath string) error { + cmd := exec.Cmd{ + Path: "./mk_cas.sh", + Stdout: os.Stdout, + Stderr: os.Stderr, + } + cmd.Dir = dirPath + t.Logf("Executing cert generation command %v.", cmd) + err := cmd.Start() + if err != nil { + t.Logf("Cert generation command failed with error:%v.", err) + return err + } + err = cmd.Wait() + if err != nil { + t.Logf("Failed to run cert generation command during wait with error:%v.", err) + return err + } + return err +} + +// CertCleanup function to clean out the CA content under test_data. +func CertCleanup(t *testing.T, dirPath string) error { + cmd := exec.Cmd{ + Path: "./cleanup.sh", + Stdout: os.Stdout, + Stderr: os.Stderr, + } + cmd.Dir = dirPath + t.Logf("Executing cleanup command") + err := cmd.Start() + if err != nil { + t.Logf("Testdata cleanup command failed with error:%v.", err) + return err + } + err = cmd.Wait() + if err != nil { + t.Logf("Testdata cleanup command failed during wait with the error:%v.", err) + return err + } + return err +} + +// ReadDecodeServerCertificate function to read and decode server certificates to extract the SubjectAltName. +func ReadDecodeServerCertificate(t *testing.T, serverCertzFile string) (san string) { + sc, err := os.ReadFile(serverCertzFile) + if err != nil { + t.Fatalf("Failed to read certificate with error: %v.", err) + } + block, _ := pem.Decode(sc) + if block == nil { + t.Fatalf("Failed to parse PEM block containing the public key.") + } + sCert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + t.Fatalf("Failed to parse certificate with error: %v.", err) + } + san = sCert.DNSNames[0] + t.Logf("ServerAltName:%s.", san) + if sn != san { + t.Fatalf("ServerAltName validation failed for %s.", serverCertzFile) + } + return san +} + +// VerifyGnsi function to validate the gNSI service RPC after successful rotation. +func VerifyGnsi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, password string, cert tls.Certificate) bool { + credOpts := []grpc.DialOption{grpc.WithBlock(), grpc.WithTransportCredentials(credentials.NewTLS( + &tls.Config{ + Certificates: []tls.Certificate{cert}, + RootCAs: caCert, + ServerName: san, + }))} + creds := &rpcCredentials{&creds.UserPass{Username: username, Password: password}} + credOpts = append(credOpts, grpc.WithPerRPCCredentials(creds)) + target := fmt.Sprintf("%s:%d", serverAddr, 9339) + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + conn, err := grpc.NewClient(target, credOpts...) + if err != nil { + t.Errorf("%sVerifyGnsi:gRPC NewClient failed to %q with err %v", time.Now().String(), target, err) + return false + } + t.Logf("Connection state: %v.", conn.GetState().String()) + defer conn.Close() + authzClient := authzpb.NewAuthzClient(conn) + rsp, err := authzClient.Get(ctx, &authzpb.GetRequest{}) + if err != nil { + statusError, _ := status.FromError(err) + if statusError.Code() == codes.FailedPrecondition { + t.Logf("Expected error FAILED_PRECONDITION seen for authz Get Request with err:%v.", err) + } else { + t.Logf("Unexpected error during authz Get Request with err:%v.", err) + return false + } + } + t.Logf("gNSI authz get response is %s", rsp) + conn.Close() + return true +} + +// VerifyGnoi function to validate the gNOI service RPC after successful rotation. +func VerifyGnoi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, password string, cert tls.Certificate) bool { + credOpts := []grpc.DialOption{grpc.WithBlock(), grpc.WithTransportCredentials(credentials.NewTLS( + &tls.Config{ + Certificates: []tls.Certificate{cert}, + RootCAs: caCert, + ServerName: san, + }))} + creds := &rpcCredentials{&creds.UserPass{Username: username, Password: password}} + credOpts = append(credOpts, grpc.WithPerRPCCredentials(creds)) + target := fmt.Sprintf("%s:%d", serverAddr, 9339) + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + conn, err := grpc.NewClient(target, credOpts...) + if err != nil { + t.Errorf("VerifyGnoi : gRPC NewClient failed to %q with err %v", target, err) + return false + } + defer conn.Close() + sysClient := spb.NewSystemClient(conn) + _, err = sysClient.Ping(ctx, &spb.PingRequest{}) + if err != nil { + t.Logf("Unable to connect gnoiClient %v", err) + return false + } + conn.Close() + return true +} + +// VerifyGnmi function to validate the gNMI service RPC after successful rotation. +func VerifyGnmi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, password string, cert tls.Certificate) bool { + credOpts := []grpc.DialOption{grpc.WithBlock(), grpc.WithTransportCredentials(credentials.NewTLS( + &tls.Config{ + Certificates: []tls.Certificate{cert}, + RootCAs: caCert, + ServerName: san, + }))} + creds := &rpcCredentials{&creds.UserPass{Username: username, Password: password}} + credOpts = append(credOpts, grpc.WithPerRPCCredentials(creds)) + target := fmt.Sprintf("%s:%d", serverAddr, 9339) + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + conn, err := grpc.NewClient(target, credOpts...) + if err != nil { + t.Errorf("VerifyGnmi: gRPC NewClient failed to %q with err %v", target, err) + return false + } + defer conn.Close() + gnmiClient := gnmipb.NewGNMIClient(conn) + t.Logf("%s:Sending gNMI Capability request.", time.Now().String()) + response, err := gnmiClient.Capabilities(ctx, &gnmipb.CapabilityRequest{}) + if err != nil { + t.Logf("gNMI Capability request failed with err: %v", err) + return false + } + t.Logf("VerifyGnmi:gNMI response: %s", response) + conn.Close() + return true +} + +// VerifyGribi function to validate the gRIBI service RPC after successful rotation. +func VerifyGribi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, password string, cert tls.Certificate) bool { + credOpts := []grpc.DialOption{grpc.WithBlock(), grpc.WithTransportCredentials(credentials.NewTLS( + &tls.Config{ + Certificates: []tls.Certificate{cert}, + RootCAs: caCert, + ServerName: san, + }))} + creds := &rpcCredentials{&creds.UserPass{Username: username, Password: password}} + credOpts = append(credOpts, grpc.WithPerRPCCredentials(creds)) + target := fmt.Sprintf("%s:%d", serverAddr, 9340) + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + conn, err := grpc.NewClient(target, credOpts...) + if err != nil { + t.Errorf("VerifyGribi: gRPC NewClient failed to %q with error:%v", target, err) + return false + } + defer conn.Close() + gRibiClient := gribipb.NewGRIBIClient(conn) + _, err = gRibiClient.Get(ctx, &gribipb.GetRequest{}) + if err != nil { + t.Logf("Failed to connect GribiClient with error:%v.", err) + return false + } + conn.Close() + return true +} + +// VerifyP4rt function to validate the P4rt service RPC after successful rotation. +func VerifyP4rt(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, password string, cert tls.Certificate) bool { + credOpts := []grpc.DialOption{grpc.WithBlock(), grpc.WithTransportCredentials(credentials.NewTLS( + &tls.Config{ + Certificates: []tls.Certificate{cert}, + RootCAs: caCert, + ServerName: san, + }))} + creds := &rpcCredentials{&creds.UserPass{Username: username, Password: password}} + credOpts = append(credOpts, grpc.WithPerRPCCredentials(creds)) + target := fmt.Sprintf("%s:%d", serverAddr, 9559) + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + conn, err := grpc.NewClient(target, credOpts...) + if err != nil { + t.Errorf("VerifyP4rt : gRPC NewClient failed to %q with error %v.", target, err) + } + defer conn.Close() + p4RtClient := p4rtpb.NewP4RuntimeClient(conn) + _, err = p4RtClient.Capabilities(ctx, &p4rtpb.CapabilitiesRequest{}) + if err != nil { + t.Logf("Failed to connect P4rtClient with error %v.", err) + return false + } + conn.Close() + return true +} + +// PreInitCheck function to dial gNMI/gNOI/gRIBI/p4RT services before certz rotation. +func PreInitCheck(ctx context.Context, t *testing.T, dut *ondatra.DUTDevice) bool { + + gnmiC, err := dut.RawAPIs().BindingDUT().DialGNMI(ctx) + if err != nil { + t.Fatalf("%s Failed to dial gNMI Connection with error: %v.", time.Now().String(), err) + } + t.Logf("Precheck:gNMI dial is successful %v", gnmiC) + gribiC, err := dut.RawAPIs().BindingDUT().DialGRIBI(ctx) + if err != nil { + t.Fatalf("%s Failed to dial gRIBI Connection with error: %v.", time.Now().String(), err) + } + t.Logf("Precheck:gRIBI dial is successful %v", gribiC) + gnoiC, err := dut.RawAPIs().BindingDUT().DialGNOI(ctx) + if err != nil { + t.Fatalf("%s Failed to dial gNOI Connection with error: %v.", time.Now().String(), err) + } + t.Logf("Precheck:gNOI dial is successful %v", gnoiC) + p4rtC, err := dut.RawAPIs().BindingDUT().DialP4RT(ctx) + if err != nil { + t.Fatalf("%s Failed to dial p4RT Connection with error: %v.", time.Now().String(), err) + } + t.Logf("Precheck:p4RT dial is successful %v", p4rtC) + return true +} + +// GetSslProfilelist function to fetch the existing ssl profiles on the device. +func GetSslProfilelist(ctx context.Context, t *testing.T, certzClient certzpb.CertzClient, certzGetReq *certzpb.GetProfileListRequest) { + getProfileResponse, err := certzClient.GetProfileList(ctx, certzGetReq) + if err != nil { + t.Fatalf("Get profile list request failed with %v!", err) + } + t.Logf("GetProfileResponse: %v", getProfileResponse) +} + +// PostValidationCheck function to do a validation of all services after certz rotation. +func PostValidationCheck(t *testing.T, caCert *x509.CertPool, expected_result bool, san, serverAddr, username, password string, cert tls.Certificate) bool { + t.Logf("%s:Verifying New gNSI connection.", time.Now().String()) + result := VerifyGnsi(t, caCert, san, serverAddr, username, password, cert) + if expected_result != result { + t.Fatalf("Failed with new gNSI Connection: got %v, want %v.", result, expected_result) + } + t.Logf("%s:Verifying New gNOI connection.", time.Now().String()) + result = VerifyGnoi(t, caCert, san, serverAddr, username, password, cert) + if expected_result != result { + t.Fatalf("Failed with new gNOI Connection: got %v, want %v", result, expected_result) + } + t.Logf("%s:Verifying New gRIBI connection.", time.Now().String()) + result = VerifyGribi(t, caCert, san, serverAddr, username, password, cert) + if expected_result != result { + t.Fatalf("Failed with new gRIBI Connection: got %v, want %v.", result, expected_result) + } + t.Logf("%s:Verifying New P4rt connection.", time.Now().String()) + result = VerifyP4rt(t, caCert, san, serverAddr, username, password, cert) + if expected_result != result { + t.Fatalf("Failed with new P4rt Connection: got %v, want %v.", result, expected_result) + } + t.Logf("%s:Verifying New gNMI connection.", time.Now().String()) + result = VerifyGnmi(t, caCert, san, serverAddr, username, password, cert) + if expected_result != result { + t.Fatalf("Failed with new gNMI Connection: got %v, want %v.", result, expected_result) + } + return true +} diff --git a/feature/security/gnsi/certz/tests/server_certificate_rotation/README.md b/feature/security/gnsi/certz/tests/server_certificate_rotation/README.md new file mode 100644 index 00000000000..078382814ec --- /dev/null +++ b/feature/security/gnsi/certz/tests/server_certificate_rotation/README.md @@ -0,0 +1,115 @@ +## CERTZ-3: gNSI Server Certificate Rotation + +## Summary + +Certificates on network devices (servers) must be rotated over time for various +operational reasons. The ability to perform a rotation is a key component of +safe operation practices. + +## Baseline Setup + +### Input Args + + * the set of certificate testdata generated with the mk_cas.sh script + in featureprofiles/feature/security/gnsi/certz/test_data + +### DUT Service Setup + +Configure the DUT to enable the following services (that are using gRPC) are up +and require using mTLS for authentication: + + * gNMI + * gNOI + * gNSI + * gRIBI + * P4RT + +Be prepared to load the relevant trust_bundle.pem file for each test Certificate +Authority(CA) under test on the DUT. Each CA has an RSA and ECDSA form, both +must be tested. + +## Tests + +### Certz-3.1 + +Perform these positive tests: + +Test that a server certificate can be rotated by using the gNSI certz Rotate() +api if the certificate is requested without the device generated CSR. + +Perform this test with both the RSA and ECDSA types. + + 0) Build the test data, configure the DUT to use the ca-0001 form + key/certificate/trust_bundle, use the server-${TYPE}-a key/certificate. + + 1) Connect a client to the service on the DUT. The client should maintain + it's connection to the service throughout the rotation process being + undertaken. + + 2) With the server running, connect and note that the certificate loaded + is the appropriate one, that it is the 'a' certificate in the ca-0001 + set of certificates, validate the SN/SAN are correct. + + 3) Use the gNSI Rotate RPC to load a server-${TYPE}-b key and certificate + on to the server. + + 4) Test that the certificate is properly loaded, using the Probe RPC. + Note that the new certificate is properly served by the server. Note + that the certificate's SN/SAN has changed to the 'b' certificate. + + 5) Send the Finalize RPC to the server. + + 6) Verify that the server is now serving the certifcate properly, that + the certificate is the 'b' certificate. + + 7) Verify that at no time during the rotation process were existing + connections to the service impaired / restarted / delayed due to + the rotation event. + + +### Certz-3.2 + +Perform these negative tests: + +Test that a server certificate can be rotated by using the gNSI certz Rotate() +api if the certificate is requested without the device generated CSR, expect a +failure because the certificate loaded is not signed by a trusted CA. + +Perform this test with both the RSA and ECDSA types. + + 0) Build the test data, configure the DUT to use the ca-0001 form + key/certificate/trust_bundle, use the server-${TYPE}-a key/certificate. + + 1) With the server running, connect and note that the ceritficate loaded + is the appropriate one. + + 2) Use the gNSI Rotate RPC to load a ca-02/server-${TYPE}-b key and + certificate on to the server. + + 3) Test that the certificate load fails, because the certificate is not + trusted by a known CA. + + 4) Tear down the Rotate RPC, forcing the device to return to the + previously used certificate/key material. + + 5) Verify that the server is now serving the previous certifcate properly. + + + +## OpenConfig Path and RPC Coverage + +The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. + +TODO(OCRPC): Record may not be correct or complete + +```yaml +rpcs: + gnsi: + certz.v1.Certz.GetProfileList: + certz.v1.Certz.AddProfile: + certz.v1.Certz.Rotate: +``` + +## Minimum DUT Platform Requirement + +vRX diff --git a/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go new file mode 100644 index 00000000000..67100e7fadc --- /dev/null +++ b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go @@ -0,0 +1,207 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// 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 + +import ( + context "context" + "crypto/tls" + "crypto/x509" + "os" + "testing" + "time" + + setupService "github.com/openconfig/featureprofiles/feature/security/gnsi/certz/tests/internal/setup_service" + "github.com/openconfig/featureprofiles/internal/fptest" + certzpb "github.com/openconfig/gnsi/certz" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ygot/ygot" +) + +const ( + dirPath = "../../test_data/" +) + +var ( + testProfile = "newprofile" + serverAddr string + username = "certzuser" + password = "certzpasswd" + servers []string + expected_result bool + timeNow = time.Now().String() +) + +// createUser function to add an user in admin role. + +func createUser(t *testing.T, dut *ondatra.DUTDevice, user, pswd string) bool { + ocUser := &oc.System_Aaa_Authentication_User{ + Username: ygot.String(user), + Role: oc.AaaTypes_SYSTEM_DEFINED_ROLES_SYSTEM_ROLE_ADMIN, + Password: ygot.String(pswd), + } + res := gnmi.Update(t, dut, gnmi.OC().System().Aaa().Authentication().User(user).Config(), ocUser) + t.Logf("Update the user configuration:%v", res) + if res == nil { + t.Fatalf("Failed to create credentials.") + } + return true +} + +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() + if !createUser(t, dut, username, password) { + t.Fatalf("%s: Failed to create certz user.", timeNow) + } + t.Logf("Validation of all services that are using gRPC before certz rotation.") + if !setupService.PreInitCheck(context.Background(), t, dut) { + t.Fatalf("%s: Failed in the preInit checks.", timeNow) + } + + ctx := context.Background() + gnsiC, err := dut.RawAPIs().BindingDUT().DialGNSI(ctx) + if err != nil { + t.Fatalf("%s: Failed to create gNSI Connection %v", timeNow, err) + } + t.Logf("%s Precheck:gNSI connection is successful %v", timeNow, gnsiC) + + t.Logf("%s:Creation of test data.", timeNow) + if setupService.CertGeneration(t, dirPath) != nil { + t.Fatalf("%s:Failed to generate the testdata certificates.", timeNow) + } + certzClient := gnsiC.Certz() + t.Logf("%s Precheck:checking baseline ssl profile list.", timeNow) + setupService.GetSslProfilelist(ctx, t, certzClient, &certzpb.GetProfileListRequest{}) + t.Logf("%s:Adding new empty ssl profile ID.", timeNow) + addProfileResponse, err := certzClient.AddProfile(ctx, &certzpb.AddProfileRequest{SslProfileId: testProfile}) + if err != nil { + t.Fatalf("%s:Add profile request failed with %v! ", timeNow, err) + } + t.Logf("%s AddProfileResponse: %v", timeNow, addProfileResponse) + t.Logf("%s: Getting the ssl profile list after new ssl profile addition.", timeNow) + setupService.GetSslProfilelist(ctx, t, certzClient, &certzpb.GetProfileListRequest{}) + + cases := []struct { + desc string + serverCert string + serverKey string + trustBundle string + clientCert string + clientKey string + mismatch bool + loop uint16 + }{ + { + desc: "Certz3.1:Rotate server-rsa-a certificate/key/trustbundle from ca-01", + serverCert: dirPath + "ca-01/server-rsa-a-cert.pem", + serverKey: dirPath + "ca-01/server-rsa-a-key.pem", + trustBundle: dirPath + "ca-01/trust_bundle_01_rsa.pem", + clientCert: dirPath + "ca-01/client-rsa-a-cert.pem", + clientKey: dirPath + "ca-01/client-rsa-a-key.pem", + loop: 1, + }, + { + desc: "Certz3.1:Rotate server-rsa-b key and certificate/key/trustbundle from ca-01", + serverCert: dirPath + "ca-01/server-rsa-b-cert.pem", + serverKey: dirPath + "ca-01/server-rsa-b-key.pem", + trustBundle: dirPath + "ca-01/trust_bundle_01_rsa.pem", + clientCert: dirPath + "ca-01/client-rsa-b-cert.pem", + clientKey: dirPath + "ca-01/client-rsa-b-key.pem", + loop: 2, + }, + { + desc: "Certz3.1:Rotate server-ecdsa-a key and certificate/key/trustbundle from ca-01", + serverCert: dirPath + "ca-01/server-ecdsa-a-cert.pem", + serverKey: dirPath + "ca-01/server-ecdsa-a-key.pem", + trustBundle: dirPath + "ca-01/trust_bundle_01_ecdsa.pem", + clientCert: dirPath + "ca-01/client-ecdsa-a-cert.pem", + clientKey: dirPath + "ca-01/client-ecdsa-a-key.pem", + loop: 3, + }, + { + desc: "Certz3.1:Rotate server-ecdsa-b key and certificate/key/trustbundle from ca-01", + serverCert: dirPath + "ca-01/server-ecdsa-b-cert.pem", + serverKey: dirPath + "ca-01/server-ecdsa-b-key.pem", + trustBundle: dirPath + "ca-01/trust_bundle_01_ecdsa.pem", + clientCert: dirPath + "ca-01/client-ecdsa-b-cert.pem", + clientKey: dirPath + "ca-01/client-ecdsa-b-key.pem", + loop: 4, + }, + } + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + t.Logf("in loop %v", tc.loop) + san := setupService.ReadDecodeServerCertificate(t, tc.serverCert) + serverCert := setupService.CreateCertzChain(t, setupService.CertificateChainRequest{ + RequestType: setupService.EntityTypeCertificateChain, + ServerCertFile: tc.serverCert, + ServerKeyFile: tc.serverKey}) + serverCertEntity := setupService.CreateCertzEntity(t, setupService.EntityTypeCertificateChain, &serverCert, "servercert") + + trustCertChain := setupService.CreateCertChainFromTrustBundle(tc.trustBundle) + trustBundleEntity := setupService.CreateCertzEntity(t, setupService.EntityTypeTrustBundle, trustCertChain, "cabundle") + cert, err := tls.LoadX509KeyPair(tc.clientCert, tc.clientKey) + if err != nil { + t.Fatalf("%s Failed to load client cert: %v", timeNow, err) + } + cacert := x509.NewCertPool() + cacertBytes, err := os.ReadFile(tc.trustBundle) + if err != nil { + t.Fatalf("%s Failed to read ca bundle :%v", timeNow, err) + } + if ok := cacert.AppendCertsFromPEM(cacertBytes); !ok { + t.Fatalf("%s Failed to parse %v", timeNow, tc.trustBundle) + } + certzClient := gnsiC.Certz() + success := setupService.CertzRotate(t, cacert, certzClient, cert, san, serverAddr, testProfile, &serverCertEntity, &trustBundleEntity) + expected_result = true + if !success { + t.Fatalf("%s %s:Certz rotation failed.", timeNow, tc.desc) + } + t.Logf("%s %s:Certz rotation completed!", timeNow, tc.desc) + + // Replace config with newly added ssl profile after successful rotate. + servers = gnmi.GetAll(t, dut, gnmi.OC().System().GrpcServerAny().Name().State()) + batch := gnmi.SetBatch{} + for _, server := range servers { + gnmi.BatchReplace(&batch, gnmi.OC().System().GrpcServer(server).CertificateId().Config(), testProfile) + } + batch.Set(t, dut) + t.Logf("%s %s:replaced gNMI config with new ssl profile successfully.", timeNow, tc.desc) + time.Sleep(5 * time.Second) //waiting 5s for gnmi config propagation + t.Run("Verification of new connection after successful server certificate rotation", func(t *testing.T) { + result := setupService.PostValidationCheck(t, cacert, expected_result, san, serverAddr, username, password, cert) + if !result { + t.Fatalf("%s postTestcase service validation failed after successful rotate -got %v, want %v .", tc.desc, result, expected_result) + } + t.Logf("%s postTestcase service validation done after server certificate rotation!", tc.desc) + t.Logf("PASS: %s successfully completed!", tc.desc) + }) + }) + } + t.Logf("Cleanup of test data.") + if setupService.CertCleanup(t, dirPath) != nil { + t.Fatalf("could not run cert cleanup command.") + } +} From 1d6388a22c803f03687fe3cce7bc3f323e69aaaa Mon Sep 17 00:00:00 2001 From: priyacj Date: Fri, 2 Aug 2024 21:42:51 -0700 Subject: [PATCH 02/10] fixed metadeta --- .../tests/server_certificate_rotation/metadata.textproto | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 feature/security/gnsi/certz/tests/server_certificate_rotation/metadata.textproto diff --git a/feature/security/gnsi/certz/tests/server_certificate_rotation/metadata.textproto b/feature/security/gnsi/certz/tests/server_certificate_rotation/metadata.textproto new file mode 100644 index 00000000000..6e4314cd26a --- /dev/null +++ b/feature/security/gnsi/certz/tests/server_certificate_rotation/metadata.textproto @@ -0,0 +1,7 @@ +# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto +# proto-message: Metadata + +uuid: "884b6f4f-92d2-4645-b50b-ca44c842037b" +plan_id: "# CERTZ-3" +description: "gNSI Server Certificate Rotation" +testbed: TESTBED_DUT_ATE_2LINKS From 7ffbd0b5774880d0fe4b454d229f79567993aba0 Mon Sep 17 00:00:00 2001 From: priyacj Date: Wed, 20 Nov 2024 12:53:05 -0800 Subject: [PATCH 03/10] fixed the deprecated grpc.WithBlock:DialOption --- .../tests/internal/setup_service/setup_service.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go b/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go index 125f4ca2967..2a1dfd9cf17 100644 --- a/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go +++ b/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go @@ -428,7 +428,7 @@ func ReadDecodeServerCertificate(t *testing.T, serverCertzFile string) (san stri // VerifyGnsi function to validate the gNSI service RPC after successful rotation. func VerifyGnsi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, password string, cert tls.Certificate) bool { - credOpts := []grpc.DialOption{grpc.WithBlock(), grpc.WithTransportCredentials(credentials.NewTLS( + credOpts := []grpc.DialOption{grpc.WithTransportCredentials(credentials.NewTLS( &tls.Config{ Certificates: []tls.Certificate{cert}, RootCAs: caCert, @@ -464,7 +464,7 @@ func VerifyGnsi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, // VerifyGnoi function to validate the gNOI service RPC after successful rotation. func VerifyGnoi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, password string, cert tls.Certificate) bool { - credOpts := []grpc.DialOption{grpc.WithBlock(), grpc.WithTransportCredentials(credentials.NewTLS( + credOpts := []grpc.DialOption{grpc.WithTransportCredentials(credentials.NewTLS( &tls.Config{ Certificates: []tls.Certificate{cert}, RootCAs: caCert, @@ -493,7 +493,7 @@ func VerifyGnoi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, // VerifyGnmi function to validate the gNMI service RPC after successful rotation. func VerifyGnmi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, password string, cert tls.Certificate) bool { - credOpts := []grpc.DialOption{grpc.WithBlock(), grpc.WithTransportCredentials(credentials.NewTLS( + credOpts := []grpc.DialOption{grpc.WithTransportCredentials(credentials.NewTLS( &tls.Config{ Certificates: []tls.Certificate{cert}, RootCAs: caCert, @@ -524,7 +524,7 @@ func VerifyGnmi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, // VerifyGribi function to validate the gRIBI service RPC after successful rotation. func VerifyGribi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, password string, cert tls.Certificate) bool { - credOpts := []grpc.DialOption{grpc.WithBlock(), grpc.WithTransportCredentials(credentials.NewTLS( + credOpts := []grpc.DialOption{grpc.WithTransportCredentials(credentials.NewTLS( &tls.Config{ Certificates: []tls.Certificate{cert}, RootCAs: caCert, @@ -553,7 +553,7 @@ func VerifyGribi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, // VerifyP4rt function to validate the P4rt service RPC after successful rotation. func VerifyP4rt(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, password string, cert tls.Certificate) bool { - credOpts := []grpc.DialOption{grpc.WithBlock(), grpc.WithTransportCredentials(credentials.NewTLS( + credOpts := []grpc.DialOption{grpc.WithTransportCredentials(credentials.NewTLS( &tls.Config{ Certificates: []tls.Certificate{cert}, RootCAs: caCert, From a23257d5c7940fa5f0903653db43b0faff34c780 Mon Sep 17 00:00:00 2001 From: priyacj Date: Sun, 24 Nov 2024 22:40:51 -0800 Subject: [PATCH 04/10] fixed the script --- .../internal/setup_service/setup_service.go | 133 +++++------------- .../server_certificate_rotation_test.go | 99 ++++++------- 2 files changed, 80 insertions(+), 152 deletions(-) diff --git a/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go b/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go index 2a1dfd9cf17..fcbe15df0ff 100644 --- a/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go +++ b/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go @@ -1,4 +1,4 @@ -// Copyright 2023 Google LLC +// 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. @@ -48,6 +48,7 @@ var ( password = "certzpasswd" sn = "role001.pop55.net.example.com" servers []string + retries int ) type rpcCredentials struct { @@ -202,88 +203,32 @@ func CreateCertChainFromTrustBundle(fileName string) *certzpb.CertificateChain { //a valid check for trust not empty if len(trust) == 0 { return &certzpb.CertificateChain{} - } else { - var prevCert *certzpb.CertificateChain - var bundleToReturn *certzpb.CertificateChain - for i := len(trust) - 1; i >= 0; i-- { - if i == len(trust)-1 { - bundleToReturn = &certzpb.CertificateChain{Certificate: &certzpb.Certificate{ - Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, - Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, - Certificate: trust[i], - }, Parent: nil} - prevCert = bundleToReturn - } else { - prevCert = bundleToReturn - bundleToReturn = &certzpb.CertificateChain{Certificate: &certzpb.Certificate{ - Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, - Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, - Certificate: trust[i], - }, Parent: prevCert} - } - } - return bundleToReturn - } -} - -// CertzRotate function to request the client certificate rotation and returns true on successful rotation. -func CertzRotate(t *testing.T, caCert *x509.CertPool, certzClient certzpb.CertzClient, cert tls.Certificate, san, serverAddr, profileID string, entities ...*certzpb.Entity) bool { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - if len(entities) == 0 { - t.Logf("At least one entity required for Rotate request.") - return false - } - uploadRequest := &certzpb.UploadRequest{Entities: entities} - rotateRequest := &certzpb.RotateCertificateRequest_Certificates{Certificates: uploadRequest} - rotateCertRequest := &certzpb.RotateCertificateRequest{ - ForceOverwrite: false, - SslProfileId: profileID, - RotateRequest: rotateRequest} - //rotateRequestClient, err := certzClient.Rotate(context.Background()) - rotateRequestClient, err := certzClient.Rotate(ctx) - defer rotateRequestClient.CloseSend() - if err != nil { - t.Fatalf("Error creating rotate request client: %v", err) } - err = rotateRequestClient.Send(rotateCertRequest) - if err != nil { - t.Fatalf("Error sending rotate request: %v", err) - } - rotateResponse := &certzpb.RotateCertificateResponse{} - for i := 0; i < 20; i++ { - rotateResponse, err = rotateRequestClient.Recv() - if err == nil { - break + var prevCert *certzpb.CertificateChain + var bundleToReturn *certzpb.CertificateChain + for i := len(trust) - 1; i >= 0; i-- { + if i == len(trust)-1 { + bundleToReturn = &certzpb.CertificateChain{Certificate: &certzpb.Certificate{ + Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, + Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, + Certificate: trust[i], + }, Parent: nil} + prevCert = bundleToReturn + } else { + prevCert = bundleToReturn + bundleToReturn = &certzpb.CertificateChain{Certificate: &certzpb.Certificate{ + Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, + Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, + Certificate: trust[i], + }, Parent: prevCert} } - t.Logf("Did not receive response ~ %vs after sending rotate request. Sleeping 10s to retry...", i*10) - time.Sleep(10 * time.Second) - } - if err != nil { - t.Logf("Error fetching rotate certificate response: %v", err) - return false } - t.Logf("Received Rotate certificate response: %v", rotateResponse) - - finalizeRequest := &certzpb.RotateCertificateRequest_FinalizeRotation{FinalizeRotation: &certzpb.FinalizeRequest{}} - rotateCertRequest = &certzpb.RotateCertificateRequest{ - ForceOverwrite: false, - SslProfileId: profileID, - RotateRequest: finalizeRequest} + return bundleToReturn - err = rotateRequestClient.Send(rotateCertRequest) - if err != nil { - t.Fatalf("Error sending rotate finalize request: %v", err) - } - err = rotateRequestClient.CloseSend() - if err != nil { - t.Fatalf("Error sending rotate close send request: %v", err) - } - return true } -// ServerCertzRotate function to request the server certificate rotation and returns true on successful rotation. -func ServerCertzRotate(t *testing.T, caCert *x509.CertPool, certzClient certzpb.CertzClient, cert tls.Certificate, ctx context.Context, dut *ondatra.DUTDevice, san, serverAddr, profileID string, entities ...*certzpb.Entity) bool { +// CertzRotate function to request the server certificate rotation and returns true on successful rotation. +func CertzRotate(t *testing.T, caCert *x509.CertPool, certzClient certzpb.CertzClient, cert tls.Certificate, ctx context.Context, dut *ondatra.DUTDevice, san, serverAddr, profileID string, entities ...*certzpb.Entity) bool { if len(entities) == 0 { t.Logf("At least one entity required for Rotate request.") return false @@ -304,7 +249,8 @@ func ServerCertzRotate(t *testing.T, caCert *x509.CertPool, certzClient certzpb. t.Fatalf("Error sending rotate request: %v", err) } rotateResponse := &certzpb.RotateCertificateResponse{} - for i := 0; i < 6; i++ { + retries = 6 + for i := 0; i < retries; i++ { rotateResponse, err = rotateRequestClient.Recv() if err == nil { break @@ -322,13 +268,15 @@ func ServerCertzRotate(t *testing.T, caCert *x509.CertPool, certzClient certzpb. servers = gnmi.GetAll(t, dut, gnmi.OC().System().GrpcServerAny().Name().State()) batch := gnmi.SetBatch{} for _, server := range servers { + t.Logf("Server:%s", server) gnmi.BatchReplace(&batch, gnmi.OC().System().GrpcServer(server).CertificateId().Config(), profileID) } batch.Set(t, dut) - t.Logf("gNMI config is replaced with new ssl profile successfully.") + t.Logf("gNMI config is replaced with new ssl profile %s successfully.", profileID) + time.Sleep(30 * time.Second) //waiting 30s for gnmi config propagation success := false //Trying for 60s for the connection to succeed. - for i := 0; i < 6; i++ { + for i := 0; i < retries; i++ { success = VerifyGnsi(t, caCert, san, serverAddr, username, password, cert) if success { break @@ -355,7 +303,7 @@ func ServerCertzRotate(t *testing.T, caCert *x509.CertPool, certzClient certzpb. } return true } else { - t.Logf("gNSI service RPC did not succeed ~60s after rotate. Certz/Rotate failed. FinalizeRequest will not be sent") + t.Logf("gNSI service RPC did not succeed ~%d*10s after rotate. Certz/Rotate failed. FinalizeRequest will not be sent", retries) return false } } @@ -382,7 +330,7 @@ func CertGeneration(t *testing.T, dirPath string) error { return err } -// CertCleanup function to clean out the CA content under test_data. +// CertCleanup function to clean out the certificate content under test_data. func CertCleanup(t *testing.T, dirPath string) error { cmd := exec.Cmd{ Path: "./cleanup.sh", @@ -404,7 +352,7 @@ func CertCleanup(t *testing.T, dirPath string) error { return err } -// ReadDecodeServerCertificate function to read and decode server certificates to extract the SubjectAltName. +// ReadDecodeServerCertificate function to read and decode server certificates to extract the SubjectAltName and validate. func ReadDecodeServerCertificate(t *testing.T, serverCertzFile string) (san string) { sc, err := os.ReadFile(serverCertzFile) if err != nil { @@ -517,7 +465,7 @@ func VerifyGnmi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, t.Logf("gNMI Capability request failed with err: %v", err) return false } - t.Logf("VerifyGnmi:gNMI response: %s", response) + t.Logf("VerifyGnmi:gNMI response: %s", response.GNMIVersion) conn.Close() return true } @@ -624,22 +572,19 @@ func PostValidationCheck(t *testing.T, caCert *x509.CertPool, expected_result bo t.Logf("%s:Verifying New gNOI connection.", time.Now().String()) result = VerifyGnoi(t, caCert, san, serverAddr, username, password, cert) if expected_result != result { - t.Fatalf("Failed with new gNOI Connection: got %v, want %v", result, expected_result) + t.Fatalf("Failed with new gNOI Connection: got false, want %v", expected_result) } t.Logf("%s:Verifying New gRIBI connection.", time.Now().String()) - result = VerifyGribi(t, caCert, san, serverAddr, username, password, cert) - if expected_result != result { - t.Fatalf("Failed with new gRIBI Connection: got %v, want %v.", result, expected_result) + if expected_result != VerifyGribi(t, caCert, san, serverAddr, username, password, cert) { + t.Fatalf("Failed with new gRIBI Connection: got false, want %v.", expected_result) } t.Logf("%s:Verifying New P4rt connection.", time.Now().String()) - result = VerifyP4rt(t, caCert, san, serverAddr, username, password, cert) - if expected_result != result { - t.Fatalf("Failed with new P4rt Connection: got %v, want %v.", result, expected_result) + if expected_result != VerifyP4rt(t, caCert, san, serverAddr, username, password, cert) { + t.Fatalf("Failed with new P4rt Connection: got false, want %v.", expected_result) } t.Logf("%s:Verifying New gNMI connection.", time.Now().String()) - result = VerifyGnmi(t, caCert, san, serverAddr, username, password, cert) - if expected_result != result { - t.Fatalf("Failed with new gNMI Connection: got %v, want %v.", result, expected_result) + if expected_result != VerifyGnmi(t, caCert, san, serverAddr, username, password, cert) { + t.Fatalf("Failed with new gNMI Connection: got false, want %v.", expected_result) } return true } diff --git a/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go index 67100e7fadc..815d9736eba 100644 --- a/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go +++ b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go @@ -40,13 +40,11 @@ var ( serverAddr string username = "certzuser" password = "certzpasswd" - servers []string expected_result bool timeNow = time.Now().String() ) // createUser function to add an user in admin role. - func createUser(t *testing.T, dut *ondatra.DUTDevice, user, pswd string) bool { ocUser := &oc.System_Aaa_Authentication_User{ Username: ygot.String(user), @@ -68,7 +66,6 @@ func TestMain(m *testing.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() if !createUser(t, dut, username, password) { @@ -78,14 +75,12 @@ func TestServerCertRotation(t *testing.T) { if !setupService.PreInitCheck(context.Background(), t, dut) { t.Fatalf("%s: Failed in the preInit checks.", timeNow) } - ctx := context.Background() gnsiC, err := dut.RawAPIs().BindingDUT().DialGNSI(ctx) if err != nil { t.Fatalf("%s: Failed to create gNSI Connection %v", timeNow, err) } t.Logf("%s Precheck:gNSI connection is successful %v", timeNow, gnsiC) - t.Logf("%s:Creation of test data.", timeNow) if setupService.CertGeneration(t, dirPath) != nil { t.Fatalf("%s:Failed to generate the testdata certificates.", timeNow) @@ -101,57 +96,55 @@ func TestServerCertRotation(t *testing.T) { t.Logf("%s AddProfileResponse: %v", timeNow, addProfileResponse) t.Logf("%s: Getting the ssl profile list after new ssl profile addition.", timeNow) setupService.GetSslProfilelist(ctx, t, certzClient, &certzpb.GetProfileListRequest{}) - cases := []struct { - desc string - serverCert string - serverKey string - trustBundle string - clientCert string - clientKey string - mismatch bool - loop uint16 + desc string + serverCert string + serverKey string + trustBundle string + p7btrustBundle string + clientCert string + clientKey string + mismatch bool }{ { - desc: "Certz3.1:Rotate server-rsa-a certificate/key/trustbundle from ca-01", - serverCert: dirPath + "ca-01/server-rsa-a-cert.pem", - serverKey: dirPath + "ca-01/server-rsa-a-key.pem", - trustBundle: dirPath + "ca-01/trust_bundle_01_rsa.pem", - clientCert: dirPath + "ca-01/client-rsa-a-cert.pem", - clientKey: dirPath + "ca-01/client-rsa-a-key.pem", - loop: 1, + desc: "Certz3.1:Rotate server-rsa-a certificate/key/trustbundle from ca-01", + serverCert: dirPath + "ca-01/server-rsa-a-cert.pem", + serverKey: dirPath + "ca-01/server-rsa-a-key.pem", + trustBundle: dirPath + "ca-01/trust_bundle_01_rsa.pem", + p7btrustBundle: dirPath + "ca-01/trust_bundle_01_rsa.p7b", + clientCert: dirPath + "ca-01/client-rsa-a-cert.pem", + clientKey: dirPath + "ca-01/client-rsa-a-key.pem", }, { - desc: "Certz3.1:Rotate server-rsa-b key and certificate/key/trustbundle from ca-01", - serverCert: dirPath + "ca-01/server-rsa-b-cert.pem", - serverKey: dirPath + "ca-01/server-rsa-b-key.pem", - trustBundle: dirPath + "ca-01/trust_bundle_01_rsa.pem", - clientCert: dirPath + "ca-01/client-rsa-b-cert.pem", - clientKey: dirPath + "ca-01/client-rsa-b-key.pem", - loop: 2, + desc: "Certz3.1:Rotate server-rsa-b key and certificate/key/trustbundle from ca-01", + serverCert: dirPath + "ca-01/server-rsa-b-cert.pem", + serverKey: dirPath + "ca-01/server-rsa-b-key.pem", + trustBundle: dirPath + "ca-01/trust_bundle_01_rsa.pem", + p7btrustBundle: dirPath + "ca-01/trust_bundle_01_rsa.p7b", + clientCert: dirPath + "ca-01/client-rsa-b-cert.pem", + clientKey: dirPath + "ca-01/client-rsa-b-key.pem", }, { - desc: "Certz3.1:Rotate server-ecdsa-a key and certificate/key/trustbundle from ca-01", - serverCert: dirPath + "ca-01/server-ecdsa-a-cert.pem", - serverKey: dirPath + "ca-01/server-ecdsa-a-key.pem", - trustBundle: dirPath + "ca-01/trust_bundle_01_ecdsa.pem", - clientCert: dirPath + "ca-01/client-ecdsa-a-cert.pem", - clientKey: dirPath + "ca-01/client-ecdsa-a-key.pem", - loop: 3, + desc: "Certz3.1:Rotate server-ecdsa-a key and certificate/key/trustbundle from ca-01", + serverCert: dirPath + "ca-01/server-ecdsa-a-cert.pem", + serverKey: dirPath + "ca-01/server-ecdsa-a-key.pem", + trustBundle: dirPath + "ca-01/trust_bundle_01_ecdsa.pem", + p7btrustBundle: dirPath + "ca-01/trust_bundle_01_ecdsa.p7b", + clientCert: dirPath + "ca-01/client-ecdsa-a-cert.pem", + clientKey: dirPath + "ca-01/client-ecdsa-a-key.pem", }, { - desc: "Certz3.1:Rotate server-ecdsa-b key and certificate/key/trustbundle from ca-01", - serverCert: dirPath + "ca-01/server-ecdsa-b-cert.pem", - serverKey: dirPath + "ca-01/server-ecdsa-b-key.pem", - trustBundle: dirPath + "ca-01/trust_bundle_01_ecdsa.pem", - clientCert: dirPath + "ca-01/client-ecdsa-b-cert.pem", - clientKey: dirPath + "ca-01/client-ecdsa-b-key.pem", - loop: 4, + desc: "Certz3.1:Rotate server-ecdsa-b key and certificate/key/trustbundle from ca-01", + serverCert: dirPath + "ca-01/server-ecdsa-b-cert.pem", + serverKey: dirPath + "ca-01/server-ecdsa-b-key.pem", + trustBundle: dirPath + "ca-01/trust_bundle_01_ecdsa.pem", + p7btrustBundle: dirPath + "ca-01/trust_bundle_01_ecdsa.p7b", + clientCert: dirPath + "ca-01/client-ecdsa-b-cert.pem", + clientKey: dirPath + "ca-01/client-ecdsa-b-key.pem", }, } for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { - t.Logf("in loop %v", tc.loop) san := setupService.ReadDecodeServerCertificate(t, tc.serverCert) serverCert := setupService.CreateCertzChain(t, setupService.CertificateChainRequest{ RequestType: setupService.EntityTypeCertificateChain, @@ -174,34 +167,24 @@ func TestServerCertRotation(t *testing.T) { t.Fatalf("%s Failed to parse %v", timeNow, tc.trustBundle) } certzClient := gnsiC.Certz() - success := setupService.CertzRotate(t, cacert, certzClient, cert, san, serverAddr, testProfile, &serverCertEntity, &trustBundleEntity) + success := setupService.CertzRotate(t, cacert, certzClient, cert, ctx, dut, san, serverAddr, testProfile, &serverCertEntity, &trustBundleEntity) expected_result = true if !success { - t.Fatalf("%s %s:Certz rotation failed.", timeNow, tc.desc) - } - t.Logf("%s %s:Certz rotation completed!", timeNow, tc.desc) - - // Replace config with newly added ssl profile after successful rotate. - servers = gnmi.GetAll(t, dut, gnmi.OC().System().GrpcServerAny().Name().State()) - batch := gnmi.SetBatch{} - for _, server := range servers { - gnmi.BatchReplace(&batch, gnmi.OC().System().GrpcServer(server).CertificateId().Config(), testProfile) + t.Fatalf("%s %s:Server certificate rotation failed.", timeNow, tc.desc) } - batch.Set(t, dut) - t.Logf("%s %s:replaced gNMI config with new ssl profile successfully.", timeNow, tc.desc) - time.Sleep(5 * time.Second) //waiting 5s for gnmi config propagation + t.Logf("%s %s:Server certificate rotation completed!", timeNow, tc.desc) t.Run("Verification of new connection after successful server certificate rotation", func(t *testing.T) { result := setupService.PostValidationCheck(t, cacert, expected_result, san, serverAddr, username, password, cert) if !result { t.Fatalf("%s postTestcase service validation failed after successful rotate -got %v, want %v .", tc.desc, result, expected_result) } t.Logf("%s postTestcase service validation done after server certificate rotation!", tc.desc) - t.Logf("PASS: %s successfully completed!", tc.desc) }) }) + t.Logf("PASS: %s successfully completed!", tc.desc) } t.Logf("Cleanup of test data.") if setupService.CertCleanup(t, dirPath) != nil { - t.Fatalf("could not run cert cleanup command.") + t.Fatalf("could not run testdata cleanup command.") } } From f8d55a612b3daa6662d30540787cc9ba561c2146 Mon Sep 17 00:00:00 2001 From: priyacj Date: Mon, 25 Nov 2024 14:36:21 -0800 Subject: [PATCH 05/10] fixed the static check error --- .../server_certificate_rotation/README.md | 113 ------------------ .../server_certificate_rotation_test.go | 8 +- 2 files changed, 4 insertions(+), 117 deletions(-) delete mode 100644 feature/security/gnsi/certz/server_certificate_rotation/README.md diff --git a/feature/security/gnsi/certz/server_certificate_rotation/README.md b/feature/security/gnsi/certz/server_certificate_rotation/README.md deleted file mode 100644 index 8a2afe1c30b..00000000000 --- a/feature/security/gnsi/certz/server_certificate_rotation/README.md +++ /dev/null @@ -1,113 +0,0 @@ -# Server Certificate Rotation - -## Summary - -Certificates on network devices (servers) must be rotated over time for various -operational reasons. The ability to perform a rotation is a key component of -safe operation practices. - -## Baseline Setup - -### Input Args - - * the set of certificate testdata generated with the mk_cas.sh script - in featureprofiles/feature/security/gnsi/certz/test_data - -### DUT Service Setup - -Configure the DUT to enable the following services (that are using gRPC) are up -and require using mTLS for authentication: - - * gNMI - * gNOI - * gNSI - * gRIBI - * P4RT - -Be prepared to load the relevant trust_bundle.pem file for each test Certificate -Authority(CA) under test on the DUT. Each CA has an RSA and ECDSA form, both -must be tested. - -## Tests - -### Certz-3.1 - -Perform these positive tests: - -Test that a server certificate can be rotated by using the gNSI certz Rotate() -api if the certificate is requested without the device generated CSR. - -Perform this test with both the RSA and ECDSA types. - - 0) Build the test data, configure the DUT to use the ca-0001 form - key/certificate/trust_bundle, use the server-${TYPE}-a key/certificate. - - 1) Connect a client to the service on the DUT. The client should maintain - it's connection to the service throughout the rotation process being - undertaken. - - 2) With the server running, connect and note that the certificate loaded - is the appropriate one, that it is the 'a' certificate in the ca-0001 - set of certificates, validate the SN/SAN are correct. - - 3) Use the gNSI Rotate RPC to load a server-${TYPE}-b key and certificate - on to the server. - - 4) Test that the certificate is properly loaded, using the Probe RPC. - Note that the new certificate is properly served by the server. Note - that the certificate's SN/SAN has changed to the 'b' certificate. - - 5) Send the Finalize RPC to the server. - - 6) Verify that the server is now serving the certifcate properly, that - the certificate is the 'b' certificate. - - 7) Verify that at no time during the rotation process were existing - connections to the service impaired / restarted / delayed due to - the rotation event. - - -### Certz-3.2 - -Perform these negative tests: - -Test that a server certificate can be rotated by using the gNSI certz Rotate() -api if the certificate is requested without the device generated CSR, expect a -failure because the certificate loaded is not signed by a trusted CA. - -Perform this test with both the RSA and ECDSA types. - - 0) Build the test data, configure the DUT to use the ca-0001 form - key/certificate/trust_bundle, use the server-${TYPE}-a key/certificate. - - 1) With the server running, connect and note that the ceritficate loaded - is the appropriate one. - - 2) Use the gNSI Rotate RPC to load a ca-02/server-${TYPE}-b key and - certificate on to the server. - - 3) Test that the certificate load fails, because the certificate is not - trusted by a known CA. - - 4) Tear down the Rotate RPC, forcing the device to return to the - previously used certificate/key material. - - 5) Verify that the server is now serving the previous certifcate properly. - - - -## OpenConfig Path and RPC Coverage - -The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here. - -TODO(OCRPC): Record may not be correct or complete - -```yaml -rpcs: - gnsi: - certz.v1.Certz.Rotate: -``` - -## Minimum DUT Platform Requirement - -vRX diff --git a/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go index 815d9736eba..b9d4d61b2fd 100644 --- a/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go +++ b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go @@ -145,7 +145,7 @@ func TestServerCertRotation(t *testing.T) { } for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { - san := setupService.ReadDecodeServerCertificate(t, tc.serverCert) + san := setupService.ReadDecodeServerCertificate(t, tc.serverCert) serverCert := setupService.CreateCertzChain(t, setupService.CertificateChainRequest{ RequestType: setupService.EntityTypeCertificateChain, ServerCertFile: tc.serverCert, @@ -164,19 +164,19 @@ func TestServerCertRotation(t *testing.T) { t.Fatalf("%s Failed to read ca bundle :%v", timeNow, err) } if ok := cacert.AppendCertsFromPEM(cacertBytes); !ok { - t.Fatalf("%s Failed to parse %v", timeNow, tc.trustBundle) + t.Fatalf("%s Failed to parse %s", timeNow, tc.trustBundle) } certzClient := gnsiC.Certz() success := setupService.CertzRotate(t, cacert, certzClient, cert, ctx, dut, san, serverAddr, testProfile, &serverCertEntity, &trustBundleEntity) - expected_result = true if !success { t.Fatalf("%s %s:Server certificate rotation failed.", timeNow, tc.desc) } t.Logf("%s %s:Server certificate rotation completed!", timeNow, tc.desc) t.Run("Verification of new connection after successful server certificate rotation", func(t *testing.T) { + expected_result = true result := setupService.PostValidationCheck(t, cacert, expected_result, san, serverAddr, username, password, cert) if !result { - t.Fatalf("%s postTestcase service validation failed after successful rotate -got %v, want %v .", tc.desc, result, expected_result) + t.Fatalf("%s postTestcase service validation failed after successful rotate.", tc.desc) } t.Logf("%s postTestcase service validation done after server certificate rotation!", tc.desc) }) From 045cfe32ba820621d62f250c8155e5e00783cf94 Mon Sep 17 00:00:00 2001 From: priyacj Date: Tue, 26 Nov 2024 10:44:04 -0800 Subject: [PATCH 06/10] fixed the string error --- .../server_certificate_rotation_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go index b9d4d61b2fd..0cfb83b245c 100644 --- a/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go +++ b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go @@ -41,7 +41,7 @@ var ( username = "certzuser" password = "certzpasswd" expected_result bool - timeNow = time.Now().String() + timeNow string ) // createUser function to add an user in admin role. @@ -68,6 +68,7 @@ func TestMain(m *testing.M) { func TestServerCertRotation(t *testing.T) { dut := ondatra.DUT(t, "dut") serverAddr = dut.Name() + timeNow = time.Now().String() if !createUser(t, dut, username, password) { t.Fatalf("%s: Failed to create certz user.", timeNow) } @@ -145,13 +146,12 @@ func TestServerCertRotation(t *testing.T) { } for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { - san := setupService.ReadDecodeServerCertificate(t, tc.serverCert) + san := setupService.ReadDecodeServerCertificate(t, tc.serverCert) serverCert := setupService.CreateCertzChain(t, setupService.CertificateChainRequest{ RequestType: setupService.EntityTypeCertificateChain, ServerCertFile: tc.serverCert, ServerKeyFile: tc.serverKey}) serverCertEntity := setupService.CreateCertzEntity(t, setupService.EntityTypeCertificateChain, &serverCert, "servercert") - trustCertChain := setupService.CreateCertChainFromTrustBundle(tc.trustBundle) trustBundleEntity := setupService.CreateCertzEntity(t, setupService.EntityTypeTrustBundle, trustCertChain, "cabundle") cert, err := tls.LoadX509KeyPair(tc.clientCert, tc.clientKey) @@ -167,7 +167,7 @@ func TestServerCertRotation(t *testing.T) { t.Fatalf("%s Failed to parse %s", timeNow, tc.trustBundle) } certzClient := gnsiC.Certz() - success := setupService.CertzRotate(t, cacert, certzClient, cert, ctx, dut, san, serverAddr, testProfile, &serverCertEntity, &trustBundleEntity) + success := setupService.CertzRotate(t, cacert, certzClient, cert, ctx, dut, san, serverAddr, testProfile, &serverCertEntity, &trustBundleEntity) if !success { t.Fatalf("%s %s:Server certificate rotation failed.", timeNow, tc.desc) } @@ -181,7 +181,7 @@ func TestServerCertRotation(t *testing.T) { t.Logf("%s postTestcase service validation done after server certificate rotation!", tc.desc) }) }) - t.Logf("PASS: %s successfully completed!", tc.desc) + t.Logf("PASS: %s successfully completed!", tc.desc) } t.Logf("Cleanup of test data.") if setupService.CertCleanup(t, dirPath) != nil { From 60e89b8b5734952dbd4389fb64acdac73821b3ef Mon Sep 17 00:00:00 2001 From: priyacj Date: Tue, 7 Jan 2025 11:39:43 -0800 Subject: [PATCH 07/10] fixed the lint static errors and feedback comments --- .../internal/setup_service/setup_service.go | 145 +++++++++++------- 1 file changed, 87 insertions(+), 58 deletions(-) diff --git a/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go b/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go index fcbe15df0ff..832f66ba739 100644 --- a/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go +++ b/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go @@ -55,7 +55,7 @@ type rpcCredentials struct { *creds.UserPass } -func (r *rpcCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { +func (r *rpcCredentials) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) { return map[string]string{ "username": r.UserPass.Username, "password": r.UserPass.Password, @@ -224,14 +224,60 @@ func CreateCertChainFromTrustBundle(fileName string) *certzpb.CertificateChain { } } return bundleToReturn +} +// CreateCertChainFromp7bTrustBundle function to create the trust bundle encoded in pkcs7. +func CreateCertChainFromp7bTrustBundle(fileName string) *certzpb.CertificateChain { + pemData, err := os.ReadFile(fileName) + if err != nil { + return &certzpb.CertificateChain{} + } + var trust [][]byte + for { + var block *pem.Block + block, pemData = pem.Decode(pemData) + if block == nil { + break + } + if block.Type != "CERTIFICATE" { + continue + } + p := pem.EncodeToMemory(block) + if p == nil { + return &certzpb.CertificateChain{} + } + trust = append(trust, p) + } + //a valid check for trust not empty + if len(trust) == 0 { + return &certzpb.CertificateChain{} + } + var prevCert *certzpb.CertificateChain + var bundleToReturn *certzpb.CertificateChain + for i := len(trust) - 1; i >= 0; i-- { + if i == len(trust)-1 { + bundleToReturn = &certzpb.CertificateChain{Certificate: &certzpb.Certificate{ + Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, + Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, + Certificate: trust[i], + }, Parent: nil} + prevCert = bundleToReturn + } else { + prevCert = bundleToReturn + bundleToReturn = &certzpb.CertificateChain{Certificate: &certzpb.Certificate{ + Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, + Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, + Certificate: trust[i], + }, Parent: prevCert} + } + } + return bundleToReturn } // CertzRotate function to request the server certificate rotation and returns true on successful rotation. -func CertzRotate(t *testing.T, caCert *x509.CertPool, certzClient certzpb.CertzClient, cert tls.Certificate, ctx context.Context, dut *ondatra.DUTDevice, san, serverAddr, profileID string, entities ...*certzpb.Entity) bool { +func CertzRotate(_ context.Context, t *testing.T, caCert *x509.CertPool, certzClient certzpb.CertzClient, cert tls.Certificate, dut *ondatra.DUTDevice, san, serverAddr, profileID string, entities ...*certzpb.Entity) bool { if len(entities) == 0 { - t.Logf("At least one entity required for Rotate request.") - return false + t.Fatalf("At least one entity required for Rotate request.") } uploadRequest := &certzpb.UploadRequest{Entities: entities} rotateRequest := &certzpb.RotateCertificateRequest_Certificates{Certificates: uploadRequest} @@ -259,11 +305,9 @@ func CertzRotate(t *testing.T, caCert *x509.CertPool, certzClient certzpb.CertzC time.Sleep(10 * time.Second) } if err != nil { - t.Logf("Error fetching rotate certificate response: %v", err) - return false + t.Fatalf("Error fetching rotate certificate response: %v", err) } t.Logf("Received Rotate certificate response: %v", rotateResponse) - // Replace config with newly added ssl profile after successful rotate. servers = gnmi.GetAll(t, dut, gnmi.OC().System().GrpcServerAny().Name().State()) batch := gnmi.SetBatch{} @@ -281,31 +325,25 @@ func CertzRotate(t *testing.T, caCert *x509.CertPool, certzClient certzpb.CertzC if success { break } - if i != 10 { - t.Logf("gNSI service RPC did not succeed ~ %vs after rotate. Sleeping 10s to retry...", i*10) - } time.Sleep(10 * time.Second) } - if success { - finalizeRequest := &certzpb.RotateCertificateRequest_FinalizeRotation{FinalizeRotation: &certzpb.FinalizeRequest{}} - rotateCertRequest = &certzpb.RotateCertificateRequest{ - ForceOverwrite: false, - SslProfileId: profileID, - RotateRequest: finalizeRequest} - - err = rotateRequestClient.Send(rotateCertRequest) - if err != nil { - t.Fatalf("Error sending rotate finalize request: %v", err) - } - err = rotateRequestClient.CloseSend() - if err != nil { - t.Fatalf("Error sending rotate close send request: %v", err) - } - return true - } else { - t.Logf("gNSI service RPC did not succeed ~%d*10s after rotate. Certz/Rotate failed. FinalizeRequest will not be sent", retries) - return false + if !success { + t.Fatalf("gNSI service RPC did not succeed ~%d*10s after rotate. Certz/Rotate failed. FinalizeRequest will not be sent", retries) + } + finalizeRequest := &certzpb.RotateCertificateRequest_FinalizeRotation{FinalizeRotation: &certzpb.FinalizeRequest{}} + rotateCertRequest = &certzpb.RotateCertificateRequest{ + ForceOverwrite: false, + SslProfileId: profileID, + RotateRequest: finalizeRequest} + err = rotateRequestClient.Send(rotateCertRequest) + if err != nil { + t.Fatalf("Error sending rotate finalize request: %v", err) + } + err = rotateRequestClient.CloseSend() + if err != nil { + t.Fatalf("Error sending rotate close send request: %v", err) } + return true } // CertGeneration function to create test data for use in TLS tests. @@ -319,13 +357,11 @@ func CertGeneration(t *testing.T, dirPath string) error { t.Logf("Executing cert generation command %v.", cmd) err := cmd.Start() if err != nil { - t.Logf("Cert generation command failed with error:%v.", err) - return err + t.Fatalf("Cert generation command failed with error:%v.", err) } err = cmd.Wait() if err != nil { - t.Logf("Failed to run cert generation command during wait with error:%v.", err) - return err + t.Fatalf("Failed to run cert generation command during wait with error:%v.", err) } return err } @@ -341,13 +377,11 @@ func CertCleanup(t *testing.T, dirPath string) error { t.Logf("Executing cleanup command") err := cmd.Start() if err != nil { - t.Logf("Testdata cleanup command failed with error:%v.", err) - return err + t.Fatalf("Testdata cleanup command failed with error:%v.", err) } err = cmd.Wait() if err != nil { - t.Logf("Testdata cleanup command failed during wait with the error:%v.", err) - return err + t.Fatalf("Testdata cleanup command failed during wait with the error:%v.", err) } return err } @@ -401,8 +435,7 @@ func VerifyGnsi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, if statusError.Code() == codes.FailedPrecondition { t.Logf("Expected error FAILED_PRECONDITION seen for authz Get Request with err:%v.", err) } else { - t.Logf("Unexpected error during authz Get Request with err:%v.", err) - return false + t.Fatalf("Unexpected error during authz Get Request with err:%v.", err) } } t.Logf("gNSI authz get response is %s", rsp) @@ -432,8 +465,7 @@ func VerifyGnoi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, sysClient := spb.NewSystemClient(conn) _, err = sysClient.Ping(ctx, &spb.PingRequest{}) if err != nil { - t.Logf("Unable to connect gnoiClient %v", err) - return false + t.Fatalf("Unable to connect gnoiClient %v", err) } conn.Close() return true @@ -462,8 +494,7 @@ func VerifyGnmi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, t.Logf("%s:Sending gNMI Capability request.", time.Now().String()) response, err := gnmiClient.Capabilities(ctx, &gnmipb.CapabilityRequest{}) if err != nil { - t.Logf("gNMI Capability request failed with err: %v", err) - return false + t.Fatalf("gNMI Capability request failed with err: %v", err) } t.Logf("VerifyGnmi:gNMI response: %s", response.GNMIVersion) conn.Close() @@ -492,8 +523,7 @@ func VerifyGribi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, gRibiClient := gribipb.NewGRIBIClient(conn) _, err = gRibiClient.Get(ctx, &gribipb.GetRequest{}) if err != nil { - t.Logf("Failed to connect GribiClient with error:%v.", err) - return false + t.Fatalf("Failed to connect GribiClient with error:%v.", err) } conn.Close() return true @@ -520,8 +550,7 @@ func VerifyP4rt(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, p4RtClient := p4rtpb.NewP4RuntimeClient(conn) _, err = p4RtClient.Capabilities(ctx, &p4rtpb.CapabilitiesRequest{}) if err != nil { - t.Logf("Failed to connect P4rtClient with error %v.", err) - return false + t.Fatalf("Failed to connect P4rtClient with error %v.", err) } conn.Close() return true @@ -563,28 +592,28 @@ func GetSslProfilelist(ctx context.Context, t *testing.T, certzClient certzpb.Ce } // PostValidationCheck function to do a validation of all services after certz rotation. -func PostValidationCheck(t *testing.T, caCert *x509.CertPool, expected_result bool, san, serverAddr, username, password string, cert tls.Certificate) bool { +func PostValidationCheck(t *testing.T, caCert *x509.CertPool, expectedResult bool, san, serverAddr, username, password string, cert tls.Certificate) bool { t.Logf("%s:Verifying New gNSI connection.", time.Now().String()) result := VerifyGnsi(t, caCert, san, serverAddr, username, password, cert) - if expected_result != result { - t.Fatalf("Failed with new gNSI Connection: got %v, want %v.", result, expected_result) + if expectedResult != result { + t.Fatalf("Failed with new gNSI Connection: got %v, want %v.", result, expectedResult) } t.Logf("%s:Verifying New gNOI connection.", time.Now().String()) result = VerifyGnoi(t, caCert, san, serverAddr, username, password, cert) - if expected_result != result { - t.Fatalf("Failed with new gNOI Connection: got false, want %v", expected_result) + if expectedResult != result { + t.Fatalf("Failed with new gNOI Connection: got false, want %v", expectedResult) } t.Logf("%s:Verifying New gRIBI connection.", time.Now().String()) - if expected_result != VerifyGribi(t, caCert, san, serverAddr, username, password, cert) { - t.Fatalf("Failed with new gRIBI Connection: got false, want %v.", expected_result) + if expectedResult != VerifyGribi(t, caCert, san, serverAddr, username, password, cert) { + t.Fatalf("Failed with new gRIBI Connection: got false, want %v.", expectedResult) } t.Logf("%s:Verifying New P4rt connection.", time.Now().String()) - if expected_result != VerifyP4rt(t, caCert, san, serverAddr, username, password, cert) { - t.Fatalf("Failed with new P4rt Connection: got false, want %v.", expected_result) + if expectedResult != VerifyP4rt(t, caCert, san, serverAddr, username, password, cert) { + t.Fatalf("Failed with new P4rt Connection: got false, want %v.", expectedResult) } t.Logf("%s:Verifying New gNMI connection.", time.Now().String()) - if expected_result != VerifyGnmi(t, caCert, san, serverAddr, username, password, cert) { - t.Fatalf("Failed with new gNMI Connection: got false, want %v.", expected_result) + if expectedResult != VerifyGnmi(t, caCert, san, serverAddr, username, password, cert) { + t.Fatalf("Failed with new gNMI Connection: got false, want %v.", expectedResult) } return true } From 9cc0aad0246268cb79f2027034dd3b5fc921acf1 Mon Sep 17 00:00:00 2001 From: priyacj Date: Tue, 7 Jan 2025 12:32:47 -0800 Subject: [PATCH 08/10] modified server_certificate_rotation/server_certificate_rotation_test.go --- .../server_certificate_rotation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go index 0cfb83b245c..5c2f56eeca8 100644 --- a/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go +++ b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go @@ -167,7 +167,7 @@ func TestServerCertRotation(t *testing.T) { t.Fatalf("%s Failed to parse %s", timeNow, tc.trustBundle) } certzClient := gnsiC.Certz() - success := setupService.CertzRotate(t, cacert, certzClient, cert, ctx, dut, san, serverAddr, testProfile, &serverCertEntity, &trustBundleEntity) + success := setupService.CertzRotate(ctx, t, cacert, certzClient, cert, dut, san, serverAddr, testProfile, &serverCertEntity, &trustBundleEntity) if !success { t.Fatalf("%s %s:Server certificate rotation failed.", timeNow, tc.desc) } From 69c668a4379aedef3e46f91fafe46bfbb4f35226 Mon Sep 17 00:00:00 2001 From: priyacj Date: Mon, 13 Jan 2025 15:05:57 -0800 Subject: [PATCH 09/10] taken care of the comments --- .../internal/setup_service/setup_service.go | 133 +++++++----------- .../server_certificate_rotation_test.go | 20 +-- 2 files changed, 59 insertions(+), 94 deletions(-) diff --git a/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go b/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go index 832f66ba739..5778917721d 100644 --- a/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go +++ b/feature/security/gnsi/certz/tests/internal/setup_service/setup_service.go @@ -18,7 +18,7 @@ package setupservice import ( - context "context" + "context" "crypto/tls" "crypto/x509" "encoding/pem" @@ -79,14 +79,6 @@ const ( EntityTypeAuthPolicy entityType = 3 ) -// CertificateChainRequest is an input argument for the type definition for the CreateCertzChain. -type CertificateChainRequest struct { - RequestType entityType - ServerCertFile string - ServerKeyFile string - TrustBundleFile string -} - // CreateCertzEntity function to create certificate entity of type certificate chain/trust bundle/CRL/Authpolicy. func CreateCertzEntity(t *testing.T, typeOfEntity entityType, entityContent any, entityVersion string) certzpb.Entity { @@ -128,6 +120,14 @@ func CreateCertzEntity(t *testing.T, typeOfEntity entityType, entityContent any, return certzpb.Entity{} } +// CertificateChainRequest is an input argument for the type definition for the CreateCertzChain. +type CertificateChainRequest struct { + RequestType entityType + ServerCertFile string + ServerKeyFile string + TrustBundleFile string +} + // CreateCertzChain function to get the certificate chain of type certificate chain/trust bundle. func CreateCertzChain(t *testing.T, certData CertificateChainRequest) certzpb.CertificateChain { @@ -200,76 +200,31 @@ func CreateCertChainFromTrustBundle(fileName string) *certzpb.CertificateChain { } trust = append(trust, p) } - //a valid check for trust not empty - if len(trust) == 0 { - return &certzpb.CertificateChain{} - } - var prevCert *certzpb.CertificateChain - var bundleToReturn *certzpb.CertificateChain - for i := len(trust) - 1; i >= 0; i-- { - if i == len(trust)-1 { - bundleToReturn = &certzpb.CertificateChain{Certificate: &certzpb.Certificate{ - Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, - Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, - Certificate: trust[i], - }, Parent: nil} - prevCert = bundleToReturn - } else { - prevCert = bundleToReturn - bundleToReturn = &certzpb.CertificateChain{Certificate: &certzpb.Certificate{ - Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, - Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, - Certificate: trust[i], - }, Parent: prevCert} - } - } - return bundleToReturn -} - -// CreateCertChainFromp7bTrustBundle function to create the trust bundle encoded in pkcs7. -func CreateCertChainFromp7bTrustBundle(fileName string) *certzpb.CertificateChain { - pemData, err := os.ReadFile(fileName) - if err != nil { - return &certzpb.CertificateChain{} - } - var trust [][]byte - for { - var block *pem.Block - block, pemData = pem.Decode(pemData) - if block == nil { - break - } - if block.Type != "CERTIFICATE" { - continue - } - p := pem.EncodeToMemory(block) - if p == nil { - return &certzpb.CertificateChain{} - } - trust = append(trust, p) - } - //a valid check for trust not empty + //To check if trust is an empty slice if len(trust) == 0 { return &certzpb.CertificateChain{} } - var prevCert *certzpb.CertificateChain - var bundleToReturn *certzpb.CertificateChain - for i := len(trust) - 1; i >= 0; i-- { - if i == len(trust)-1 { - bundleToReturn = &certzpb.CertificateChain{Certificate: &certzpb.Certificate{ - Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, - Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, - Certificate: trust[i], - }, Parent: nil} - prevCert = bundleToReturn - } else { - prevCert = bundleToReturn - bundleToReturn = &certzpb.CertificateChain{Certificate: &certzpb.Certificate{ + // Create the first certificate chain object + bundleToReturn := &certzpb.CertificateChain{ + Certificate: &certzpb.Certificate{ + Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, + Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, + Certificate: trust[len(trust)-1], + }, + Parent: nil, + } + prevCert := bundleToReturn + // Iterate over the remaining certificates to create the certificate chain + for i := len(trust) - 2; i >= 0; i-- { + parent := &certzpb.CertificateChain{ + Certificate: &certzpb.Certificate{ Type: certzpb.CertificateType_CERTIFICATE_TYPE_X509, Encoding: certzpb.CertificateEncoding_CERTIFICATE_ENCODING_PEM, Certificate: trust[i], - }, Parent: prevCert} + }, + Parent: prevCert, } + prevCert = parent } return bundleToReturn } @@ -277,7 +232,8 @@ func CreateCertChainFromp7bTrustBundle(fileName string) *certzpb.CertificateChai // CertzRotate function to request the server certificate rotation and returns true on successful rotation. func CertzRotate(_ context.Context, t *testing.T, caCert *x509.CertPool, certzClient certzpb.CertzClient, cert tls.Certificate, dut *ondatra.DUTDevice, san, serverAddr, profileID string, entities ...*certzpb.Entity) bool { if len(entities) == 0 { - t.Fatalf("At least one entity required for Rotate request.") + t.Logf("At least one entity required for Rotate request.") + return false } uploadRequest := &certzpb.UploadRequest{Entities: entities} rotateRequest := &certzpb.RotateCertificateRequest_Certificates{Certificates: uploadRequest} @@ -305,9 +261,11 @@ func CertzRotate(_ context.Context, t *testing.T, caCert *x509.CertPool, certzCl time.Sleep(10 * time.Second) } if err != nil { - t.Fatalf("Error fetching rotate certificate response: %v", err) + t.Logf("Error fetching rotate certificate response: %v", err) + return false } t.Logf("Received Rotate certificate response: %v", rotateResponse) + // Replace config with newly added ssl profile after successful rotate. servers = gnmi.GetAll(t, dut, gnmi.OC().System().GrpcServerAny().Name().State()) batch := gnmi.SetBatch{} @@ -325,22 +283,24 @@ func CertzRotate(_ context.Context, t *testing.T, caCert *x509.CertPool, certzCl if success { break } + t.Logf("gNSI service RPC did not succeed ~ %vs after rotate. Sleeping 10s to retry...", i*10) time.Sleep(10 * time.Second) } if !success { - t.Fatalf("gNSI service RPC did not succeed ~%d*10s after rotate. Certz/Rotate failed. FinalizeRequest will not be sent", retries) + t.Logf("gNSI service RPC did not succeed ~%d*10s after rotate. Certz/Rotate failed. FinalizeRequest will not be sent", retries) + return false } finalizeRequest := &certzpb.RotateCertificateRequest_FinalizeRotation{FinalizeRotation: &certzpb.FinalizeRequest{}} rotateCertRequest = &certzpb.RotateCertificateRequest{ ForceOverwrite: false, SslProfileId: profileID, RotateRequest: finalizeRequest} - err = rotateRequestClient.Send(rotateCertRequest) - if err != nil { + + if err := rotateRequestClient.Send(rotateCertRequest); err != nil { t.Fatalf("Error sending rotate finalize request: %v", err) } - err = rotateRequestClient.CloseSend() - if err != nil { + + if err = rotateRequestClient.CloseSend(); err != nil { t.Fatalf("Error sending rotate close send request: %v", err) } return true @@ -435,7 +395,8 @@ func VerifyGnsi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, if statusError.Code() == codes.FailedPrecondition { t.Logf("Expected error FAILED_PRECONDITION seen for authz Get Request with err:%v.", err) } else { - t.Fatalf("Unexpected error during authz Get Request with err:%v.", err) + t.Logf("Unexpected error during authz Get Request with err:%v.", err) + return false } } t.Logf("gNSI authz get response is %s", rsp) @@ -465,7 +426,8 @@ func VerifyGnoi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, sysClient := spb.NewSystemClient(conn) _, err = sysClient.Ping(ctx, &spb.PingRequest{}) if err != nil { - t.Fatalf("Unable to connect gnoiClient %v", err) + t.Logf("Unable to connect gnoiClient %v", err) + return false } conn.Close() return true @@ -494,7 +456,8 @@ func VerifyGnmi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, t.Logf("%s:Sending gNMI Capability request.", time.Now().String()) response, err := gnmiClient.Capabilities(ctx, &gnmipb.CapabilityRequest{}) if err != nil { - t.Fatalf("gNMI Capability request failed with err: %v", err) + t.Logf("gNMI Capability request failed with err: %v", err) + return false } t.Logf("VerifyGnmi:gNMI response: %s", response.GNMIVersion) conn.Close() @@ -523,7 +486,8 @@ func VerifyGribi(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, gRibiClient := gribipb.NewGRIBIClient(conn) _, err = gRibiClient.Get(ctx, &gribipb.GetRequest{}) if err != nil { - t.Fatalf("Failed to connect GribiClient with error:%v.", err) + t.Logf("Failed to connect GribiClient with error:%v.", err) + return false } conn.Close() return true @@ -550,7 +514,8 @@ func VerifyP4rt(t *testing.T, caCert *x509.CertPool, san, serverAddr, username, p4RtClient := p4rtpb.NewP4RuntimeClient(conn) _, err = p4RtClient.Capabilities(ctx, &p4rtpb.CapabilitiesRequest{}) if err != nil { - t.Fatalf("Failed to connect P4rtClient with error %v.", err) + t.Logf("Failed to connect P4rtClient with error %v.", err) + return false } conn.Close() return true diff --git a/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go index 5c2f56eeca8..ebc02313ac9 100644 --- a/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go +++ b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -package server_certificate_rotation +package servercertificaterotation import ( - context "context" + "context" "crypto/tls" "crypto/x509" "os" @@ -36,12 +36,12 @@ const ( ) var ( - testProfile = "newprofile" - serverAddr string - username = "certzuser" - password = "certzpasswd" - expected_result bool - timeNow string + testProfile = "newprofile" + serverAddr string + username = "certzuser" + password = "certzpasswd" + expectedResult bool + timeNow string ) // createUser function to add an user in admin role. @@ -173,8 +173,8 @@ func TestServerCertRotation(t *testing.T) { } t.Logf("%s %s:Server certificate rotation completed!", timeNow, tc.desc) t.Run("Verification of new connection after successful server certificate rotation", func(t *testing.T) { - expected_result = true - result := setupService.PostValidationCheck(t, cacert, expected_result, san, serverAddr, username, password, cert) + expectedResult = true + result := setupService.PostValidationCheck(t, cacert, expectedResult, san, serverAddr, username, password, cert) if !result { t.Fatalf("%s postTestcase service validation failed after successful rotate.", tc.desc) } From c4fe8b51c6870f7f5c2e2d4c6e53f42ee3564e1e Mon Sep 17 00:00:00 2001 From: priyacj Date: Mon, 13 Jan 2025 15:10:12 -0800 Subject: [PATCH 10/10] fixed the package name --- .../server_certificate_rotation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go index ebc02313ac9..abf18237eee 100644 --- a/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go +++ b/feature/security/gnsi/certz/tests/server_certificate_rotation/server_certificate_rotation_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package servercertificaterotation +package servercertificaterotationtest import ( "context"