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