github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/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, 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{name}
    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, pub *ecdsa.PublicKey) 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  
   100  	_, err := genCertificateECDSA(baseDir, name, &template, ca.SignCert,
   101  		pub, ca.Signer)
   102  
   103  	if err != nil {
   104  		return err
   105  	}
   106  
   107  	return nil
   108  }
   109  
   110  // default template for X509 subject
   111  func subjectTemplate() pkix.Name {
   112  	return pkix.Name{
   113  		Country:  []string{"US"},
   114  		Locality: []string{"San Francisco"},
   115  		Province: []string{"California"},
   116  	}
   117  }
   118  
   119  // default template for X509 certificates
   120  func x509Template() x509.Certificate {
   121  
   122  	//generate a serial number
   123  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
   124  	serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
   125  
   126  	now := time.Now()
   127  	//basic template to use
   128  	x509 := x509.Certificate{
   129  		SerialNumber:          serialNumber,
   130  		NotBefore:             now,
   131  		NotAfter:              now.Add(3650 * 24 * time.Hour), //~ten years
   132  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
   133  		BasicConstraintsValid: true,
   134  	}
   135  	return x509
   136  
   137  }
   138  
   139  // generate a signed X509 certficate using ECDSA
   140  func genCertificateECDSA(baseDir, name string, template, parent *x509.Certificate, pub *ecdsa.PublicKey,
   141  	priv interface{}) (*x509.Certificate, error) {
   142  
   143  	//create the x509 public cert
   144  	certBytes, err := x509.CreateCertificate(rand.Reader, template, parent, pub, priv)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	//write cert out to file
   150  	fileName := filepath.Join(baseDir, name+"-cert.pem")
   151  	certFile, err := os.Create(fileName)
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  	//pem encode the cert
   156  	err = pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})
   157  	certFile.Close()
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  
   162  	x509Cert, err := x509.ParseCertificate(certBytes)
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	return x509Cert, nil
   167  }