github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/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.KeyUsageCertSign | x509.KeyUsageCRLSign
    61  				template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageAny, x509.ExtKeyUsageServerAuth}
    62  
    63  				//set the organization for the subject
    64  				subject := subjectTemplate()
    65  				subject.Organization = []string{org}
    66  				subject.CommonName = name
    67  
    68  				template.Subject = subject
    69  				template.SubjectKeyId = priv.SKI()
    70  
    71  				x509Cert, err := genCertificateECDSA(baseDir, name, &template, &template,
    72  					ecPubKey, signer)
    73  				response = err
    74  				if err == nil {
    75  					ca = &CA{
    76  						Name:     name,
    77  						Signer:   signer,
    78  						SignCert: x509Cert,
    79  					}
    80  				}
    81  			}
    82  		}
    83  	}
    84  	return ca, response
    85  }
    86  
    87  // SignCertificate creates a signed certificate based on a built-in template
    88  // and saves it in baseDir/name
    89  func (ca *CA) SignCertificate(baseDir, name string, sans []string, pub *ecdsa.PublicKey) (*x509.Certificate, error) {
    90  
    91  	template := x509Template()
    92  	template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
    93  
    94  	//set the organization for the subject
    95  	subject := subjectTemplate()
    96  	subject.CommonName = name
    97  
    98  	template.Subject = subject
    99  	template.DNSNames = sans
   100  
   101  	cert, err := genCertificateECDSA(baseDir, name, &template, ca.SignCert,
   102  		pub, ca.Signer)
   103  
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  
   108  	return cert, nil
   109  }
   110  
   111  // default template for X509 subject
   112  func subjectTemplate() pkix.Name {
   113  	return pkix.Name{
   114  		Country:  []string{"US"},
   115  		Locality: []string{"San Francisco"},
   116  		Province: []string{"California"},
   117  	}
   118  }
   119  
   120  // default template for X509 certificates
   121  func x509Template() x509.Certificate {
   122  
   123  	//generate a serial number
   124  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
   125  	serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
   126  
   127  	now := time.Now()
   128  	//basic template to use
   129  	x509 := x509.Certificate{
   130  		SerialNumber:          serialNumber,
   131  		NotBefore:             now,
   132  		NotAfter:              now.Add(3650 * 24 * time.Hour), //~ten years
   133  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
   134  		BasicConstraintsValid: true,
   135  	}
   136  	return x509
   137  
   138  }
   139  
   140  // generate a signed X509 certficate using ECDSA
   141  func genCertificateECDSA(baseDir, name string, template, parent *x509.Certificate, pub *ecdsa.PublicKey,
   142  	priv interface{}) (*x509.Certificate, error) {
   143  
   144  	//create the x509 public cert
   145  	certBytes, err := x509.CreateCertificate(rand.Reader, template, parent, pub, priv)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	//write cert out to file
   151  	fileName := filepath.Join(baseDir, name+"-cert.pem")
   152  	certFile, err := os.Create(fileName)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  	//pem encode the cert
   157  	err = pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})
   158  	certFile.Close()
   159  	if err != nil {
   160  		return nil, err
   161  	}
   162  
   163  	x509Cert, err := x509.ParseCertificate(certBytes)
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  	return x509Cert, nil
   168  }