github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/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  	now := time.Now()
   132  	//basic template to use
   133  	x509 := x509.Certificate{
   134  		SerialNumber:          serialNumber,
   135  		NotBefore:             now,
   136  		NotAfter:              now.Add(3650 * 24 * time.Hour), //~ten years
   137  		BasicConstraintsValid: true,
   138  	}
   139  	return x509
   140  
   141  }
   142  
   143  // generate a signed X509 certficate using ECDSA
   144  func genCertificateECDSA(baseDir, name string, template, parent *x509.Certificate, pub *ecdsa.PublicKey,
   145  	priv interface{}) (*x509.Certificate, error) {
   146  
   147  	//create the x509 public cert
   148  	certBytes, err := x509.CreateCertificate(rand.Reader, template, parent, pub, priv)
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  
   153  	//write cert out to file
   154  	fileName := filepath.Join(baseDir, name+"-cert.pem")
   155  	certFile, err := os.Create(fileName)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  	//pem encode the cert
   160  	err = pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})
   161  	certFile.Close()
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  
   166  	x509Cert, err := x509.ParseCertificate(certBytes)
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  	return x509Cert, nil
   171  }