120 lines
3.5 KiB
Go
120 lines
3.5 KiB
Go
/*
|
|
* Copyright 2022 The Dragonfly Authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package issuer
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"math/big"
|
|
"time"
|
|
|
|
"github.com/johanbrandhorst/certify"
|
|
|
|
logger "d7y.io/dragonfly/v2/internal/dflog"
|
|
)
|
|
|
|
const (
|
|
// defaultManagerValidityPeriod is default manager validity period of certificate.
|
|
defaultManagerValidityPeriod = 10 * 365 * 24 * time.Hour
|
|
)
|
|
|
|
// dragonflyManagerIssuer provides manager issuer function.
|
|
type dragonflyManagerIssuer struct {
|
|
tlsCACert *tls.Certificate
|
|
validityPeriod time.Duration
|
|
}
|
|
|
|
// ManagerOption is a functional option for configuring the dragonflyManagerIssuer.
|
|
type ManagerOption func(i *dragonflyManagerIssuer)
|
|
|
|
// WithManagerValidityPeriod set the manager validityPeriod for dragonflyManagerIssuer.
|
|
func WithManagerValidityPeriod(d time.Duration) ManagerOption {
|
|
return func(i *dragonflyManagerIssuer) {
|
|
i.validityPeriod = d
|
|
}
|
|
}
|
|
|
|
// NewDragonflyManagerIssuer returns a new certify.Issuer instence.
|
|
func NewDragonflyManagerIssuer(tlsCACert *tls.Certificate, opts ...ManagerOption) certify.Issuer {
|
|
i := &dragonflyManagerIssuer{
|
|
tlsCACert: tlsCACert,
|
|
validityPeriod: defaultManagerValidityPeriod,
|
|
}
|
|
|
|
for _, opt := range opts {
|
|
opt(i)
|
|
}
|
|
|
|
return i
|
|
}
|
|
|
|
// Issue returns tls Certificate of issuing.
|
|
func (i *dragonflyManagerIssuer) Issue(ctx context.Context, commonName string, certConfig *certify.CertConfig) (*tls.Certificate, error) {
|
|
x509CACert, err := x509.ParseCertificate(i.tlsCACert.Certificate[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pk, err := rsa.GenerateKey(rand.Reader, 4096)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
serial, err := rand.Int(rand.Reader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
now := time.Now()
|
|
template := x509.Certificate{
|
|
SerialNumber: serial,
|
|
Subject: pkix.Name{
|
|
CommonName: commonName,
|
|
Organization: defaultSubjectOrganization,
|
|
},
|
|
DNSNames: certConfig.SubjectAlternativeNames,
|
|
IPAddresses: certConfig.IPSubjectAlternativeNames,
|
|
URIs: certConfig.URISubjectAlternativeNames,
|
|
NotBefore: now.Add(-10 * time.Minute).UTC(),
|
|
NotAfter: now.Add(i.validityPeriod).UTC(),
|
|
BasicConstraintsValid: true,
|
|
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageDataEncipherment | x509.KeyUsageKeyEncipherment,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
|
}
|
|
|
|
cert, err := x509.CreateCertificate(rand.Reader, &template, x509CACert, &pk.PublicKey, i.tlsCACert.PrivateKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
leaf, err := x509.ParseCertificate(cert)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
logger.Debugf("issue certificate from manager, common name: %s, issuer: %s", commonName, leaf.Issuer.CommonName)
|
|
|
|
return &tls.Certificate{
|
|
Certificate: append([][]byte{cert}, i.tlsCACert.Certificate...),
|
|
PrivateKey: pk,
|
|
Leaf: leaf,
|
|
}, nil
|
|
}
|