pkg/common/utils/certificate/certificate.go (86 lines of code) (raw):

// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you 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 certificate import ( "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "errors" "k8s.io/klog/v2" "math/big" "time" ) var ( // SerialNumberLimit is the maximum number used as a certificate serial number SerialNumberLimit = new(big.Int).Lsh(big.NewInt(1), 128) DefaultExpireTimeout = 365 * 24 * time.Hour UpdateCABefore = 10 * time.Minute ) var ( Cert_Type = "CERTIFICATE" PrivateKey_Type = "RSA PRIVATE KEY" ) type CAOptions struct { //Subject of location information to build. Subject pkix.Name //privateKey to be used for signing certificates(auto generated if not provided) PrivateKey *rsa.PrivateKey //all fully dns name for certificate. DnsNames []string } type CA struct { //PrivateKey is the unnamedwatches private key privateKey []byte //the encoded certificate. cert []byte //the struct of privateKey. PrivateKey *rsa.PrivateKey // the certificate used to issue new certificates Certificate *x509.Certificate } // create CA according to the options. func NewCAConfigSecret(options CAOptions) (*CA, error) { serial, err := rand.Int(rand.Reader, SerialNumberLimit) if err != nil { return nil, errors.New("new CA failed, " + err.Error()) } pk, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return nil, errors.New("generate key failed, " + err.Error()) } certificate := &x509.Certificate{ SerialNumber: serial, Subject: options.Subject, NotBefore: time.Now().Add(-10 * time.Minute), NotAfter: time.Now().Add(DefaultExpireTimeout), DNSNames: options.DnsNames, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, KeyUsage: x509.KeyUsageDigitalSignature, BasicConstraintsValid: true, } cert, err := x509.CreateCertificate(rand.Reader, certificate, certificate, &pk.PublicKey, pk) if err != nil { return nil, errors.New("failed to create certificate, " + err.Error()) } return &CA{ privateKey: pemEncode(PrivateKey_Type, x509.MarshalPKCS1PrivateKey(pk)), cert: pemEncode(Cert_Type, cert), PrivateKey: pk, Certificate: certificate, }, nil } // return the encode signed key. func (ca *CA) GetEncodePrivateKey() []byte { return ca.privateKey } // return the encode signed certificate. func (ca *CA) GetEncodeCert() []byte { return ca.cert } func pemEncode(asType string, data []byte) []byte { return pem.EncodeToMemory(&pem.Block{Type: asType, Bytes: data}) } // check the CA is still valid. privateKey convert to publickey equals to config publickey, the certificate is not expired. func ValidCA(ca *CA) bool { //privatekey match publickey k := ca.Certificate.PublicKey.(*rsa.PublicKey) if !k.Equal(ca.PrivateKey.Public()) { return false } now := time.Now() if now.Before(ca.Certificate.NotBefore) { klog.Infof("CA cert is not valid yet, subject %s.", ca.Certificate.Subject) return false } if now.After(ca.Certificate.NotAfter.Add(-UpdateCABefore)) { return false } return true }