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 }