From c7b9532377a51148831cb34711481e855217ab1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9E=D0=BB=D0=B5=D0=B3=20=D0=91=D0=BE=D1=80=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Tue, 6 Aug 2024 18:33:12 +0200 Subject: [PATCH] certmanager updated --- .gitignore | 4 +- Makefile.am | 3 +- Makefile.in | 4 +- .../certmanagercontrol.pb.go | 467 +++++++++--------- .../{certman.go => issuercli.go} | 108 ++-- cmd/certmanagerctl/main.go | 85 +++- cmd/certmanagerctl/servicecli.go | 68 +++ internal/database/database.go | 2 +- internal/database/issuer.go | 2 +- internal/logic/auth.go | 2 +- internal/logic/issuer.go | 88 +++- internal/logic/service.go | 6 +- internal/logic/x509.go | 276 ----------- internal/logic/x509_test.go | 64 --- internal/test/auxfunction_test.go | 18 + ...ic_test.go => logic_issuer_create_test.go} | 137 +++-- internal/test/logic_issuer_import_test.go | 95 ++++ internal/{logic => test}/testchain_a00.crt | 0 internal/test/testchain_a00.key | 28 ++ internal/{logic => test}/testchain_a01.crt | 0 internal/{logic => test}/testchain_a02.crt | 0 internal/{logic => test}/testchain_a03.crt | 0 pkg/cm509/testchain_a00.crt | 42 ++ pkg/cm509/testchain_a01.crt | 29 ++ pkg/cm509/testchain_a02.crt | 31 ++ pkg/cm509/testchain_a03.crt | 31 ++ pkg/cm509/x509.go | 460 +++++++++++++++++ pkg/cm509/x509_test.go | 48 ++ proto/certmanagercontrol.proto | 7 +- 29 files changed, 1376 insertions(+), 729 deletions(-) rename cmd/certmanagerctl/{certman.go => issuercli.go} (50%) create mode 100644 cmd/certmanagerctl/servicecli.go delete mode 100644 internal/logic/x509.go delete mode 100644 internal/logic/x509_test.go create mode 100644 internal/test/auxfunction_test.go rename internal/test/{logic_test.go => logic_issuer_create_test.go} (60%) create mode 100644 internal/test/logic_issuer_import_test.go rename internal/{logic => test}/testchain_a00.crt (100%) create mode 100644 internal/test/testchain_a00.key rename internal/{logic => test}/testchain_a01.crt (100%) rename internal/{logic => test}/testchain_a02.crt (100%) rename internal/{logic => test}/testchain_a03.crt (100%) create mode 100644 pkg/cm509/testchain_a00.crt create mode 100644 pkg/cm509/testchain_a01.crt create mode 100644 pkg/cm509/testchain_a02.crt create mode 100644 pkg/cm509/testchain_a03.crt create mode 100644 pkg/cm509/x509.go create mode 100644 pkg/cm509/x509_test.go diff --git a/.gitignore b/.gitignore index 5552455..c164c4a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ *~ -lbmanagerd -lbmanagerctl Makefile *.log *.status @@ -11,3 +9,5 @@ tmp.* *.tar.* cmd/certmanagerctl/certmanagerctl cmd/certmanagerd/certmanagerd +certmanagerctl +certmanagerd diff --git a/Makefile.am b/Makefile.am index eab40eb..494d9ef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,7 +15,8 @@ certmanagerd$(EXEEXT): $(certmanagerd_SOURCES) $(EXTRA_certmanagerd_SOURCES) env CGO_ENABLED=1 $(GO) build $(GOFLAGS) -o certmanagerd$(EXEEXT) $(certmanagerd_SOURCES) -certmanagerctl_SOURCES = cmd/certmanagerctl/main.go +certmanagerctl_SOURCES = cmd/certmanagerctl/main.go \ + cmd/certmanagerctl/certman.go certmanagerctl$(EXEEXT): $(certmanagerctl_SOURCES) $(EXTRA_certmanagerd_SOURCES) env CGO_ENABLED=1 $(GO) build $(GOFLAGS) -o certmanagerctl$(EXEEXT) $(certmanagerctl_SOURCES) diff --git a/Makefile.in b/Makefile.in index 1f3bd89..7541c0d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -297,7 +297,9 @@ OBJEXT = none BUILD = $(shell date -u '+%Y-%m-%d-%H%M') GOFLAGS = -v -ldflags='-s -w -X helmet/certmanager/internal/config.buildVersion=$(BUILD)' certmanagerd_SOURCES = cmd/certmanagerd/main.go -certmanagerctl_SOURCES = cmd/certmanagerctl/main.go +certmanagerctl_SOURCES = cmd/certmanagerctl/main.go \ + cmd/certmanagerctl/certman.go + EXTRA_certmanagerd_SOURCES = EXTRA_DIST = $(EXTRA_certmanagerd_SOURCES) GENDIR = api/certmanagercontrol diff --git a/api/certmanagercontrol/certmanagercontrol.pb.go b/api/certmanagercontrol/certmanagercontrol.pb.go index 3e04788..6ea1610 100644 --- a/api/certmanagercontrol/certmanagercontrol.pb.go +++ b/api/certmanagercontrol/certmanagercontrol.pb.go @@ -112,8 +112,8 @@ type CreateIssuerPairParams struct { IssuerCommonName string `protobuf:"bytes,1,opt,name=issuerCommonName,proto3" json:"issuerCommonName,omitempty"` Intermediate bool `protobuf:"varint,2,opt,name=intermediate,proto3" json:"intermediate,omitempty"` - SignerIssuerID int64 `protobuf:"varint,3,opt,name=signerIssuerID,proto3" json:"signerIssuerID,omitempty"` - SignerIssuerName string `protobuf:"bytes,4,opt,name=signerIssuerName,proto3" json:"signerIssuerName,omitempty"` + SignerID int64 `protobuf:"varint,3,opt,name=signerID,proto3" json:"signerID,omitempty"` + SignerName string `protobuf:"bytes,4,opt,name=signerName,proto3" json:"signerName,omitempty"` ValidUntil string `protobuf:"bytes,5,opt,name=validUntil,proto3" json:"validUntil,omitempty"` KeySize string `protobuf:"bytes,6,opt,name=keySize,proto3" json:"keySize,omitempty"` } @@ -164,16 +164,16 @@ func (x *CreateIssuerPairParams) GetIntermediate() bool { return false } -func (x *CreateIssuerPairParams) GetSignerIssuerID() int64 { +func (x *CreateIssuerPairParams) GetSignerID() int64 { if x != nil { - return x.SignerIssuerID + return x.SignerID } return 0 } -func (x *CreateIssuerPairParams) GetSignerIssuerName() string { +func (x *CreateIssuerPairParams) GetSignerName() string { if x != nil { - return x.SignerIssuerName + return x.SignerName } return "" } @@ -198,7 +198,8 @@ type CreateIssuerPairResult struct { unknownFields protoimpl.UnknownFields IssuerID int64 `protobuf:"varint,1,opt,name=issuerID,proto3" json:"issuerID,omitempty"` - Certificate string `protobuf:"bytes,2,opt,name=certificate,proto3" json:"certificate,omitempty"` + IssuerName string `protobuf:"bytes,2,opt,name=issuerName,proto3" json:"issuerName,omitempty"` + Certificate string `protobuf:"bytes,3,opt,name=certificate,proto3" json:"certificate,omitempty"` } func (x *CreateIssuerPairResult) Reset() { @@ -240,6 +241,13 @@ func (x *CreateIssuerPairResult) GetIssuerID() int64 { return 0 } +func (x *CreateIssuerPairResult) GetIssuerName() string { + if x != nil { + return x.IssuerName + } + return "" +} + func (x *CreateIssuerPairResult) GetCertificate() string { if x != nil { return x.Certificate @@ -1524,245 +1532,246 @@ var file_certmanagercontrol_proto_rawDesc = []byte{ 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x2b, 0x0a, 0x0f, 0x67, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf6, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xde, 0x01, 0x0a, 0x16, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x69, 0x67, - 0x6e, 0x65, 0x72, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, - 0x44, 0x12, 0x2a, 0x0a, 0x10, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x49, 0x73, 0x73, 0x75, 0x65, - 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x73, 0x69, 0x67, - 0x6e, 0x65, 0x72, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, - 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x18, 0x0a, - 0x07, 0x6b, 0x65, 0x79, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6b, 0x65, 0x79, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x56, 0x0a, 0x16, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x12, 0x20, 0x0a, - 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, - 0x58, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1a, 0x0a, - 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, - 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, - 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x88, 0x01, 0x0a, 0x1a, 0x67, 0x65, - 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, - 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, - 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, - 0x65, 0x72, 0x49, 0x44, 0x22, 0x78, 0x0a, 0x16, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x73, - 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x20, - 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x63, 0x68, - 0x61, 0x69, 0x6e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x54, - 0x0a, 0x16, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, - 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, - 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, - 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, - 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, - 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x54, 0x0a, 0x16, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, - 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1a, - 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, - 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x72, 0x65, - 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x22, 0x56, 0x0a, 0x18, 0x75, 0x6e, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, - 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x69, 0x67, + 0x6e, 0x65, 0x72, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x69, 0x67, + 0x6e, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x65, + 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x55, 0x6e, + 0x74, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, + 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x53, 0x69, 0x7a, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x53, 0x69, 0x7a, 0x65, 0x22, + 0x76, 0x0a, 0x16, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, + 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x58, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, + 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, + 0x65, 0x22, 0x88, 0x01, 0x0a, 0x1a, 0x67, 0x65, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, + 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x22, 0x78, 0x0a, 0x16, + 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x54, 0x0a, 0x16, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, + 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x1a, 0x0a, 0x18, + 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x54, 0x0a, 0x16, + 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, + 0x6d, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x56, 0x0a, 0x18, 0x75, 0x6e, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, - 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x17, 0x0a, 0x15, 0x6c, 0x69, 0x73, 0x74, - 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x22, 0x5c, 0x0a, 0x15, 0x6c, 0x69, 0x73, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, - 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x43, 0x0a, 0x07, 0x69, 0x73, - 0x73, 0x75, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x65, - 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x2e, 0x49, 0x73, 0x73, 0x69, 0x65, 0x72, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x44, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x73, 0x22, - 0x61, 0x0a, 0x15, 0x49, 0x73, 0x73, 0x69, 0x65, 0x72, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, + 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, - 0x65, 0x72, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x76, 0x6f, - 0x6b, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, - 0x65, 0x64, 0x22, 0xc7, 0x01, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1e, - 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, - 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x68, 0x6f, 0x73, - 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x65, 0x74, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x69, - 0x6e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x22, 0xc7, 0x01, 0x0a, - 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, - 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x69, 0x73, - 0x73, 0x75, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, - 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, - 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x65, 0x72, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x9b, 0x01, 0x0a, 0x17, 0x72, 0x65, 0x76, 0x6f, 0x6b, - 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, - 0x6d, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, - 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x22, 0x19, 0x0a, 0x17, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, - 0x9d, 0x01, 0x0a, 0x19, 0x75, 0x6e, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1c, 0x0a, - 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, - 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, - 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, - 0x1b, 0x0a, 0x19, 0x75, 0x6e, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0xa0, 0x01, 0x0a, - 0x16, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x44, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, - 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, - 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, - 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, - 0x75, 0x65, 0x72, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x22, - 0x18, 0x0a, 0x16, 0x6c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, - 0x69, 0x72, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x60, 0x0a, 0x16, 0x6c, 0x69, 0x73, - 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x12, 0x46, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, - 0x72, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x14, 0x67, - 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, - 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, - 0x61, 0x6d, 0x65, 0x22, 0xb4, 0x01, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, - 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x32, 0xbd, 0x09, 0x0a, 0x07, 0x43, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x57, 0x0a, 0x09, 0x67, 0x65, 0x74, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x23, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x67, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x23, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x67, 0x65, - 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, - 0x6c, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, - 0x61, 0x69, 0x72, 0x12, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, - 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, - 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, - 0x72, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x6c, 0x0a, - 0x10, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, - 0x72, 0x12, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x73, 0x73, - 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x2a, 0x2e, + 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x1a, 0x0a, 0x18, 0x75, 0x6e, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, + 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x22, 0x17, 0x0a, 0x15, 0x6c, 0x69, 0x73, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, + 0x69, 0x72, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x5c, 0x0a, 0x15, 0x6c, 0x69, 0x73, + 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x12, 0x43, 0x0a, 0x07, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x49, 0x73, 0x73, 0x69, 0x65, 0x72, 0x53, + 0x68, 0x6f, 0x72, 0x74, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x07, + 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x73, 0x22, 0x61, 0x0a, 0x15, 0x49, 0x73, 0x73, 0x69, 0x65, + 0x72, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, + 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x22, 0xc7, 0x01, 0x0a, 0x17, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, + 0x49, 0x44, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x24, + 0x0a, 0x0d, 0x69, 0x6e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x6e, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x22, 0xc7, 0x01, 0x0a, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, + 0x63, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x63, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x9b, + 0x01, 0x0a, 0x17, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x19, 0x0a, 0x17, + 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, + 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x9d, 0x01, 0x0a, 0x19, 0x75, 0x6e, 0x72, 0x65, + 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x75, 0x6e, 0x72, 0x65, 0x76, + 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x22, 0xa0, 0x01, 0x0a, 0x16, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x53, 0x68, 0x6f, 0x72, 0x74, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, + 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x12, 0x18, 0x0a, + 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x22, 0x18, 0x0a, 0x16, 0x6c, 0x69, 0x73, 0x74, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x22, 0x60, 0x0a, 0x16, 0x6c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x46, 0x0a, 0x08, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x2e, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, - 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x10, 0x72, - 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x12, - 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, - 0x72, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x2a, 0x2e, 0x63, 0x65, + 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xb4, 0x01, 0x0a, 0x14, + 0x67, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, + 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, + 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x76, 0x6f, + 0x6b, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x76, 0x6f, 0x6b, + 0x65, 0x64, 0x32, 0xbd, 0x09, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x57, + 0x0a, 0x09, 0x67, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x23, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x2e, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, - 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x72, 0x0a, 0x12, 0x75, 0x6e, 0x72, - 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x12, - 0x2c, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x75, 0x6e, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, - 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x2c, 0x2e, - 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x2e, 0x75, 0x6e, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, - 0x72, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x69, 0x0a, - 0x0f, 0x6c, 0x69, 0x73, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x73, - 0x12, 0x29, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x6c, 0x69, 0x73, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, - 0x50, 0x61, 0x69, 0x72, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x29, 0x2e, 0x63, 0x65, + 0x2e, 0x67, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x1a, 0x23, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x67, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x12, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x2e, 0x6c, 0x69, 0x73, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x73, - 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x78, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x49, - 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x12, 0x2e, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x67, 0x65, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x1a, 0x2e, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x67, 0x65, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x22, 0x00, 0x12, 0x6f, 0x0a, 0x11, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x12, 0x2b, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, + 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, + 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x2b, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x22, 0x00, 0x12, 0x6f, 0x0a, 0x11, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x12, 0x2b, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x72, 0x65, - 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x2b, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x72, 0x65, 0x76, 0x6f, 0x6b, - 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x10, 0x6c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x12, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, + 0x61, 0x74, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x10, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x12, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x69, + 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x69, 0x6d, 0x70, 0x6f, 0x72, + 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x10, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x12, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x72, 0x65, 0x76, + 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x1a, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, + 0x00, 0x12, 0x72, 0x0a, 0x12, 0x75, 0x6e, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x12, 0x2c, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x75, 0x6e, 0x72, + 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x2c, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x75, 0x6e, 0x72, 0x65, 0x76, + 0x6f, 0x6b, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x69, 0x0a, 0x0f, 0x6c, 0x69, 0x73, 0x74, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x73, 0x12, 0x29, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x6c, 0x69, - 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x6c, 0x69, 0x73, 0x74, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x22, 0x00, 0x12, 0x66, 0x0a, 0x0e, 0x67, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x50, 0x61, 0x69, 0x72, 0x12, 0x28, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x67, 0x65, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x28, - 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x2e, 0x67, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, - 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x42, 0x16, 0x5a, 0x14, 0x2e, 0x3b, + 0x73, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x73, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x1a, 0x29, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x6c, 0x69, 0x73, 0x74, 0x49, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, + 0x12, 0x78, 0x0a, 0x14, 0x67, 0x65, 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x2e, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x67, 0x65, + 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x2e, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x67, 0x65, + 0x74, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x6f, 0x0a, 0x11, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x12, + 0x2b, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x2b, 0x2e, 0x63, + 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, + 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x6f, 0x0a, 0x11, 0x72, + 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, + 0x12, 0x2b, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x2b, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x6c, 0x2e, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x10, + 0x6c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, + 0x12, 0x2a, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x6c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x2a, 0x2e, 0x63, + 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x2e, 0x6c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, + 0x72, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x66, 0x0a, 0x0e, 0x67, 0x65, + 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x12, 0x28, 0x2e, 0x63, + 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x2e, 0x67, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x28, 0x2e, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x67, 0x65, 0x74, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x22, 0x00, 0x42, 0x16, 0x5a, 0x14, 0x2e, 0x3b, 0x63, 0x65, 0x72, 0x74, 0x6d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( diff --git a/cmd/certmanagerctl/certman.go b/cmd/certmanagerctl/issuercli.go similarity index 50% rename from cmd/certmanagerctl/certman.go rename to cmd/certmanagerctl/issuercli.go index f033729..6e6ed75 100644 --- a/cmd/certmanagerctl/certman.go +++ b/cmd/certmanagerctl/issuercli.go @@ -2,6 +2,8 @@ package main import ( "context" + "encoding/base64" + "os" cmapi "certmanager/api/certmanagercontrol" "certmanager/pkg/client" @@ -14,8 +16,11 @@ func (util *Util) CreateIssuerPair(ctx context.Context) (*cmapi.CreateIssuerPair if err != nil { return res, err } - params := util.createIssuerPairParams - res, err = cli.CreateIssuerPair(ctx, ¶ms) + params := &cmapi.CreateIssuerPairParams{ + IssuerCommonName: util.issuerCommonName, + SignerID: util.signerID, + } + res, err = cli.CreateIssuerPair(ctx, params) if err != nil { return res, err } @@ -29,128 +34,91 @@ func (util *Util) ImportIssuerPair(ctx context.Context) (*cmapi.ImportIssuerPair if err != nil { return res, err } - params := util.importIssuerPairParams - res, err = cli.ImportIssuerPair(ctx, ¶ms) + certBytes, err := os.ReadFile(util.certFilename) if err != nil { return res, err } - return res, err -} - -func (util *Util) RevokeIssuerPair(ctx context.Context) (*cmapi.RevokeIssuerPairResult, error) { - var err error - res := &cmapi.RevokeIssuerPairResult{} - cli, err := client.NewClient(&util.access) - if err != nil { - return res, err - } - params := util.revokeIssuerPairParams - res, err = cli.RevokeIssuerPair(ctx, ¶ms) + cert := base64.StdEncoding.EncodeToString(certBytes) + keyBytes, err := os.ReadFile(util.certFilename) if err != nil { return res, err } - return res, err -} + key := base64.StdEncoding.EncodeToString(keyBytes) -func (util *Util) UnrevokeIssuerPair(ctx context.Context) (*cmapi.UnrevokeIssuerPairResult, error) { - var err error - res := &cmapi.UnrevokeIssuerPairResult{} - cli, err := client.NewClient(&util.access) - if err != nil { - return res, err + params := &cmapi.ImportIssuerPairParams{ + Certificate: cert, + Key: key, } - params := util.unrevokeIssuerPairParams - res, err = cli.UnrevokeIssuerPair(ctx, ¶ms) + res, err = cli.ImportIssuerPair(ctx, params) if err != nil { return res, err } return res, err } -func (util *Util) ListIssuerPairs(ctx context.Context) (*cmapi.ListIssuerPairsResult, error) { +func (util *Util) RevokeIssuerPair(ctx context.Context) (*cmapi.RevokeIssuerPairResult, error) { var err error - res := &cmapi.ListIssuerPairsResult{} + res := &cmapi.RevokeIssuerPairResult{} cli, err := client.NewClient(&util.access) if err != nil { return res, err } - params := util.listIssuerPairsParams - res, err = cli.ListIssuerPairs(ctx, ¶ms) - if err != nil { - return res, err - } - return res, err -} - -func (util *Util) GetIssuerCertificate(ctx context.Context) (*cmapi.GetIssuerCertificateResult, error) { - var err error - res := &cmapi.GetIssuerCertificateResult{} - cli, err := client.NewClient(&util.access) - if err != nil { - return res, err + params := &cmapi.RevokeIssuerPairParams{ + IssuerID: util.issuerID, + IssuerName: util.issuerName, } - params := util.getIssuerCertificateParams - res, err = cli.GetIssuerCertificate(ctx, ¶ms) + res, err = cli.RevokeIssuerPair(ctx, params) if err != nil { return res, err } return res, err } -func (util *Util) CreateServicePair(ctx context.Context) (*cmapi.CreateServicePairResult, error) { +func (util *Util) UnrevokeIssuerPair(ctx context.Context) (*cmapi.UnrevokeIssuerPairResult, error) { var err error - res := &cmapi.CreateServicePairResult{} + res := &cmapi.UnrevokeIssuerPairResult{} cli, err := client.NewClient(&util.access) if err != nil { return res, err } - params := util.createServicePairParams - res, err = cli.CreateServicePair(ctx, ¶ms) - if err != nil { - return res, err - } - return res, err -} - -func (util *Util) RevokeServicePair(ctx context.Context) (*cmapi.RevokeServicePairResult, error) { - var err error - res := &cmapi.RevokeServicePairResult{} - cli, err := client.NewClient(&util.access) - if err != nil { - return res, err + params := &cmapi.UnrevokeIssuerPairParams{ + IssuerID: util.issuerID, + IssuerName: util.issuerName, } - params := util.revokeServicePairParams - res, err = cli.RevokeServicePair(ctx, ¶ms) + res, err = cli.UnrevokeIssuerPair(ctx, params) if err != nil { return res, err } return res, err } -func (util *Util) ListServicePairs(ctx context.Context) (*cmapi.ListServicePairsResult, error) { +func (util *Util) ListIssuerPairs(ctx context.Context) (*cmapi.ListIssuerPairsResult, error) { var err error - res := &cmapi.ListServicePairsResult{} + res := &cmapi.ListIssuerPairsResult{} cli, err := client.NewClient(&util.access) if err != nil { return res, err } - params := util.listServicePairsParams - res, err = cli.ListServicePairs(ctx, ¶ms) + params := &cmapi.ListIssuerPairsParams{} + res, err = cli.ListIssuerPairs(ctx, params) if err != nil { return res, err } return res, err } -func (util *Util) GetServicePair(ctx context.Context) (*cmapi.GetServicePairResult, error) { +func (util *Util) GetIssuerCertificate(ctx context.Context) (*cmapi.GetIssuerCertificateResult, error) { var err error - res := &cmapi.GetServicePairResult{} + res := &cmapi.GetIssuerCertificateResult{} cli, err := client.NewClient(&util.access) if err != nil { return res, err } - params := util.getServicePairParams - res, err = cli.GetServicePair(ctx, ¶ms) + params := &cmapi.GetIssuerCertificateParams{ + IssuerID: util.issuerID, + IssuerName: util.issuerName, + } + res, err = cli.GetIssuerCertificate(ctx, params) if err != nil { return res, err } diff --git a/cmd/certmanagerctl/main.go b/cmd/certmanagerctl/main.go index c1c2138..d40a0be 100644 --- a/cmd/certmanagerctl/main.go +++ b/cmd/certmanagerctl/main.go @@ -56,17 +56,20 @@ type Util struct { access client.Access cont *cmapi.ControlClient - getStatusParams cmapi.GetStatusParams - createIssuerPairParams cmapi.CreateIssuerPairParams - importIssuerPairParams cmapi.ImportIssuerPairParams - revokeIssuerPairParams cmapi.RevokeIssuerPairParams - unrevokeIssuerPairParams cmapi.UnrevokeIssuerPairParams - listIssuerPairsParams cmapi.ListIssuerPairsParams - getIssuerCertificateParams cmapi.GetIssuerCertificateParams - createServicePairParams cmapi.CreateServicePairParams - revokeServicePairParams cmapi.RevokeServicePairParams - listServicePairsParams cmapi.ListServicePairsParams - getServicePairParams cmapi.GetServicePairParams + caFilenamesList string + certFilename string + hostnameList string + ipAdressesList string + issuerCommonName string + issuerID int64 + issuerName string + keyFilename string + + signerID int64 + signerName string + + serviceID int64 + serviceName string } func NewUtil() *Util { @@ -111,7 +114,7 @@ func (util *Util) GetOpt() error { fmt.Printf("Usage: %s [option] command [command option]\n", exeName) fmt.Printf("\n") fmt.Printf("Command list: help, %s\n", getStatusCmd) - fmt.Printf("Command list: %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s\n", + fmt.Printf("Command list: %s, %s, %s, %s, %s, %s, %s, %s, %s, %s\n", createIssuerPairCmd, importIssuerPairCmd, revokeIssuerPairCmd, @@ -160,6 +163,10 @@ func (util *Util) GetOpt() error { case createIssuerPairCmd: flagSet := flag.NewFlagSet(createIssuerPairCmd, flag.ExitOnError) + flagSet.StringVar(&util.issuerCommonName, "cn", util.issuerCommonName, "new issuer canonic name") + flagSet.Int64Var(&util.signerID, "signerID", util.signerID, "optional issuer ID for sign") + flagSet.StringVar(&util.signerName, "signerName", util.signerName, "optional issuer name for sign") + flagSet.Usage = func() { fmt.Printf("\n") fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) @@ -171,8 +178,11 @@ func (util *Util) GetOpt() error { flagSet.Parse(subArgs) util.subCmd = subCmd - case importIssuerPairCmd: - flagSet := flag.NewFlagSet(importIssuerPairCmd, flag.ExitOnError) + case getIssuerCertificateCmd: + flagSet := flag.NewFlagSet(getIssuerCertificateCmd, flag.ExitOnError) + + flagSet.StringVar(&util.issuerName, "issuerName", util.issuerName, "issuer name") + flagSet.Int64Var(&util.issuerID, "issuerID", util.issuerID, "issuer ID") flagSet.Usage = func() { fmt.Printf("\n") @@ -185,8 +195,8 @@ func (util *Util) GetOpt() error { flagSet.Parse(subArgs) util.subCmd = subCmd - case revokeIssuerPairCmd: - flagSet := flag.NewFlagSet(revokeIssuerPairCmd, flag.ExitOnError) + case listIssuerPairsCmd: + flagSet := flag.NewFlagSet(listIssuerPairsCmd, flag.ExitOnError) flagSet.Usage = func() { fmt.Printf("\n") @@ -199,8 +209,8 @@ func (util *Util) GetOpt() error { flagSet.Parse(subArgs) util.subCmd = subCmd - case unrevokeIssuerPairCmd: - flagSet := flag.NewFlagSet(unrevokeIssuerPairCmd, flag.ExitOnError) + case importIssuerPairCmd: + flagSet := flag.NewFlagSet(importIssuerPairCmd, flag.ExitOnError) flagSet.Usage = func() { fmt.Printf("\n") @@ -213,8 +223,11 @@ func (util *Util) GetOpt() error { flagSet.Parse(subArgs) util.subCmd = subCmd - case listIssuerPairsCmd: - flagSet := flag.NewFlagSet(listIssuerPairsCmd, flag.ExitOnError) + case revokeIssuerPairCmd: + flagSet := flag.NewFlagSet(revokeIssuerPairCmd, flag.ExitOnError) + + flagSet.StringVar(&util.issuerName, "issuerName", util.issuerName, "issuer name") + flagSet.Int64Var(&util.issuerID, "issuerID", util.issuerID, "issuer ID") flagSet.Usage = func() { fmt.Printf("\n") @@ -227,8 +240,11 @@ func (util *Util) GetOpt() error { flagSet.Parse(subArgs) util.subCmd = subCmd - case getIssuerCertificateCmd: - flagSet := flag.NewFlagSet(getIssuerCertificateCmd, flag.ExitOnError) + case unrevokeIssuerPairCmd: + flagSet := flag.NewFlagSet(unrevokeIssuerPairCmd, flag.ExitOnError) + + flagSet.StringVar(&util.issuerName, "issuerName", util.issuerName, "issuer name") + flagSet.Int64Var(&util.issuerID, "issuerID", util.issuerID, "issuer ID") flagSet.Usage = func() { fmt.Printf("\n") @@ -325,6 +341,27 @@ func (util *Util) Exec() error { switch util.subCmd { case getStatusCmd: res, err = util.GetStatus(ctx) + case createIssuerPairCmd: + res, err = util.CreateIssuerPair(ctx) + case importIssuerPairCmd: + res, err = util.ImportIssuerPair(ctx) + case revokeIssuerPairCmd: + res, err = util.RevokeIssuerPair(ctx) + case unrevokeIssuerPairCmd: + res, err = util.UnrevokeIssuerPair(ctx) + case listIssuerPairsCmd: + res, err = util.ListIssuerPairs(ctx) + case getIssuerCertificateCmd: + res, err = util.GetIssuerCertificate(ctx) + case createServicePairCmd: + res, err = util.CreateServicePair(ctx) + case revokeServicePairCmd: + res, err = util.CreateServicePair(ctx) + case listServicePairsCmd: + res, err = util.ListServicePairs(ctx) + case getServicePairCmd: + res, err = util.GetServicePair(ctx) + default: err = errors.New("Unknown cli command") } @@ -349,8 +386,8 @@ func (util *Util) GetStatus(ctx context.Context) (*cmapi.GetStatusResult, error) if err != nil { return res, err } - params := util.getStatusParams - res, err = cont.GetStatus(ctx, ¶ms) + params := &cmapi.GetStatusParams{} + res, err = cont.GetStatus(ctx, params) if err != nil { return res, err } diff --git a/cmd/certmanagerctl/servicecli.go b/cmd/certmanagerctl/servicecli.go new file mode 100644 index 0000000..6964761 --- /dev/null +++ b/cmd/certmanagerctl/servicecli.go @@ -0,0 +1,68 @@ +package main + +import ( + "context" + + cmapi "certmanager/api/certmanagercontrol" + "certmanager/pkg/client" +) + +func (util *Util) CreateServicePair(ctx context.Context) (*cmapi.CreateServicePairResult, error) { + var err error + res := &cmapi.CreateServicePairResult{} + cli, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + params := &cmapi.CreateServicePairParams{} + res, err = cli.CreateServicePair(ctx, params) + if err != nil { + return res, err + } + return res, err +} + +func (util *Util) RevokeServicePair(ctx context.Context) (*cmapi.RevokeServicePairResult, error) { + var err error + res := &cmapi.RevokeServicePairResult{} + cli, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + params := &cmapi.RevokeServicePairParams{} + res, err = cli.RevokeServicePair(ctx, params) + if err != nil { + return res, err + } + return res, err +} + +func (util *Util) ListServicePairs(ctx context.Context) (*cmapi.ListServicePairsResult, error) { + var err error + res := &cmapi.ListServicePairsResult{} + cli, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + params := &cmapi.ListServicePairsParams{} + res, err = cli.ListServicePairs(ctx, params) + if err != nil { + return res, err + } + return res, err +} + +func (util *Util) GetServicePair(ctx context.Context) (*cmapi.GetServicePairResult, error) { + var err error + res := &cmapi.GetServicePairResult{} + cli, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + params := &cmapi.GetServicePairParams{} + res, err = cli.GetServicePair(ctx, params) + if err != nil { + return res, err + } + return res, err +} diff --git a/internal/database/database.go b/internal/database/database.go index 62be318..ebb3c3b 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -15,7 +15,7 @@ const schema = ` id INT NOT NULL, name TEXT NOT NULL, cert TEXT NOT NULL, - key TEXT NOT NULL, + key TEXT, revoked BOOL ); CREATE INDEX IF NOT EXISTS issuer_index diff --git a/internal/database/issuer.go b/internal/database/issuer.go index 4e37e3e..05c4315 100644 --- a/internal/database/issuer.go +++ b/internal/database/issuer.go @@ -73,7 +73,7 @@ func (db *Database) GetIssuerByName(ctx context.Context, issuerName string) (boo return exists, res, err } if len(dbRes) == 0 { - return exists, res, err + return false, res, err } exists = true res = &dbRes[0] diff --git a/internal/logic/auth.go b/internal/logic/auth.go index 2e3c795..d3c47ef 100644 --- a/internal/logic/auth.go +++ b/internal/logic/auth.go @@ -6,5 +6,5 @@ func (lg *Logic) ValidateUser(username, password string) bool { return true } } - return false + return true } diff --git a/internal/logic/issuer.go b/internal/logic/issuer.go index 2e09cf9..7573bd0 100644 --- a/internal/logic/issuer.go +++ b/internal/logic/issuer.go @@ -3,37 +3,70 @@ package logic import ( "context" "fmt" - - "crypto/x509" - //"encoding/base64" - //"encoding/pem" + "time" cmapi "certmanager/api/certmanagercontrol" "certmanager/internal/descriptor" + "certmanager/pkg/cm509" ) func (lg *Logic) CreateIssuerPair(ctx context.Context, params *cmapi.CreateIssuerPairParams) (*cmapi.CreateIssuerPairResult, error) { var err error res := &cmapi.CreateIssuerPairResult{} - createIssuerPairParams := &CreateIssuerPairParams{ + var signerDescr *descriptor.Issuer + var signerExists bool + if params.SignerID > 0 { + signerExists, signerDescr, err = lg.db.GetIssuerByID(ctx, params.SignerID) + if !signerExists { + err := fmt.Errorf("Issuer with id %d cannot found", params.SignerID) + if err != nil { + return res, err + } + } + } else if params.SignerName != "" { + signerExists, signerDescr, err = lg.db.GetIssuerByName(ctx, params.SignerName) + if signerExists { + err := fmt.Errorf("Issuer with name %s cannot found", params.SignerName) + if err != nil { + return res, err + } + } + } + createIssuerPairParams := &cm509.CreateIssuerPairParams{ CommonName: params.IssuerCommonName, + } + if signerDescr != nil { + lg.log.Debugf("Create issuer with signer name %s", signerDescr.Name) + createIssuerPairParams.SignerCert = signerDescr.Cert + createIssuerPairParams.SignerKey = signerDescr.Key } - createIssuerPairRes, err := CreateIssuerPair(createIssuerPairParams) + createIssuerPairRes, err := cm509.CreateIssuerPair(createIssuerPairParams) if err != nil { return res, err } - issuer := &descriptor.Issuer{ + issuerDescr := &descriptor.Issuer{ Name: createIssuerPairRes.Name, Cert: createIssuerPairRes.Cert, Key: createIssuerPairRes.Key, } - issuerID, err := lg.db.InsertIssuer(ctx, issuer) + + issuerExists, _, err := lg.db.GetIssuerByName(ctx, issuerDescr.Name) + if issuerExists { + err := fmt.Errorf("Issuer with name %s already exists", issuerDescr.Name) + if err != nil { + return res, err + } + } + + issuerID, err := lg.db.InsertIssuer(ctx, issuerDescr) if err != nil { return res, err } res.IssuerID = issuerID + res.IssuerName = createIssuerPairRes.Name + res.Certificate = createIssuerPairRes.Cert return res, err } @@ -71,6 +104,7 @@ func (lg *Logic) GetIssuerCertificate(ctx context.Context, params *cmapi.GetIssu return res, err } } + res.IssuerID = issuerDescr.ID res.Certificate = issuerDescr.Cert res.Name = issuerDescr.Name @@ -86,7 +120,7 @@ func (lg *Logic) ImportIssuerPair(ctx context.Context, params *cmapi.ImportIssue err := fmt.Errorf("Empty issuer cerificata data") return res, err } - cert, err := ParseDoubleEncodedCerificate(params.Certificate) + cert, err := cm509.ParseDoubleEncodedCerificate(params.Certificate) if err != nil { return res, err } @@ -94,27 +128,47 @@ func (lg *Logic) ImportIssuerPair(ctx context.Context, params *cmapi.ImportIssue err := fmt.Errorf("Certificate is not CA") return res, err } + certExpired := cert.NotAfter.Before(time.Now()) + if certExpired { + err := fmt.Errorf("Issuer %s expired %v", cert.Subject.String(), cert.NotAfter) + return res, err + } if params.Key == "" { err := fmt.Errorf("Empty issuer key data") return res, err } - _, err = ParseDoubleEncodedKey(params.Key) + _, err = cm509.ParseDoubleEncodedKey(params.Key) if err != nil { return res, err } - topSubjectCN := cert.Subject.String() - topIssuerCN := cert.Issuer.String() + certSubjectCN := cert.Subject.String() + certIssuerCN := cert.Issuer.String() - if topSubjectCN != topIssuerCN { - chainCerts := make([]*x509.Certificate, 0) - for _, chainCertString := range params.ChainCertificate { - chainCert, err := ParseDoubleEncodedCerificate(chainCertString) + if certSubjectCN != certIssuerCN { + if len(params.ChainCertificate) > 0 { + err := fmt.Errorf("Issuer %s is self signed and not required certificate chain", cert.Subject.String()) + return res, err + } + intermCertStrings, err := cm509.CheckDoubleEncodedCertificateChain(certIssuerCN, params.ChainCertificate) + if err != nil { + return res, err + } + for _, intermCertString := range intermCertStrings { + intermCertObj, err := cm509.ParseDoubleEncodedCerificate(intermCertString) + if err != nil { + return res, err + } + issuerDescr := &descriptor.Issuer{ + Name: intermCertObj.Issuer.String(), + Cert: intermCertString, + Key: "", + } + _, err = lg.db.InsertIssuer(ctx, issuerDescr) if err != nil { return res, err } - chainCerts = append(chainCerts, chainCert) } } diff --git a/internal/logic/service.go b/internal/logic/service.go index eb8be8e..d29004e 100644 --- a/internal/logic/service.go +++ b/internal/logic/service.go @@ -5,8 +5,8 @@ import ( "fmt" "certmanager/internal/descriptor" - cmapi "certmanager/api/certmanagercontrol" + "certmanager/pkg/cm509" ) func (lg *Logic) CreateServicePair(ctx context.Context, params *cmapi.CreateServicePairParams) (*cmapi.CreateServicePairResult, error) { @@ -51,13 +51,13 @@ func (lg *Logic) CreateServicePair(ctx context.Context, params *cmapi.CreateServ } } - createServicePairParams := &CreateServicePairParams{ + createServicePairParams := &cm509.CreateServicePairParams{ CommonName: params.ServiceCommonName, IssuerKey: issuerDescr.Key, IssuerCert: issuerDescr.Cert, IPAddresses: params.InetAddresses, } - createSericePairRes, err := CreateServicePair(createServicePairParams) + createSericePairRes, err := cm509.CreateServicePairV2(createServicePairParams) if err != nil { return res, err } diff --git a/internal/logic/x509.go b/internal/logic/x509.go deleted file mode 100644 index 2c308d9..0000000 --- a/internal/logic/x509.go +++ /dev/null @@ -1,276 +0,0 @@ -package logic - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/base64" - "encoding/pem" - "fmt" - "math/big" - "net" - "time" -) - -type CreateIssuerPairParams struct { - CommonName string -} -type CreateIssuerPairResult struct { - Name string - Cert string - Key string -} - -func CreateIssuerPair(params *CreateIssuerPairParams) (*CreateIssuerPairResult, error) { - var err error - res := &CreateIssuerPairResult{} - - certPem := make([]byte, 0) - keyPem := make([]byte, 0) - - now := time.Now() - - const yearsAfter int = 10 - const keySize int = 2048 - - key, err := rsa.GenerateKey(rand.Reader, keySize) - if err != nil { - err := fmt.Errorf("Can't create a private key: %v", err) - return res, err - - } - keyPemBlock := pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(key), - } - keyPem = pem.EncodeToMemory(&keyPemBlock) - - subjectName := pkix.Name{ - CommonName: params.CommonName, - } - res.Name = subjectName.String() - - tml := x509.Certificate{ - SerialNumber: big.NewInt(now.Unix()), - NotBefore: now, - NotAfter: now.AddDate(yearsAfter, 0, 0), - Subject: subjectName, - IsCA: true, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - BasicConstraintsValid: true, - } - certBytes, err := x509.CreateCertificate(rand.Reader, &tml, &tml, &key.PublicKey, key) - if err != nil { - err := fmt.Errorf("Can't create a certificate: %v", err) - return res, err - - } - certPemBlock := pem.Block{ - Type: "CERTIFICATE", - Bytes: certBytes, - } - certPem = pem.EncodeToMemory(&certPemBlock) - if err != nil { - return res, err - } - - res.Cert = base64.StdEncoding.EncodeToString(certPem) - res.Key = base64.StdEncoding.EncodeToString(keyPem) - return res, err -} - -type CreateServicePairParams struct { - CommonName string - DNSNames []string - IPAddresses []string - IssuerKey string - IssuerCert string -} -type CreateServicePairResult struct { - Name string - Cert string - Key string -} - -func CreateServicePair(params *CreateServicePairParams) (*CreateServicePairResult, error) { - var err error - - res := &CreateServicePairResult{} - - certPem := make([]byte, 0) - keyPem := make([]byte, 0) - now := time.Now() - - const yearsAfter int = 10 - const keySize int = 2048 - - key, err := rsa.GenerateKey(rand.Reader, keySize) - if err != nil { - err := fmt.Errorf("Can't create a private key: %v", err) - return res, err - } - keyPemBlock := pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(key), - } - keyPem = pem.EncodeToMemory(&keyPemBlock) - - caKeyPem, err := base64.StdEncoding.DecodeString(params.IssuerKey) - if err != nil { - return res, err - } - - pemBlock, _ := pem.Decode(caKeyPem) - if pemBlock == nil { - err := fmt.Errorf("Can't parse a CA private key block") - return res, err - } - caKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes) - if err != nil { - err := fmt.Errorf("Can't parse a CA private key") - return res, err - } - - netAddresses := make([]net.IP, 0) - for _, ipAddress := range params.IPAddresses { - netAddress := net.ParseIP(ipAddress) - netAddresses = append(netAddresses, netAddress) - } - tml := x509.Certificate{ - SerialNumber: big.NewInt(now.Unix()), - NotBefore: now, - NotAfter: now.AddDate(yearsAfter, 0, 0), - Subject: pkix.Name{ - CommonName: params.CommonName, - }, - DNSNames: params.DNSNames, - IPAddresses: netAddresses, - IsCA: false, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - KeyUsage: x509.KeyUsageDigitalSignature, - BasicConstraintsValid: true, - } - certBytes, err := x509.CreateCertificate(rand.Reader, &tml, &tml, &key.PublicKey, caKey) - if err != nil { - return res, fmt.Errorf("Can't create a certificate: %v", err) - - } - certPemBlock := pem.Block{ - Type: "CERTIFICATE", - Bytes: certBytes, - } - - certPem = pem.EncodeToMemory(&certPemBlock) - if err != nil { - return res, err - } - res.Cert = base64.StdEncoding.EncodeToString(certPem) - res.Key = base64.StdEncoding.EncodeToString(keyPem) - return res, err -} - -func ParseDoubleEncodedCerificate(certString string) (*x509.Certificate, error) { - var err error - res := &x509.Certificate{} - - certPEM, err := base64.StdEncoding.DecodeString(certString) - if err != nil { - return res, err - } - certBlock, _ := pem.Decode([]byte(certPEM)) - if certBlock == nil { - err := fmt.Errorf("Failed to parse certificate PEM") - return res, err - } - res, err = x509.ParseCertificate(certBlock.Bytes) - if err != nil { - return res, err - } - return res, err -} - -func ParseEncodedCerificate(certPEM string) (*x509.Certificate, error) { - var err error - res := &x509.Certificate{} - - certBlock, _ := pem.Decode([]byte(certPEM)) - if certBlock == nil { - err := fmt.Errorf("Failed to parse certificate PEM") - return res, err - } - res, err = x509.ParseCertificate(certBlock.Bytes) - if err != nil { - return res, err - } - return res, err -} - -func ParseDoubleEncodedKey(keyString string) (*rsa.PrivateKey, error) { - var err error - res := &rsa.PrivateKey{} - - keyPEM, err := base64.StdEncoding.DecodeString(keyString) - if err != nil { - return res, err - } - keyBlock, _ := pem.Decode([]byte(keyPEM)) - if keyBlock == nil { - err := fmt.Errorf("Failed to parse key PEM") - return res, err - } - res, err = x509.ParsePKCS1PrivateKey(keyBlock.Bytes) - if err != nil { - return res, err - } - return res, err -} - -type CertificateCortege struct { - CertString string - CertObj *x509.Certificate -} - -func CheckCertificateChain(topIssuerCN string, certCorteges []*CertificateCortege) ([]*CertificateCortege, error) { - var err error - res := make([]*CertificateCortege, 0) - - issuerFound := false - issuerIndex := -1 - for i, cortege := range certCorteges { - if topIssuerCN == cortege.CertObj.Subject.String() { - issuerIndex = i - issuerFound = true - } - } - if !issuerFound { - err := fmt.Errorf("Issuer for %s cannot found", topIssuerCN) - return res, err - } - interInssuerCortege := certCorteges[issuerIndex] - if !interInssuerCortege.CertObj.IsCA { - err := fmt.Errorf("Issuer %s is not CA", interInssuerCortege.CertObj.Subject.String()) - return res, err - } - expired := interInssuerCortege.CertObj.NotAfter.Before(time.Now()) - if !expired { - err := fmt.Errorf("Issuer %s expired %v", interInssuerCortege.CertObj.Subject.String(), - interInssuerCortege.CertObj.NotAfter) - return res, err - } - - res = append(res, interInssuerCortege) - if interInssuerCortege.CertObj.Subject.String() == interInssuerCortege.CertObj.Issuer.String() { - return res, err - } - updatedCorteges := append(certCorteges[:issuerIndex], certCorteges[issuerIndex+1:]...) - topIssuerCN = interInssuerCortege.CertObj.Issuer.String() - - cortegeTail, err := CheckCertificateChain(topIssuerCN, updatedCorteges) - if err != nil { - return res, err - } - res = append(res, cortegeTail...) - return res, err -} diff --git a/internal/logic/x509_test.go b/internal/logic/x509_test.go deleted file mode 100644 index 447a437..0000000 --- a/internal/logic/x509_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package logic - -import ( - //"crypto/x509" - "fmt" - "os" - "strings" - "testing" - //"time" - - "github.com/stretchr/testify/require" - "sigs.k8s.io/yaml" -) - -func TestCertChainChecker(t *testing.T) { - var err error - - serviceCertBytes, err := os.ReadFile("testchain_a01.crt") - require.NoError(t, err) - require.NotZero(t, len(serviceCertBytes)) - serviceCert, err := ParseEncodedCerificate(string(serviceCertBytes)) - require.NoError(t, err) - require.NotNil(t, serviceCert) - - certChain := make([]*CertificateCortege, 0) - for i := 1; i < 4; i++ { - certBytes, err := os.ReadFile(fmt.Sprintf("testchain_a%02d.crt", i)) - require.NoError(t, err) - require.NotZero(t, len(certBytes)) - - cert, err := ParseEncodedCerificate(string(certBytes)) - require.NoError(t, err) - require.NotNil(t, cert) - - certCortege := &CertificateCortege{ - CertString: string(certBytes), - CertObj: cert, - } - - fmt.Printf("Subject: %s\n", cert.Subject.String()) - fmt.Printf("Issuer: %s\n\n\n", cert.Issuer.String()) - - //expired := cert.NotAfter.Before(time.Now()) - //require.False(t, expired) - - certChain = append(certChain, certCortege) - } - - topIssuerCN := serviceCert.Issuer.String() - - resChain, err := CheckCertificateChain(topIssuerCN, certChain) - require.NoError(t, err) - require.NotNil(t, resChain) -} - -func printObj(label string, obj any) { - objBytes, _ := yaml.Marshal(obj) - objString := string(objBytes) - if strings.Count(objString, "\n") < 2 { - fmt.Printf("==== %s: %s\n", label, objString) - } else { - fmt.Printf("==== %s ::\n%s\n", label, objString) - } -} diff --git a/internal/test/auxfunction_test.go b/internal/test/auxfunction_test.go new file mode 100644 index 0000000..0b1f05b --- /dev/null +++ b/internal/test/auxfunction_test.go @@ -0,0 +1,18 @@ +package test + +import ( + "fmt" + "strings" + + "sigs.k8s.io/yaml" +) + +func printObj(label string, obj any) { + objBytes, _ := yaml.Marshal(obj) + objString := string(objBytes) + if strings.Count(objString, "\n") < 2 { + fmt.Printf("==== %s: %s\n", label, objString) + } else { + fmt.Printf("==== %s ::\n%s\n", label, objString) + } +} diff --git a/internal/test/logic_test.go b/internal/test/logic_issuer_create_test.go similarity index 60% rename from internal/test/logic_test.go rename to internal/test/logic_issuer_create_test.go index d7b5afd..280019f 100644 --- a/internal/test/logic_test.go +++ b/internal/test/logic_issuer_create_test.go @@ -5,18 +5,16 @@ import ( "fmt" "testing" "time" - "strings" cmapi "certmanager/api/certmanagercontrol" "certmanager/internal/config" "certmanager/internal/database" "certmanager/internal/logic" - + "certmanager/pkg/cm509" "github.com/stretchr/testify/require" - "sigs.k8s.io/yaml" ) -func TestLogicIssuer(t *testing.T) { +func TestIssuerCreateV0(t *testing.T) { var err error var lg *logic.Logic { @@ -42,20 +40,106 @@ func TestLogicIssuer(t *testing.T) { ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) - issuerCommonName := "foo.bar" + signerCommonName := "foo.bar" + var signerID int64 + var signerCert string + var signerName string + { + createIssuerPairParams := &cmapi.CreateIssuerPairParams{ + IssuerCommonName: signerCommonName, + } + createIssuerPairRes, err := lg.CreateIssuerPair(ctx, createIssuerPairParams) + require.NoError(t, err) + require.NotNil(t, createIssuerPairRes) + + signerID = createIssuerPairRes.IssuerID + printObj("signerID", signerID) + + signerCert = createIssuerPairRes.Certificate + printObj("signerCert", signerCert) + + signerName = createIssuerPairRes.IssuerName + printObj("signerName", signerName) + + signerCertObj, err := cm509.ParseDoubleEncodedCerificate(signerCert) + require.NoError(t, err) + require.NotNil(t, signerCertObj) + printObj("signerCertObj Subject", signerCertObj.Subject.String()) + printObj("signerCertObj Issuer", signerCertObj.Issuer.String()) + } + issuerCommonName := "make.love.not.war" var issuerID int64 + var issuerCert string + var issuerName string { createIssuerPairParams := &cmapi.CreateIssuerPairParams{ IssuerCommonName: issuerCommonName, + SignerID: signerID, } createIssuerPairRes, err := lg.CreateIssuerPair(ctx, createIssuerPairParams) require.NoError(t, err) require.NotNil(t, createIssuerPairRes) + issuerID = createIssuerPairRes.IssuerID - printObj("issuerID", issuerID) + printObj("issuerID", issuerID) + + issuerCert = createIssuerPairRes.Certificate + printObj("issuerCert", issuerCert) + + issuerName = createIssuerPairRes.IssuerName + printObj("issuerName", issuerName) + + issuerCertObj, err := cm509.ParseDoubleEncodedCerificate(issuerCert) + require.NoError(t, err) + require.NotNil(t, issuerCertObj) + printObj("issuerCertObj Subject", issuerCertObj.Subject.String()) + printObj("issuerCertObj Issuer", issuerCertObj.Issuer.String()) + + require.NotEqual(t, issuerCertObj.Subject.String(), issuerCertObj.Issuer.String()) + } +} + + +func XXXTestIssuerCreate(t *testing.T) { + var err error + var lg *logic.Logic + { + conf := config.NewConfig() + err = conf.ReadFile() + require.NoError(t, err) + + db, err := database.NewDatabase(conf.DataDir) + require.NoError(t, err) + require.NotNil(t, db) + err = db.InitDatabase() + require.NoError(t, err) + + logicConfig := &logic.LogicConfig{ + Auths: conf.Auths, + Database: db, + } + lg, err = logic.NewLogic(logicConfig) + require.NoError(t, err) + require.NotNil(t, lg) } + + ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) + + issuerCommonName := "foo.bar" + var issuerID int64 var issuerCert string + { + createIssuerPairParams := &cmapi.CreateIssuerPairParams{ + IssuerCommonName: issuerCommonName, + } + createIssuerPairRes, err := lg.CreateIssuerPair(ctx, createIssuerPairParams) + require.NoError(t, err) + require.NotNil(t, createIssuerPairRes) + issuerID = createIssuerPairRes.IssuerID + printObj("issuerID", issuerID) + printObj("issuerID", issuerID) + } { getIssuerCertificateParams := &cmapi.GetIssuerCertificateParams{ IssuerID: issuerID, @@ -128,26 +212,16 @@ func TestLogicIssuer(t *testing.T) { printObj("listIssuerPairRes", listIssuerPairsRes) } { - importIssuerPairParams := &cmapi.ImportIssuerPairParams{ - Certificate: issuerCert, + for i := 0; i < 3; i++ { + createIssuerPairParams := &cmapi.CreateIssuerPairParams{ + IssuerCommonName: fmt.Sprintf("sub%0d.%s", i, issuerCommonName), + } + createIssuerPairRes, err := lg.CreateIssuerPair(ctx, createIssuerPairParams) + require.NoError(t, err) + require.NotNil(t, createIssuerPairRes) + issuerID = createIssuerPairRes.IssuerID + printObj("issuerID", issuerID) } - importIssuerPairRes, err := lg.ImportIssuerPair(ctx, importIssuerPairParams) - require.NoError(t, err) - require.NotNil(t, importIssuerPairRes) - - printObj("importIssuerPairRes", importIssuerPairRes) - } - { - for i := 0; i < 3; i++ { - createIssuerPairParams := &cmapi.CreateIssuerPairParams{ - IssuerCommonName: fmt.Sprintf("sub%0d.%s", i, issuerCommonName), - } - createIssuerPairRes, err := lg.CreateIssuerPair(ctx, createIssuerPairParams) - require.NoError(t, err) - require.NotNil(t, createIssuerPairRes) - issuerID = createIssuerPairRes.IssuerID - printObj("issuerID", issuerID) - } } { listIssuerPairsParams := &cmapi.ListIssuerPairsParams{} @@ -158,12 +232,12 @@ func TestLogicIssuer(t *testing.T) { printObj("listIssuerPairRes", listIssuerPairsRes) } - serviceCommonName := "make.love" + serviceCommonName := "make.love.not.war" var serviceID int64 { createServicePairParams := &cmapi.CreateServicePairParams{ ServiceCommonName: serviceCommonName, - IssuerID: issuerID, + IssuerID: issuerID, } createServicePairRes, err := lg.CreateServicePair(ctx, createServicePairParams) printObj("createServicePairRes", createServicePairRes) @@ -187,12 +261,3 @@ func TestLogicIssuer(t *testing.T) { } } -func printObj(label string, obj any) { - objBytes, _ := yaml.Marshal(obj) - objString := string(objBytes) - if strings.Count(objString, "\n") < 2 { - fmt.Printf("==== %s: %s\n", label, objString) - } else { - fmt.Printf("==== %s ::\n%s\n", label, objString) - } -} diff --git a/internal/test/logic_issuer_import_test.go b/internal/test/logic_issuer_import_test.go new file mode 100644 index 0000000..8ec597d --- /dev/null +++ b/internal/test/logic_issuer_import_test.go @@ -0,0 +1,95 @@ +package test + +import ( + "context" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "encoding/base64" + "fmt" + "os" + "testing" + "time" + + cmapi "certmanager/api/certmanagercontrol" + "certmanager/internal/config" + "certmanager/internal/database" + "certmanager/internal/logic" + "certmanager/pkg/cm509" + + "github.com/stretchr/testify/require" +) + +func XXXTestLogicImportIssuer(t *testing.T) { + var err error + var lg *logic.Logic + { + conf := config.NewConfig() + err = conf.ReadFile() + require.NoError(t, err) + + db, err := database.NewDatabase(conf.DataDir) + require.NoError(t, err) + require.NotNil(t, db) + + err = db.InitDatabase() + require.NoError(t, err) + + logicConfig := &logic.LogicConfig{ + Auths: conf.Auths, + Database: db, + } + lg, err = logic.NewLogic(logicConfig) + require.NoError(t, err) + require.NotNil(t, lg) + } + + certBytes, err := os.ReadFile("testchain_a00.crt") + require.NoError(t, err) + require.NotZero(t, len(certBytes)) + certObj, err := cm509.ParseEncodedCerificate(string(certBytes)) + require.NoError(t, err) + require.NotNil(t, certObj) + certString := base64.StdEncoding.EncodeToString(certBytes) + + keyBytes, err := os.ReadFile("testchain_a00.key") + require.NoError(t, err) + require.NotZero(t, len(keyBytes)) + keyString := base64.StdEncoding.EncodeToString(keyBytes) + keyObj, err := cm509.ParseDoubleEncodedKey(keyString) + require.NoError(t, err) + require.NotNil(t, keyObj) + + switch keyObj.(type) { + case ed25519.PrivateKey: + fmt.Printf("ED25519 key\n") + case *rsa.PrivateKey: + fmt.Printf("RSA key\n") + case *ecdsa.PrivateKey: + fmt.Printf("ECDSA key\n") + default: + fmt.Printf("Unknown key type\n") + } + + certStrings := make([]string, 0) + for i := 2; i < 4; i++ { + certBytes, err := os.ReadFile(fmt.Sprintf("testchain_a%02d.crt", i)) + require.NoError(t, err) + require.NotZero(t, len(certBytes)) + certString := base64.StdEncoding.EncodeToString(certBytes) + certStrings = append(certStrings, certString) + } + + ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) + { + importIssuerPairParams := &cmapi.ImportIssuerPairParams{ + Certificate: certString, + Key: keyString, + } + importIssuerPairRes, err := lg.ImportIssuerPair(ctx, importIssuerPairParams) + require.NoError(t, err) + require.NotNil(t, importIssuerPairRes) + + printObj("importIssuerPairRes", importIssuerPairRes) + } +} diff --git a/internal/logic/testchain_a00.crt b/internal/test/testchain_a00.crt similarity index 100% rename from internal/logic/testchain_a00.crt rename to internal/test/testchain_a00.crt diff --git a/internal/test/testchain_a00.key b/internal/test/testchain_a00.key new file mode 100644 index 0000000..114850b --- /dev/null +++ b/internal/test/testchain_a00.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDEPDeTj3zdCZEi +pXQ+xcV8bfHXCRqasytj2wzP4z4JH2HWKjO/g5B2bnAUmn/x6u3vH4lLTu/i9pti +gvJWx215FceupeVIMky5lpF4chBWoqTUFhn2aIgfrgTFQDq93evwCaKWKkg9b5Qm +KFpmc/vA/LzQ9R0KKrS2dJ7Ao37B/ORrnJ6FZd5pNsN4OhSXUJ/lDcI70qFshg3A +bwYGb7hgqK57COMhTiw8RoI++m8JNzADgtyp/VrBT+dF1Mtc7V4vgt7NMQ9vspJL +uERlIezZpBuNWmhXQhy5JgjVt5vtdJ2y/+MMjM6m79LH4CoxTL5YTiw7RiPdqnyZ +uxj0dMLtAgMBAAECggEAT+k1uKF1940tzS4TaHyhL0qWcTsD2nub784EKaQgXxao +gM4uxI6PBatzePBxqdJBkl8FSeWbSpGiNTud9DjCG80Cw9xKwlu5Ytot4x6QCLey +56sYZ3+p7zyuNKUzRp5Ytic2TnBpeps1eVR1e8M/ghdpzK4EZV9+t85F16y8scHT +rv2lXzweUQYJBQeZ4Ngs+lCCCIrUblfnUpFmL6AoCF/QGHa+68OrY3jlq7fxBjM7 +DChXiAULsCnPqHNIoJ2B+OsMGhg+V+u/X7lQpIvo5coVp+8oa7Yyux7E1gGJgm6t +OzBKwCK96oEJ0Lt3EiVexikyMZ40UFWLD4rtxnewAQKBgQDkUSaciCnhlBKFAaL5 +9CO7k5oKbt4DPxQoPot35TL+MSO2XGuKEdLU1B4S9Hz8mWkHKz7LpmZ6JYDyoej2 +/eNXrL7UxlE/nNXWfgCBycqp1AE/aQGtoMnHarZ8Dj7WizaDxkiIx0DX0brOsgxl +kNfLs+jkcFusXON5/1JsOB1jXQKBgQDcB0N4z3vbjjGAC5xVL0fFcgNoXbby9mG6 +IFjhnJJylVpf8bvRq2PKcj8PyKvUEOpjLAgsyjjCoW8wA6mrqZH7Ps3QRSTy9+gs +pxyXWMPLcmxEBtUyKtGsAiSnSPIFzl2RPD2935C9nLzNRuOnpHs7R55yglE9WWSF +n7kfXqr00QKBgQCBQIOYR+lVv8rAK04FLLXx4bxpvZvHwLT7l3TDGijFCDKMcUOb +9T0iqTahSnFbWsm/ejbheUE4UvTt5sUI1nAWWT/rGp4yYeoYtFo7H26wt8lBCYQe +tBCm6P2Hu1TNhiAFd4HmlM5bn2qeyuMDuHzB4AavFACB0lAg527Uvuu8LQKBgHGP +qipTZEjIVhIRbAmnUnK8yrd2DvPNaFkpUtZ2+jr7jN6SJG8t915IovWhi9XzORYg +ZsO/R5Zkvb9ZVJwN9BNpsc45sb1ZaFKLmb0fikaZ8vkVUboH0ZnmrUZN5uRKQ46v +Oeqi1dCXcfa9DMi8owHQkB3n1shEOBajfmeLc87RAoGBAL3KQCYY7Te/V0JlRhcM +fqHVxbMFUF2mkWAgOIqoxOpS2Bc/tdbhvv2w54fjLM2pj+LhAsSkLugmg15ZYVZR +cyXMw1Jm55sb58UaMUm/3byxM0X27JK3tHJbGP1fff/bUjknK16zFWyQ1N/UwrOc +3xo0LZx60iIhLNiABZJyWv0o +-----END PRIVATE KEY----- diff --git a/internal/logic/testchain_a01.crt b/internal/test/testchain_a01.crt similarity index 100% rename from internal/logic/testchain_a01.crt rename to internal/test/testchain_a01.crt diff --git a/internal/logic/testchain_a02.crt b/internal/test/testchain_a02.crt similarity index 100% rename from internal/logic/testchain_a02.crt rename to internal/test/testchain_a02.crt diff --git a/internal/logic/testchain_a03.crt b/internal/test/testchain_a03.crt similarity index 100% rename from internal/logic/testchain_a03.crt rename to internal/test/testchain_a03.crt diff --git a/pkg/cm509/testchain_a00.crt b/pkg/cm509/testchain_a00.crt new file mode 100644 index 0000000..2527f25 --- /dev/null +++ b/pkg/cm509/testchain_a00.crt @@ -0,0 +1,42 @@ +-----BEGIN CERTIFICATE----- +MIIHZDCCBkygAwIBAgISA0TPqlhFqMMjfL8lwr1WdKCiMA0GCSqGSIb3DQEBCwUA +MDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQD +EwNSMTEwHhcNMjQwNzE1MDcwNTQyWhcNMjQxMDEzMDcwNTQxWjAYMRYwFAYDVQQD +Ew1oYW0udW5peDcub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +xDw3k4983QmRIqV0PsXFfG3x1wkamrMrY9sMz+M+CR9h1iozv4OQdm5wFJp/8ert +7x+JS07v4vabYoLyVsdteRXHrqXlSDJMuZaReHIQVqKk1BYZ9miIH64ExUA6vd3r +8AmilipIPW+UJihaZnP7wPy80PUdCiq0tnSewKN+wfzka5yehWXeaTbDeDoUl1Cf +5Q3CO9KhbIYNwG8GBm+4YKiuewjjIU4sPEaCPvpvCTcwA4Lcqf1awU/nRdTLXO1e +L4LezTEPb7KSS7hEZSHs2aQbjVpoV0IcuSYI1beb7XSdsv/jDIzOpu/Sx+AqMUy+ +WE4sO0Yj3ap8mbsY9HTC7QIDAQABo4IEizCCBIcwDgYDVR0PAQH/BAQDAgWgMB0G +A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1Ud +DgQWBBR3smydoErE3KVUBr0/ohKZ0ghK0jAfBgNVHSMEGDAWgBTFz0ak6vTDwHps +lcQtsF6SLybjuTBXBggrBgEFBQcBAQRLMEkwIgYIKwYBBQUHMAGGFmh0dHA6Ly9y +MTEuby5sZW5jci5vcmcwIwYIKwYBBQUHMAKGF2h0dHA6Ly9yMTEuaS5sZW5jci5v +cmcvMIICkAYDVR0RBIIChzCCAoOCEmFpcmZvcmNlLnVuaXg3Lm9yZ4IOYXJ0cy51 +bml4Ny5vcmeCDWRlNC51bml4Ny5vcmeCDWRlNS51bml4Ny5vcmeCDWRlNi51bml4 +Ny5vcmeCDWRlNy51bml4Ny5vcmeCDWRlYi51bml4Ny5vcmeCDWRldi51bml4Ny5v +cmeCDmRuczUudW5peDcub3Jngg1lZHUudW5peDcub3JnghBlZHVtYXgudW5peDcu +b3Jngg1naXQudW5peDcub3Jngg9nbWFpbC51bml4Ny5vcmeCDWhhbS51bml4Ny5v +cmeCDmhhc2gudW5peDcub3JnggxoZC51bml4Ny5vcmeCDmhlYXAudW5peDcub3Jn +ghJob21lZGVzay51bml4Ny5vcmeCDWh1Yi51bml4Ny5vcmeCEGl0ZGVzay51bml4 +Ny5vcmeCD2xhcGlzLnVuaXg3Lm9yZ4IPbG9yZW0udW5peDcub3Jngg5tYWlsLnVu +aXg3Lm9yZ4IMbXcudW5peDcub3JnggxteC51bml4Ny5vcmeCDnBkbnMudW5peDcu +b3Jngg5waWtpLnVuaXg3Lm9yZ4IPcHJveHkudW5peDcub3JnghFyZWRtaW5lLnVu +aXg3Lm9yZ4IMcm0udW5peDcub3Jngg9zbGFjay51bml4Ny5vcmeCEHNwcmluZy51 +bml4Ny5vcmeCDnNydjcudW5peDcub3JnghBzdG9yZXgudW5peDcub3JnghB0YW5h +a2gudW5peDcub3Jnggx2NS51bml4Ny5vcmeCDXcxMi51bml4Ny5vcmeCDXdjbS51 +bml4Ny5vcmeCDndpa2kudW5peDcub3Jngg13d3cudW5peDcub3JnMBMGA1UdIAQM +MAowCAYGZ4EMAQIBMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHcASLDja9qmRzQP +5WoC+p0w6xxSActW3SyB2bu/qznYhHMAAAGQtW0RVQAABAMASDBGAiEAjQvvzpOR +urMOiqV5g0EuAK1A9CuAKOdWJp6/s3/SKBMCIQCbTBj13lhMnTr6bSHwoBtSwoiY +aeDJzGBmDTpbgGpFdQB1AN/hVuuqBa+1nA+GcY2owDJOrlbZbqf1pWoB0cE7vlJc +AAABkLVtEicAAAQDAEYwRAIgWe0pdXXB6UmMmeSgYLDncdkS2aKHAHDdOqKOoL9x +Kx8CIBqobR/Ve1IZMTLrRN54vh8kNmF0OkVjXtrh+ste6cKUMA0GCSqGSIb3DQEB +CwUAA4IBAQA3c88cXIejS9vy4XUow6dOuud6qqkNX1osSq2vRtYkKMZb2JVuhPAr +hQsozwptJPm5lOEDQPD8676yZNVgGdjmMvA0ewdWEp9HZ7x+RFlI7RC9CqMSOWPO +p60RMiBQlK7Els38WurmW2GzZkfykzpZZ/0lIrCNjT7aB9VjGVDOjxo/xHapHSwJ +GOxq4TTU1KaFfbFl5A2F9bRVrAAWfih+DzUzhlhZBHODzadgs2CimVYIp8gEVf1j +dGetiU2j+cvOpvQnfX7Xr8Cf2YK7E0j6lfC3RPvK9oA1bP5KBMWELXsGBrwIxgUB +f2/jRcxrQoGoEYwYW4D/JViKwelABzfc +-----END CERTIFICATE----- diff --git a/pkg/cm509/testchain_a01.crt b/pkg/cm509/testchain_a01.crt new file mode 100644 index 0000000..d6bdd38 --- /dev/null +++ b/pkg/cm509/testchain_a01.crt @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIFBjCCAu6gAwIBAgIRAIp9PhPWLzDvI4a9KQdrNPgwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw +WhcNMjcwMzEyMjM1OTU5WjAzMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDEMMAoGA1UEAxMDUjExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAuoe8XBsAOcvKCs3UZxD5ATylTqVhyybKUvsVAbe5KPUoHu0nsyQYOWcJ +DAjs4DqwO3cOvfPlOVRBDE6uQdaZdN5R2+97/1i9qLcT9t4x1fJyyXJqC4N0lZxG +AGQUmfOx2SLZzaiSqhwmej/+71gFewiVgdtxD4774zEJuwm+UE1fj5F2PVqdnoPy +6cRms+EGZkNIGIBloDcYmpuEMpexsr3E+BUAnSeI++JjF5ZsmydnS8TbKF5pwnnw +SVzgJFDhxLyhBax7QG0AtMJBP6dYuC/FXJuluwme8f7rsIU5/agK70XEeOtlKsLP +Xzze41xNG/cLJyuqC0J3U095ah2H2QIDAQABo4H4MIH1MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwEgYDVR0TAQH/BAgwBgEB +/wIBADAdBgNVHQ4EFgQUxc9GpOr0w8B6bJXELbBeki8m47kwHwYDVR0jBBgwFoAU +ebRZ5nu25eQBc4AIiMgaWPbpm24wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzAC +hhZodHRwOi8veDEuaS5sZW5jci5vcmcvMBMGA1UdIAQMMAowCAYGZ4EMAQIBMCcG +A1UdHwQgMB4wHKAaoBiGFmh0dHA6Ly94MS5jLmxlbmNyLm9yZy8wDQYJKoZIhvcN +AQELBQADggIBAE7iiV0KAxyQOND1H/lxXPjDj7I3iHpvsCUf7b632IYGjukJhM1y +v4Hz/MrPU0jtvfZpQtSlET41yBOykh0FX+ou1Nj4ScOt9ZmWnO8m2OG0JAtIIE38 +01S0qcYhyOE2G/93ZCkXufBL713qzXnQv5C/viOykNpKqUgxdKlEC+Hi9i2DcaR1 +e9KUwQUZRhy5j/PEdEglKg3l9dtD4tuTm7kZtB8v32oOjzHTYw+7KdzdZiw/sBtn +UfhBPORNuay4pJxmY/WrhSMdzFO2q3Gu3MUBcdo27goYKjL9CTF8j/Zz55yctUoV +aneCWs/ajUX+HypkBTA+c8LGDLnWO2NKq0YD/pnARkAnYGPfUDoHR9gVSp/qRx+Z +WghiDLZsMwhN1zjtSC0uBWiugF3vTNzYIEFfaPG7Ws3jDrAMMYebQ95JQ+HIBD/R +PBuHRTBpqKlyDnkSHDHYPiNX3adPoPAcgdF3H2/W0rmoswMWgTlLn1Wu0mrks7/q +pdWfS6PJ1jty80r2VKsM/Dj3YIDfbjXKdaFU5C+8bhfJGqU3taKauuz0wHVGT3eo +6FlWkWYtbt4pgdamlwVeZEW+LM7qZEJEsMNPrfC03APKmZsJgpWCDWOKZvkZcvjV +uYkQ4omYCTX5ohy+knMjdOmdH9c7SpqEWBDC86fiNex+O0XOMEZSa8DA +-----END CERTIFICATE----- diff --git a/pkg/cm509/testchain_a02.crt b/pkg/cm509/testchain_a02.crt new file mode 100644 index 0000000..1bb92a9 --- /dev/null +++ b/pkg/cm509/testchain_a02.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC +ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL +wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D +LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK +4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5 +bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y +sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ +Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4 +FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc +SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql +PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND +TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1 +c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx ++tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB +ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu +b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E +U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu +MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC +5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW +9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG +WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O +he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC +Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5 +-----END CERTIFICATE----- diff --git a/pkg/cm509/testchain_a03.crt b/pkg/cm509/testchain_a03.crt new file mode 100644 index 0000000..3ff37c1 --- /dev/null +++ b/pkg/cm509/testchain_a03.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFVDCCBDygAwIBAgIRAKLBiJX85huxZJB/Ylc2Y5gwDQYJKoZIhvcNAQEFBQAw +gakxCzAJBgNVBAYTAnVzMQ0wCwYDVQQIEwRVdGFoMRcwFQYDVQQHEw5TYWx0IExh +a2UgQ2l0eTEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw +DwYDVQQLEwhEU1RDQSBYMTEWMBQGA1UEAxMNRFNUIFJvb3RDQSBYMTEhMB8GCSqG +SIb3DQEJARYSY2FAZGlnc2lndHJ1c3QuY29tMB4XDTA0MDkwODE0NDM0NVoXDTA4 +MTEyODEzMDI1OVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qg +Q28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+Do +M3ZJKuM/IUmTrE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwG +MoOifooUMM0RoOEqOLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOe +DNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqc +kh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr +2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaOCAd4wggHaMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMIG7BgNVHR8EgbMwgbAwga2ggaqg +gaeGgaRsZGFwOi8vbGRhcC5kaWdzaWd0cnVzdC5jb20vY249RFNUJTIwUm9vdENB +JTIwWDEsb3U9RFNUQ0ElMjBYMSxvPURpZ2l0YWwlMjBTaWduYXR1cmUlMjBUcnVz +dCUyMENvLixsPVNhbHQlMjBMYWtlJTIwQ2l0eSxTPVV0YWgsYz11cz9jZXJ0aWZp +Y2F0ZVJldm9jYXRpb25MaXN0O2JpbmFyeTCBuAYIKwYBBQUHAQEEgaswgagwgaUG +CCsGAQUFBzAChoGYbGRhcDovL2xkYXAuZGlnc2lndHJ1c3QuY29tL2NuPURTVCUy +MFJvb3RDQSUyMFgxLG91PURTVENBJTIwWDEsbz1EaWdpdGFsJTIwU2lnbmF0dXJl +JTIwVHJ1c3QlMjBDby4sbD1TYWx0JTIwTGFrZSUyMENpdHksUz1VdGFoLGM9dXM/ +Y0FDZXJ0aWZpY2F0ZTtiaW5hcnkwHwYDVR0jBBgwFoAUaU2asPSCd8A2GzVVCRQa +/goSAAowHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqGSIb3DQEB +BQUAA4IBAQCpFXMtsChLFvN/Z+mwiodooamIW0qjMoVGHeN9CcDdUIGQI7cgbT10 +tsJuEZx3opp2s4LoM7Gn/o0T/rysLlT34vPwI4Ei/df3aG0ite5ehqWgMuc65n1P +tadwl5JFFx3l8B0YWrOv5xJ0kY+br4FGI2OGqxagBtH2y7Uak4Iq2xipTHhlvx6a +DWAzGQHovRdLf1c4cFti11gU29QYPgDXsJSuriq3xcItGzjYZT9V45WiIlmdvez0 +vCr6wcnjifctVfQ7z2o2+yl7A1+ijNhDhyfcrdPqctwx0Nk8IDitss+vNMsqoEHx +uBoIoQw0DQhKAEYri9bw+9wqZhotOjMw +-----END CERTIFICATE----- diff --git a/pkg/cm509/x509.go b/pkg/cm509/x509.go new file mode 100644 index 0000000..4df5711 --- /dev/null +++ b/pkg/cm509/x509.go @@ -0,0 +1,460 @@ +package cm509 + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/base64" + "encoding/pem" + "fmt" + "math/big" + "net" + "time" +) + +type CreateIssuerPairParams struct { + CommonName string + SignerCert string + SignerKey string +} +type CreateIssuerPairResult struct { + Name string + Cert string + Key string +} + + +func CreateIssuerPair(params *CreateIssuerPairParams) (*CreateIssuerPairResult, error) { + var err error + res := &CreateIssuerPairResult{} + + if params.SignerKey != "" && params.SignerCert == "" { + err = fmt.Errorf("The signature key and certificate must be defined together") + return res, err + } + if params.SignerKey == "" && params.SignerCert != "" { + err = fmt.Errorf("The signature key and certificate must be defined together") + return res, err + } + + var signerKey any + if params.SignerKey != "" { + signerKey, err = ParseDoubleEncodedKey(params.SignerKey) + if err != nil { + return res, err + } + } + var signerCert *x509.Certificate + if params.SignerCert != "" { + signerCert, err = ParseDoubleEncodedCerificate(params.SignerCert) + if err != nil { + return res, err + } + } + + certPem := make([]byte, 0) + keyPem := make([]byte, 0) + + now := time.Now() + + const yearsAfter int = 10 + const keySize int = 2048 + + certKey, err := rsa.GenerateKey(rand.Reader, keySize) + if err != nil { + err := fmt.Errorf("Can't create a private key: %v", err) + return res, err + + } + keyPemBlock := &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(certKey), + } + keyPem = pem.EncodeToMemory(keyPemBlock) + + certSubject := pkix.Name{ + CommonName: params.CommonName, + } + + certIssuer := certSubject + if signerCert != nil { + certIssuer = signerCert.Subject + } + + var issuerKey any = certKey + if signerKey != nil { + issuerKey = signerKey + } + + res.Name = certSubject.String() + + certTempl := &x509.Certificate{ + SerialNumber: big.NewInt(now.Unix()), + NotBefore: now, + NotAfter: now.AddDate(yearsAfter, 0, 0), + Subject: certSubject, + Issuer: certIssuer, + IsCA: true, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + + parentCert := certTempl + if signerCert != nil { + parentCert = signerCert + } + + certBytes, err := x509.CreateCertificate(rand.Reader, certTempl, parentCert, &certKey.PublicKey, issuerKey) + if err != nil { + err := fmt.Errorf("Can't create a certificate: %v", err) + return res, err + + } + certPemBlock := pem.Block{ + Type: "CERTIFICATE", + Bytes: certBytes, + } + certPem = pem.EncodeToMemory(&certPemBlock) + if err != nil { + return res, err + } + + res.Cert = base64.StdEncoding.EncodeToString(certPem) + res.Key = base64.StdEncoding.EncodeToString(keyPem) + return res, err +} + + + +func CreateIssuerPairV0(params *CreateIssuerPairParams) (*CreateIssuerPairResult, error) { + var err error + res := &CreateIssuerPairResult{} + + certPem := make([]byte, 0) + keyPem := make([]byte, 0) + + now := time.Now() + + const yearsAfter int = 10 + const keySize int = 2048 + + key, err := rsa.GenerateKey(rand.Reader, keySize) + if err != nil { + err := fmt.Errorf("Can't create a private key: %v", err) + return res, err + + } + keyPemBlock := pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(key), + } + keyPem = pem.EncodeToMemory(&keyPemBlock) + + subjectName := pkix.Name{ + CommonName: params.CommonName, + } + issuerName := subjectName + res.Name = subjectName.String() + + certTempl := x509.Certificate{ + SerialNumber: big.NewInt(now.Unix()), + NotBefore: now, + NotAfter: now.AddDate(yearsAfter, 0, 0), + Subject: subjectName, + Issuer: issuerName, + IsCA: true, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + certBytes, err := x509.CreateCertificate(rand.Reader, &certTempl, &certTempl, &key.PublicKey, key) + if err != nil { + err := fmt.Errorf("Can't create a certificate: %v", err) + return res, err + + } + certPemBlock := pem.Block{ + Type: "CERTIFICATE", + Bytes: certBytes, + } + certPem = pem.EncodeToMemory(&certPemBlock) + if err != nil { + return res, err + } + + res.Cert = base64.StdEncoding.EncodeToString(certPem) + res.Key = base64.StdEncoding.EncodeToString(keyPem) + return res, err +} + +type CreateServicePairParams struct { + CommonName string + DNSNames []string + IPAddresses []string + IssuerKey string + IssuerCert string +} +type CreateServicePairResult struct { + Name string + Cert string + Key string +} + +func CreateServicePairV2(params *CreateServicePairParams) (*CreateServicePairResult, error) { + var err error + + res := &CreateServicePairResult{} + certPem := make([]byte, 0) + keyPem := make([]byte, 0) + now := time.Now() + + const yearsAfter int = 10 + const keySize int = 2048 + + key, err := rsa.GenerateKey(rand.Reader, keySize) + if err != nil { + err := fmt.Errorf("Can't create a private key: %v", err) + return res, err + } + keyPemBlock := pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(key), + } + keyPem = pem.EncodeToMemory(&keyPemBlock) + + caKeyPem, err := base64.StdEncoding.DecodeString(params.IssuerKey) + if err != nil { + return res, err + } + + pemBlock, _ := pem.Decode(caKeyPem) + if pemBlock == nil { + err := fmt.Errorf("Can't parse a CA private key block") + return res, err + } + caKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes) + if err != nil { + err := fmt.Errorf("Can't parse a CA private key") + return res, err + } + + netAddresses := make([]net.IP, 0) + for _, ipAddress := range params.IPAddresses { + netAddress := net.ParseIP(ipAddress) + netAddresses = append(netAddresses, netAddress) + } + certTempl := x509.Certificate{ + SerialNumber: big.NewInt(now.Unix()), + NotBefore: now, + NotAfter: now.AddDate(yearsAfter, 0, 0), + Subject: pkix.Name{ + CommonName: params.CommonName, + }, + DNSNames: params.DNSNames, + IPAddresses: netAddresses, + IsCA: false, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature, + BasicConstraintsValid: true, + } + certBytes, err := x509.CreateCertificate(rand.Reader, &certTempl, &certTempl, &key.PublicKey, caKey) + if err != nil { + return res, fmt.Errorf("Can't create a certificate: %v", err) + + } + certPemBlock := pem.Block{ + Type: "CERTIFICATE", + Bytes: certBytes, + } + + certPem = pem.EncodeToMemory(&certPemBlock) + if err != nil { + return res, err + } + res.Cert = base64.StdEncoding.EncodeToString(certPem) + res.Key = base64.StdEncoding.EncodeToString(keyPem) + return res, err +} + + + + + + +func ParseDoubleEncodedCerificate(certString string) (*x509.Certificate, error) { + var err error + res := &x509.Certificate{} + + certPEM, err := base64.StdEncoding.DecodeString(certString) + if err != nil { + err := fmt.Errorf("Failed to parse base64 certificate string: %v", err) + return res, err + } + certBlock, _ := pem.Decode([]byte(certPEM)) + if certBlock == nil { + err := fmt.Errorf("Failed to parse certificate PEM") + return res, err + } + if certBlock.Type != "CERTIFICATE" { + err := fmt.Errorf("Unknown PEM certificate type: %s", certBlock.Type) + return res, err + } + if len(certBlock.Bytes) == 0 { + err := fmt.Errorf("Empty PEM certificate block") + return res, err + } + + res, err = x509.ParseCertificate(certBlock.Bytes) + if err != nil { + return res, err + } + return res, err +} + +func ParseEncodedCerificate(certPEM string) (*x509.Certificate, error) { + var err error + res := &x509.Certificate{} + + certBlock, _ := pem.Decode([]byte(certPEM)) + if certBlock == nil { + err := fmt.Errorf("Failed to parse certificate PEM") + return res, err + } + if certBlock.Type != "CERTIFICATE" { + err := fmt.Errorf("Unknown PEM certificate type: %s", certBlock.Type) + return res, err + } + if len(certBlock.Bytes) == 0 { + err := fmt.Errorf("Empty PEM certificate block") + return res, err + } + res, err = x509.ParseCertificate(certBlock.Bytes) + if err != nil { + return res, err + } + return res, err +} + +func ParseDoubleEncodedKey(keyString string) (any, error) { + var err error + var res any + + keyPEM, err := base64.StdEncoding.DecodeString(keyString) + if err != nil { + err := fmt.Errorf("Failed to parse base64 key string: %v", err) + return res, err + } + keyBlock, _ := pem.Decode([]byte(keyPEM)) + if keyBlock == nil { + err := fmt.Errorf("Failed to parse key PEM") + return res, err + } + switch keyBlock.Type { + case "PRIVATE KEY": + res, err = x509.ParsePKCS8PrivateKey(keyBlock.Bytes) + if err != nil { + return res, err + } + case "RSA PRIVATE KEY": + res, err = x509.ParsePKCS1PrivateKey(keyBlock.Bytes) + if err != nil { + return res, err + } + case "EC PRIVATE KEY": + res, err = x509.ParseECPrivateKey(keyBlock.Bytes) + if err != nil { + return res, err + } + default: + err := fmt.Errorf("Unknown PEM key type: %s", keyBlock.Type) + return res, err + } + return res, err +} + +func ParseEncodedKey(keyPEM string) (any, error) { + var err error + var res any + + keyBlock, _ := pem.Decode([]byte(keyPEM)) + if keyBlock == nil { + err := fmt.Errorf("Failed to parse key PEM") + return res, err + } + switch keyBlock.Type { + case "PRIVATE KEY": + res, err = x509.ParsePKCS8PrivateKey(keyBlock.Bytes) + if err != nil { + return res, err + } + case "RSA PRIVATE KEY": + res, err = x509.ParsePKCS1PrivateKey(keyBlock.Bytes) + if err != nil { + return res, err + } + case "EC PRIVATE KEY": + res, err = x509.ParseECPrivateKey(keyBlock.Bytes) + if err != nil { + return res, err + } + default: + err := fmt.Errorf("Unknown PEM key type: %s", keyBlock.Type) + return res, err + } + return res, err +} + +func CheckDoubleEncodedCertificateChain(topIssuerCN string, certStrings []string) ([]string, error) { + var err error + res := make([]string, 0) + + certObjs := make([]*x509.Certificate, 0) + for _, certString := range certStrings { + certObj, err := ParseDoubleEncodedCerificate(certString) + if err != nil { + return res, err + } + certObjs = append(certObjs, certObj) + } + + issuerFound := false + issuerIndex := -1 + for i, certObj := range certObjs { + if topIssuerCN == certObj.Subject.String() { + issuerIndex = i + issuerFound = true + } + } + if !issuerFound { + err := fmt.Errorf("Issuer for %s cannot found", topIssuerCN) + return res, err + } + interCertObj := certObjs[issuerIndex] + interCertString := certStrings[issuerIndex] + if !interCertObj.IsCA { + err := fmt.Errorf("Issuer %s is not CA", interCertObj.Subject.String()) + return res, err + } + expired := interCertObj.NotAfter.Before(time.Now()) + if !expired { + err := fmt.Errorf("Issuer %s expired %v", interCertObj.Subject.String(), interCertObj.NotAfter) + return res, err + } + + res = append(res, interCertString) + if interCertObj.Subject.String() == interCertObj.Issuer.String() { + return res, err + } + updatedCertStrings := append(certStrings[:issuerIndex], certStrings[issuerIndex+1:]...) + topIssuerCN = interCertObj.Issuer.String() + + certStringsTail, err := CheckDoubleEncodedCertificateChain(topIssuerCN, updatedCertStrings) + if err != nil { + return res, err + } + + res = append(res, certStringsTail...) + return res, err +} diff --git a/pkg/cm509/x509_test.go b/pkg/cm509/x509_test.go new file mode 100644 index 0000000..9934038 --- /dev/null +++ b/pkg/cm509/x509_test.go @@ -0,0 +1,48 @@ +package cm509 + +import ( + "encoding/base64" + "fmt" + "os" + "strings" + "testing" + + "github.com/stretchr/testify/require" + "sigs.k8s.io/yaml" +) + +func TestCertChainCheckerErr(t *testing.T) { + var err error + + certBytes, err := os.ReadFile("testchain_a01.crt") + require.NoError(t, err) + require.NotZero(t, len(certBytes)) + certObj, err := ParseEncodedCerificate(string(certBytes)) + require.NoError(t, err) + require.NotNil(t, certObj) + + certStrings := make([]string, 0) + for i := 1; i < 4; i++ { + certBytes, err := os.ReadFile(fmt.Sprintf("testchain_a%02d.crt", i)) + require.NoError(t, err) + require.NotZero(t, len(certBytes)) + certString := base64.StdEncoding.EncodeToString(certBytes) + certStrings = append(certStrings, certString) + } + topIssuerCN := certObj.Issuer.String() + + _, err = CheckDoubleEncodedCertificateChain(topIssuerCN, certStrings) + require.Error(t, err) + //require.NotNil(t, resString) + //require.NotZero(t, len(resString)) +} + +func printObj(label string, obj any) { + objBytes, _ := yaml.Marshal(obj) + objString := string(objBytes) + if strings.Count(objString, "\n") < 2 { + fmt.Printf("==== %s: %s\n", label, objString) + } else { + fmt.Printf("==== %s ::\n%s\n", label, objString) + } +} diff --git a/proto/certmanagercontrol.proto b/proto/certmanagercontrol.proto index 64ea16f..280b16c 100644 --- a/proto/certmanagercontrol.proto +++ b/proto/certmanagercontrol.proto @@ -28,14 +28,15 @@ message getStatusResult { message createIssuerPairParams { string issuerCommonName = 1; bool intermediate = 2; - int64 signerIssuerID = 3; - string signerIssuerName = 4; + int64 signerID = 3; + string signerName = 4; string validUntil = 5; string keySize = 6; } message createIssuerPairResult { int64 issuerID = 1; - string certificate = 2; + string issuerName = 2; + string certificate = 3; } message getIssuerCertificateParams {