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 }