dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/credentials/certgenerate/generate_csr.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  /*
    19   *
    20   * Copyright Istio Authors
    21   *
    22   */
    23  
    24  package certgenerate
    25  
    26  import (
    27  	"crypto"
    28  	"crypto/ecdsa"
    29  	"crypto/elliptic"
    30  	"crypto/rand"
    31  	"crypto/rsa"
    32  	"crypto/x509"
    33  	"crypto/x509/pkix"
    34  	"errors"
    35  	"fmt"
    36  	"os"
    37  	"strings"
    38  
    39  	"github.com/dubbogo/gost/log/logger"
    40  )
    41  
    42  // minimumRsaKeySize is the minimum RSA key size to generate certificates
    43  // to ensure proper security
    44  const minimumRsaKeySize = 2048
    45  
    46  // GenCSR generates a X.509 certificate sign request and private key with the given options.
    47  func GenCSR(options CertOptions) ([]byte, []byte, error) {
    48  	var priv interface{}
    49  	var err error
    50  	if options.ECSigAlg != "" {
    51  		switch options.ECSigAlg {
    52  		case EcdsaSigAlg:
    53  			priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    54  			if err != nil {
    55  				return nil, nil, fmt.Errorf("EC key generation failed (%v)", err)
    56  			}
    57  		default:
    58  			return nil, nil, errors.New("csr cert generation fails due to unsupported EC signature algorithm")
    59  		}
    60  	} else {
    61  		if options.RSAKeySize < minimumRsaKeySize {
    62  			return nil, nil, fmt.Errorf("requested key size does not meet the minimum requied size of %d (requested: %d)", minimumRsaKeySize, options.RSAKeySize)
    63  		}
    64  
    65  		priv, err = rsa.GenerateKey(rand.Reader, options.RSAKeySize)
    66  		if err != nil {
    67  			return nil, nil, fmt.Errorf("RSA key generation failed (%v)", err)
    68  		}
    69  	}
    70  	template, err := GenCSRTemplate(options)
    71  	if err != nil {
    72  		return nil, nil, fmt.Errorf("CSR template creation failed (%v)", err)
    73  	}
    74  
    75  	csrBytes, err := x509.CreateCertificateRequest(rand.Reader, template, crypto.PrivateKey(priv))
    76  	if err != nil {
    77  		return nil, nil, fmt.Errorf("CSR creation failed (%v)", err)
    78  	}
    79  
    80  	csr, privKey, err := encodePem(true, csrBytes, priv, options.PKCS8Key)
    81  	return csr, privKey, err
    82  }
    83  
    84  // GenCSRTemplate generates a certificateRequest template with the given options.
    85  func GenCSRTemplate(options CertOptions) (*x509.CertificateRequest, error) {
    86  	template := &x509.CertificateRequest{
    87  		Subject: pkix.Name{
    88  			Organization: []string{options.Org},
    89  		},
    90  	}
    91  
    92  	if h := options.Host; len(h) > 0 {
    93  		s, err := BuildSubjectAltNameExtension(h)
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  		if options.IsDualUse {
    98  			cn, err := DualUseCommonName(h)
    99  			if err != nil {
   100  				// logger and continue
   101  				//logger.Errorf("dual-use failed for CSR template - omitting CN (%v)", err)
   102  			} else {
   103  				template.Subject.CommonName = cn
   104  			}
   105  		}
   106  		template.ExtraExtensions = []pkix.Extension{*s}
   107  	}
   108  
   109  	return template, nil
   110  }
   111  
   112  // AppendRootCerts appends root certificates in RootCertFile to the input certificate.
   113  func AppendRootCerts(pemCert []byte, rootCertFile string) ([]byte, error) {
   114  	rootCerts := pemCert
   115  	if len(rootCertFile) > 0 {
   116  		logger.Debugf("append root certificates from %v", rootCertFile)
   117  		certBytes, err := os.ReadFile(rootCertFile)
   118  		if err != nil {
   119  			return rootCerts, fmt.Errorf("failed to read root certificates (%v)", err)
   120  		}
   121  		rootCerts = AppendCertByte(pemCert, certBytes)
   122  	}
   123  	return rootCerts, nil
   124  }
   125  
   126  // AppendCertByte: Append x.509 rootCert in bytes to existing certificate chain (in bytes)
   127  func AppendCertByte(pemCert []byte, rootCert []byte) []byte {
   128  	rootCerts := []byte{}
   129  	if len(pemCert) > 0 {
   130  		// Copy the input certificate
   131  		rootCerts = []byte(strings.TrimSuffix(string(pemCert), "\n") + "\n")
   132  	}
   133  	rootCerts = append(rootCerts, rootCert...)
   134  	return rootCerts
   135  }