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 }