Files
certmanager/internal/logic/issuer.go
Олег Бородин 7a267cdc4d update
2024-09-14 07:49:45 +02:00

431 lines
11 KiB
Go

package logic
import (
"context"
"crypto/sha256"
"fmt"
"time"
"certmanager/internal/descriptor"
"certmanager/pkg/auxid"
"certmanager/pkg/cm509"
"certmanager/pkg/cmctl"
)
func (lg *Logic) CreateIssuerPair(ctx context.Context, accountID int64, params *cmctl.CreateIssuerPairParams) (*cmctl.CreateIssuerPairResult, error) {
var err error
res := &cmctl.CreateIssuerPairResult{}
grantExists, _, err := lg.db.GetGrant(ctx, accountID, descriptor.GrantModifyUssuers)
if err != nil {
return res, err
}
if !grantExists {
err := fmt.Errorf("Operation not allowed for the user")
return res, err
}
if params.IssuerCommonName == "" {
err := fmt.Errorf("No common name specified")
return res, err
}
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
}
}
}
newIssuerID := auxid.GenID()
createIssuerPairParams := &cm509.CreateIssuerPairParams{
CommonName: params.IssuerCommonName,
OrganizationName: params.IssuerOrganizationName,
OrganizationalUnitName: params.IssuerOrganizationalUnitName,
SerialNumber: newIssuerID,
}
if signerDescr != nil {
err = cm509.DoubleEncodedCertKeyMatch(signerDescr.Cert, signerDescr.Key)
if err != nil {
return res, err
}
lg.log.Debugf("Create issuer with signer name %s", signerDescr.Name)
createIssuerPairParams.SignerCert = signerDescr.Cert
createIssuerPairParams.SignerKey = signerDescr.Key
}
createIssuerPairRes, err := cm509.CreateIssuerPair(createIssuerPairParams)
if err != nil {
return res, err
}
issuerDescr := &descriptor.Issuer{
ID: newIssuerID,
Name: createIssuerPairRes.Name,
Cert: createIssuerPairRes.Cert,
Key: createIssuerPairRes.Key,
}
if signerDescr != nil {
issuerDescr.SignerName = signerDescr.Name
issuerDescr.SignerID = signerDescr.ID
} else {
issuerDescr.SignerName = issuerDescr.Name
issuerDescr.SignerID = issuerDescr.ID
}
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
}
}
issuerCertObj, err := cm509.ParseDoubleEncodedCerificate(createIssuerPairRes.Cert)
if err != nil {
return res, err
}
fingerprintBytes := sha256.Sum256(issuerCertObj.Raw)
fingerprint := fmt.Sprintf("sha256:%x", fingerprintBytes)
if signerExists {
signerDescrs, err := lg.GetIssuerChain(ctx, issuerDescr.SignerID)
if err != nil {
return res, err
}
for _, signerDescr := range signerDescrs {
res.SignerCertificates = append(res.SignerCertificates, signerDescr.Cert)
res.SignerNames = append(res.SignerNames, signerDescr.Name)
}
}
err = lg.db.InsertIssuer(ctx, issuerDescr)
if err != nil {
return res, err
}
encodedKey, err := cm509.EncryptAES256(createIssuerPairRes.Key, params.EncodingKey)
if err != nil {
return res, err
}
res.Fingerprint = fingerprint
res.IssuerID = issuerDescr.ID
res.IssuerName = createIssuerPairRes.Name
res.Certificate = createIssuerPairRes.Cert
res.EncodedKey = encodedKey
return res, err
}
func (lg *Logic) GetIssuerCertificate(ctx context.Context, accountID int64, params *cmctl.GetIssuerCertificateParams) (*cmctl.GetIssuerCertificateResult, error) {
var err error
res := &cmctl.GetIssuerCertificateResult{
SignerCertificates: make([]string, 0),
SignerNames: make([]string, 0),
}
grantExists, _, err := lg.db.GetGrant(ctx, accountID, descriptor.GrantModifyUssuers)
if err != nil {
return res, err
}
if !grantExists {
err := fmt.Errorf("Operation not allowed for the user")
return res, err
}
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 this ID was found")
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 this common name was found")
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
}
}
signerDescrs, err := lg.GetIssuerChain(ctx, issuerDescr.SignerID)
if err != nil {
return res, err
}
for _, signerDescr := range signerDescrs {
res.SignerCertificates = append(res.SignerCertificates, signerDescr.Cert)
res.SignerNames = append(res.SignerNames, signerDescr.Name)
}
err = cm509.DoubleEncodedCertKeyMatch(issuerDescr.Cert, issuerDescr.Key)
if err != nil {
return res, err
}
issuerCertObj, err := cm509.ParseDoubleEncodedCerificate(issuerDescr.Cert)
if err != nil {
return res, err
}
fingerprintBytes := sha256.Sum256(issuerCertObj.Raw)
fingerprint := fmt.Sprintf("sha256:%x", fingerprintBytes)
var encodedKey string
if params.EncodingKey != "" {
encodedKey, err = cm509.EncryptAES256(issuerDescr.Key, params.EncodingKey)
if err != nil {
return res, err
}
}
res.IssuerID = issuerDescr.ID
res.Certificate = issuerDescr.Cert
res.EncodedKey = encodedKey
res.Name = issuerDescr.Name
res.Revoked = issuerDescr.Revoked
res.Fingerprint = fingerprint
return res, err
}
func (lg *Logic) ImportIssuerPair(ctx context.Context, accountID int64, params *cmctl.ImportIssuerPairParams) (*cmctl.ImportIssuerPairResult, error) {
var err error
res := &cmctl.ImportIssuerPairResult{}
grantExists, _, err := lg.db.GetGrant(ctx, accountID, descriptor.GrantModifyUssuers)
if err != nil {
return res, err
}
if !grantExists {
err := fmt.Errorf("Operation not allowed for the user")
return res, err
}
if params.Certificate == "" {
err := fmt.Errorf("Empty issuer cerificata data")
return res, err
}
cert, err := cm509.ParseDoubleEncodedCerificate(params.Certificate)
if err != nil {
return res, err
}
if !cert.IsCA {
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 = cm509.ParseDoubleEncodedKey(params.Key)
if err != nil {
return res, err
}
certSubjectCN := cert.Subject.String()
certIssuerCN := cert.Issuer.String()
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{
ID: auxid.GenID(),
Name: intermCertObj.Issuer.String(),
Cert: intermCertString,
Key: "",
}
err = lg.db.InsertIssuer(ctx, issuerDescr)
if err != nil {
return res, err
}
}
}
issuerDescr := &descriptor.Issuer{
ID: auxid.GenID(),
Name: cert.Issuer.String(),
Cert: params.Certificate,
Key: params.Key,
}
err = lg.db.InsertIssuer(ctx, issuerDescr)
if err != nil {
return res, err
}
res.IssuerName = cert.Subject.String()
res.IssuerID = issuerDescr.ID
return res, err
}
func (lg *Logic) RevokeIssuerPair(ctx context.Context, accountID int64, params *cmctl.RevokeIssuerPairParams) (*cmctl.RevokeIssuerPairResult, error) {
var err error
res := &cmctl.RevokeIssuerPairResult{}
grantExists, _, err := lg.db.GetGrant(ctx, accountID, descriptor.GrantModifyUssuers)
if err != nil {
return res, err
}
if !grantExists {
err := fmt.Errorf("Operation not allowed for the user")
return res, err
}
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 this ID was found")
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 this common name was found")
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 {
issuerDescr.Revoked = true
err = lg.db.UpdateIssuerByID(ctx, issuerDescr.ID, issuerDescr)
if err != nil {
return res, err
}
}
return res, err
}
func (lg *Logic) UnrevokeIssuerPair(ctx context.Context, accountID int64, params *cmctl.UnrevokeIssuerPairParams) (*cmctl.UnrevokeIssuerPairResult, error) {
var err error
res := &cmctl.UnrevokeIssuerPairResult{}
grantExists, _, err := lg.db.GetGrant(ctx, accountID, descriptor.GrantModifyUssuers)
if err != nil {
return res, err
}
if !grantExists {
err := fmt.Errorf("Operation not allowed for the user")
return res, err
}
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 this ID was found")
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 this common name was found")
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 {
issuerDescr.Revoked = false
err = lg.db.UpdateIssuerByID(ctx, issuerDescr.ID, issuerDescr)
if err != nil {
return res, err
}
}
return res, err
}
func (lg *Logic) ListIssuerPairs(ctx context.Context, accountID int64, params *cmctl.ListIssuerPairsParams) (*cmctl.ListIssuerPairsResult, error) {
var err error
res := &cmctl.ListIssuerPairsResult{
Issuers: make([]*cmctl.IssierShortDescriptor, 0),
}
listIssuers, err := lg.db.ListIssuers(ctx)
if err != nil {
return res, err
}
for _, issuer := range listIssuers {
issuerShortDescr := cmctl.IssierShortDescriptor{
IssuerID: issuer.ID,
Name: issuer.Name,
SignerID: issuer.SignerID,
SignerName: issuer.SignerName,
Revoked: issuer.Revoked,
}
res.Issuers = append(res.Issuers, &issuerShortDescr)
}
return res, err
}