github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/common/tools/cryptogen/ca/generator.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  package ca
    17  
    18  import (
    19  	"crypto"
    20  	"crypto/ecdsa"
    21  	"crypto/rand"
    22  	"crypto/x509"
    23  	"crypto/x509/pkix"
    24  	"encoding/pem"
    25  	"math/big"
    26  	"os"
    27  	"time"
    28  
    29  	"path/filepath"
    30  
    31  	"github.com/hyperledger/fabric/common/tools/cryptogen/csp"
    32  )
    33  
    34  type CA struct {
    35  	Name string
    36  	//SignKey  *ecdsa.PrivateKey
    37  	Signer   crypto.Signer
    38  	SignCert *x509.Certificate
    39  }
    40  
    41  // NewCA creates an instance of CA and saves the signing key pair in
    42  // baseDir/name
    43  func NewCA(baseDir, org, name string) (*CA, error) {
    44  
    45  	var response error
    46  	var ca *CA
    47  
    48  	err := os.MkdirAll(baseDir, 0755)
    49  	if err == nil {
    50  		priv, signer, err := csp.GeneratePrivateKey(baseDir)
    51  		response = err
    52  		if err == nil {
    53  			// get public signing certificate
    54  			ecPubKey, err := csp.GetECPublicKey(priv)
    55  			response = err
    56  			if err == nil {
    57  				template := x509Template()
    58  				//this is a CA
    59  				template.IsCA = true
    60  				template.KeyUsage |= x509.KeyUsageDigitalSignature |
    61  					x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign |
    62  					x509.KeyUsageCRLSign
    63  				template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageAny}
    64  
    65  				//set the organization for the subject
    66  				subject := subjectTemplate()
    67  				subject.Organization = []string{org}
    68  				subject.CommonName = name
    69  
    70  				template.Subject = subject
    71  				template.SubjectKeyId = priv.SKI()
    72  
    73  				x509Cert, err := genCertificateECDSA(baseDir, name, &template, &template,
    74  					ecPubKey, signer)
    75  				response = err
    76  				if err == nil {
    77  					ca = &CA{
    78  						Name:     name,
    79  						Signer:   signer,
    80  						SignCert: x509Cert,
    81  					}
    82  				}
    83  			}
    84  		}
    85  	}
    86  	return ca, response
    87  }
    88  
    89  // SignCertificate creates a signed certificate based on a built-in template
    90  // and saves it in baseDir/name
    91  func (ca *CA) SignCertificate(baseDir, name string, sans []string, pub *ecdsa.PublicKey,
    92  	ku x509.KeyUsage, eku []x509.ExtKeyUsage) (*x509.Certificate, error) {
    93  
    94  	template := x509Template()
    95  	template.KeyUsage = ku
    96  	template.ExtKeyUsage = eku
    97  
    98  	//set the organization for the subject
    99  	subject := subjectTemplate()
   100  	subject.CommonName = name
   101  
   102  	template.Subject = subject
   103  	template.DNSNames = sans
   104  
   105  	cert, err := genCertificateECDSA(baseDir, name, &template, ca.SignCert,
   106  		pub, ca.Signer)
   107  
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  
   112  	return cert, nil
   113  }
   114  
   115  // default template for X509 subject
   116  func subjectTemplate() pkix.Name {
   117  	return pkix.Name{
   118  		Country:  []string{"US"},
   119  		Locality: []string{"San Francisco"},
   120  		Province: []string{"California"},
   121  	}
   122  }
   123  
   124  // default template for X509 certificates
   125  func x509Template() x509.Certificate {
   126  
   127  	// generate a serial number
   128  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
   129  	serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
   130  
   131  	// set expiry to around 10 years
   132  	expiry := 3650 * 24 * time.Hour
   133  	// backdate 5 min
   134  	notBefore := time.Now().Add(-5 * time.Minute).UTC()
   135  
   136  	//basic template to use
   137  	x509 := x509.Certificate{
   138  		SerialNumber:          serialNumber,
   139  		NotBefore:             notBefore,
   140  		NotAfter:              notBefore.Add(expiry).UTC(),
   141  		BasicConstraintsValid: true,
   142  	}
   143  	return x509
   144  
   145  }
   146  
   147  // generate a signed X509 certficate using ECDSA
   148  func genCertificateECDSA(baseDir, name string, template, parent *x509.Certificate, pub *ecdsa.PublicKey,
   149  	priv interface{}) (*x509.Certificate, error) {
   150  
   151  	//create the x509 public cert
   152  	certBytes, err := x509.CreateCertificate(rand.Reader, template, parent, pub, priv)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  
   157  	//write cert out to file
   158  	fileName := filepath.Join(baseDir, name+"-cert.pem")
   159  	certFile, err := os.Create(fileName)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	//pem encode the cert
   164  	err = pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})
   165  	certFile.Close()
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  
   170  	x509Cert, err := x509.ParseCertificate(certBytes)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  	return x509Cert, nil
   175  }