391 lines
10 KiB
Go
391 lines
10 KiB
Go
package logic
|
|
|
|
import (
|
|
"context"
|
|
"crypto/x509"
|
|
"fmt"
|
|
"time"
|
|
|
|
"certmanager/internal/descriptor"
|
|
"certmanager/pkg/auxid"
|
|
"certmanager/pkg/cm509"
|
|
"certmanager/pkg/cmctl"
|
|
)
|
|
|
|
func (lg *Logic) CreateServicePair(ctx context.Context, userID int64, params *cmctl.CreateServicePairParams) (*cmctl.CreateServicePairResult, error) {
|
|
var err error
|
|
res := &cmctl.CreateServicePairResult{}
|
|
|
|
var issuerDescr *descriptor.Issuer
|
|
var issuerExists bool
|
|
switch {
|
|
case params.IssuerID != 0:
|
|
issuerExists, issuerDescr, err = lg.db.GetIssuerByID(ctx, params.IssuerID)
|
|
if !issuerExists {
|
|
err := fmt.Errorf("No signer with id %d was found", params.IssuerID)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
case params.IssuerName != "":
|
|
issuerExists, issuerDescr, err = lg.db.GetIssuerByName(ctx, params.IssuerName)
|
|
if !issuerExists {
|
|
err := fmt.Errorf("No signer with name %s was found", params.IssuerName)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
default:
|
|
err := fmt.Errorf("Issuer id or name is not specified")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
if issuerDescr == nil {
|
|
err := fmt.Errorf("Issuer descriptor is nil")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
if issuerDescr.Revoked {
|
|
err := fmt.Errorf("The issuer revoked")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
|
|
err = cm509.DoubleEncodedCertKeyMatch(issuerDescr.Cert, issuerDescr.Key)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
createServicePairParams := &cm509.CreateServicePairParams{
|
|
CommonName: params.ServiceCommonName,
|
|
IssuerKey: issuerDescr.Key,
|
|
IssuerCert: issuerDescr.Cert,
|
|
IPAddresses: params.InetAddresses,
|
|
DNSNames: params.Hostnames,
|
|
}
|
|
createSericePairRes, err := cm509.CreateServicePair(createServicePairParams)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
serviceDescr := &descriptor.Service{
|
|
ID: auxid.GenID(),
|
|
Name: createSericePairRes.Name,
|
|
IssuerID: issuerDescr.ID,
|
|
IssuerName: issuerDescr.Name,
|
|
Cert: createSericePairRes.Cert,
|
|
Key: createSericePairRes.Key,
|
|
}
|
|
err = lg.db.InsertService(ctx, serviceDescr)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
res.ServiceName = createSericePairRes.Name
|
|
res.ServiceID = serviceDescr.ID
|
|
res.Certificate = createSericePairRes.Cert
|
|
res.Key = createSericePairRes.Key
|
|
res.IssuerID = issuerDescr.ID
|
|
res.IssuerName = issuerDescr.Name
|
|
res.IssuerCertificate = issuerDescr.Cert
|
|
return res, err
|
|
}
|
|
|
|
func (lg *Logic) GetServicePair(ctx context.Context, userID int64, params *cmctl.GetServicePairParams) (*cmctl.GetServicePairResult, error) {
|
|
var err error
|
|
res := &cmctl.GetServicePairResult{
|
|
IssuerCertificates: make([]string, 0),
|
|
}
|
|
var serviceDescr *descriptor.Service
|
|
var serviceExists bool
|
|
switch {
|
|
case params.ServiceID != 0:
|
|
serviceExists, serviceDescr, err = lg.db.GetServiceByID(ctx, params.ServiceID)
|
|
if !serviceExists {
|
|
err := fmt.Errorf("No service was found for id %d", params.ServiceID)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
case params.ServiceName != "":
|
|
serviceExists, serviceDescr, err = lg.db.GetServiceByName(ctx, params.ServiceName)
|
|
if !serviceExists {
|
|
err := fmt.Errorf("No service was found for name %s", params.ServiceName)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
default:
|
|
err := fmt.Errorf("Service ID or name is not specified")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
if serviceDescr == nil {
|
|
err := fmt.Errorf("Service descriptor is nil")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
|
|
issuerExists, issuerDescr, err := lg.db.GetIssuerByID(ctx, serviceDescr.IssuerID)
|
|
if !issuerExists {
|
|
err := fmt.Errorf("No issuer for service was found")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
|
|
serviceCertObj, err := cm509.ParseDoubleEncodedCerificate(serviceDescr.Cert)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
issuerCertObj, err := cm509.ParseDoubleEncodedCerificate(issuerDescr.Cert)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
if serviceCertObj.Subject.String() != serviceDescr.Name {
|
|
err := fmt.Errorf("The subject's identities in the database and certificate do not match")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
if serviceCertObj.Issuer.String() != serviceDescr.IssuerName {
|
|
err := fmt.Errorf("The issuer's identities in the database and certificate do not match")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
|
|
if serviceCertObj.Issuer.String() != issuerDescr.Name {
|
|
err := fmt.Errorf("The issuer's and service identities in the database and certificate do not match")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
|
|
if serviceCertObj.Issuer.String() != issuerCertObj.Subject.String() {
|
|
err := fmt.Errorf("The issuer's and service identities into certificates do not match")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
|
|
issuerDescrs, err := lg.GetIssuerChain(ctx, serviceDescr.IssuerID)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
for _, issuerDescr := range issuerDescrs {
|
|
res.IssuerCertificates = append(res.IssuerCertificates, issuerDescr.Cert)
|
|
}
|
|
|
|
signerCertPool := x509.NewCertPool()
|
|
for _, issuerDescr := range issuerDescrs {
|
|
issuerCertObj, err := cm509.ParseDoubleEncodedCerificate(issuerDescr.Cert)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
signerCertPool.AddCert(issuerCertObj)
|
|
}
|
|
opts := x509.VerifyOptions{
|
|
Roots: signerCertPool,
|
|
CurrentTime: time.Now(),
|
|
}
|
|
_, err = serviceCertObj.Verify(opts)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
err = cm509.DoubleEncodedCertKeyMatch(serviceDescr.Cert, serviceDescr.Key)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
res.Certificate = serviceDescr.Cert
|
|
res.Key = serviceDescr.Key
|
|
res.IssuerID = serviceDescr.IssuerID
|
|
res.IssuerName = serviceDescr.IssuerName
|
|
res.Revoked = serviceDescr.Revoked
|
|
res.IssuerCertificate = issuerDescr.Cert
|
|
return res, err
|
|
}
|
|
|
|
func (lg *Logic) GetIssuerChain(ctx context.Context, firstIssuerID int64) ([]*descriptor.Issuer, error) {
|
|
var err error
|
|
res := make([]*descriptor.Issuer, 0)
|
|
|
|
firstIssuerExists, firstIssuerDescr, err := lg.db.GetIssuerByID(ctx, firstIssuerID)
|
|
if !firstIssuerExists {
|
|
err := fmt.Errorf("No issuer for service was found")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
|
|
deep := 1
|
|
nextDescrs, err := lg.GetNextIssuerChain(ctx, deep, firstIssuerDescr)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
res = append(res, nextDescrs...)
|
|
return res, err
|
|
}
|
|
func (lg *Logic) GetNextIssuerChain(ctx context.Context, deep int, firstIssuerDescr *descriptor.Issuer) ([]*descriptor.Issuer, error) {
|
|
var err error
|
|
res := make([]*descriptor.Issuer, 0)
|
|
|
|
res = append(res, firstIssuerDescr)
|
|
|
|
deep += 1
|
|
const maxDeep = 12
|
|
if deep > maxDeep {
|
|
err := fmt.Errorf("Cannot found root issuer after %d loops", maxDeep)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
|
|
firstIssuerCertObj, err := cm509.ParseDoubleEncodedCerificate(firstIssuerDescr.Cert)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
itIsSelfSignedRoot := (firstIssuerDescr.SignerID == firstIssuerDescr.SignerID) &&
|
|
(firstIssuerCertObj.Issuer.String() == firstIssuerCertObj.Subject.String())
|
|
if itIsSelfSignedRoot {
|
|
return res, err
|
|
}
|
|
|
|
lg.log.Debugf("%d %d", firstIssuerDescr.ID, firstIssuerDescr.SignerID)
|
|
|
|
nextIssuerExists, nextIssuerDescrs, err := lg.db.GetIssuerByID(ctx, firstIssuerDescr.SignerID)
|
|
if !nextIssuerExists {
|
|
err := fmt.Errorf("No issuer for service was found")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
nextDescrs, err := lg.GetNextIssuerChain(ctx, deep, nextIssuerDescrs)
|
|
res = append(res, nextDescrs...)
|
|
|
|
return res, err
|
|
}
|
|
|
|
func (lg *Logic) ListServicePairs(ctx context.Context, userID int64, params *cmctl.ListServicePairsParams) (*cmctl.ListServicePairsResult, error) {
|
|
var err error
|
|
res := &cmctl.ListServicePairsResult{
|
|
Services: make([]*cmctl.ServiceShortDescriptor, 0),
|
|
}
|
|
|
|
listServices, err := lg.db.ListServices(ctx)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
for _, service := range listServices {
|
|
serviceShortDescr := cmctl.ServiceShortDescriptor{
|
|
ServiceID: service.ID,
|
|
IssuerID: service.IssuerID,
|
|
IssuerName: service.IssuerName,
|
|
Name: service.Name,
|
|
Revoked: service.Revoked,
|
|
}
|
|
res.Services = append(res.Services, &serviceShortDescr)
|
|
}
|
|
return res, err
|
|
}
|
|
|
|
func (lg *Logic) RevokeServicePair(ctx context.Context, userID int64, params *cmctl.RevokeServicePairParams) (*cmctl.RevokeServicePairResult, error) {
|
|
var err error
|
|
res := &cmctl.RevokeServicePairResult{}
|
|
|
|
var serviceDescr *descriptor.Service
|
|
var serviceExists bool
|
|
switch {
|
|
case params.ServiceID != 0:
|
|
serviceExists, serviceDescr, err = lg.db.GetServiceByID(ctx, params.ServiceID)
|
|
if !serviceExists {
|
|
err := fmt.Errorf("No signer with id %d was found", params.ServiceID)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
case params.ServiceName != "":
|
|
serviceExists, serviceDescr, err = lg.db.GetServiceByName(ctx, params.ServiceName)
|
|
if !serviceExists {
|
|
err := fmt.Errorf("No signer with name %s was found", params.ServiceName)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
default:
|
|
err := fmt.Errorf("Service ID or name is not specified")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
if serviceDescr == nil {
|
|
err := fmt.Errorf("Service descriptor is nil")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
if !serviceDescr.Revoked {
|
|
serviceDescr.Revoked = true
|
|
err = lg.db.UpdateServiceByID(ctx, serviceDescr.ID, serviceDescr)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
return res, err
|
|
}
|
|
|
|
func (lg *Logic) UnrevokeServicePair(ctx context.Context, userID int64, params *cmctl.UnrevokeServicePairParams) (*cmctl.UnrevokeServicePairResult, error) {
|
|
var err error
|
|
res := &cmctl.UnrevokeServicePairResult{}
|
|
|
|
var serviceDescr *descriptor.Service
|
|
var serviceExists bool
|
|
switch {
|
|
case params.ServiceID != 0:
|
|
serviceExists, serviceDescr, err = lg.db.GetServiceByID(ctx, params.ServiceID)
|
|
if !serviceExists {
|
|
err := fmt.Errorf("No signer with id %d was found", params.ServiceID)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
case params.ServiceName != "":
|
|
serviceExists, serviceDescr, err = lg.db.GetServiceByName(ctx, params.ServiceName)
|
|
if !serviceExists {
|
|
err := fmt.Errorf("No signer with name %s was found", params.ServiceName)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
default:
|
|
err := fmt.Errorf("Service ID or name is not specified")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
if serviceDescr == nil {
|
|
err := fmt.Errorf("Service descriptor is nil")
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
if serviceDescr.Revoked {
|
|
serviceDescr.Revoked = false
|
|
err = lg.db.UpdateServiceByID(ctx, serviceDescr.ID, serviceDescr)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
}
|
|
return res, err
|
|
}
|