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 }