github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/cryptogen/msp/msp.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 package msp 7 8 import ( 9 "crypto/x509" 10 "encoding/pem" 11 "os" 12 "path/filepath" 13 14 "github.com/hechain20/hechain/internal/cryptogen/ca" 15 "github.com/hechain20/hechain/internal/cryptogen/csp" 16 fabricmsp "github.com/hechain20/hechain/msp" 17 "github.com/pkg/errors" 18 "gopkg.in/yaml.v2" 19 ) 20 21 const ( 22 CLIENT = iota 23 ORDERER 24 PEER 25 ADMIN 26 ) 27 28 const ( 29 CLIENTOU = "client" 30 PEEROU = "peer" 31 ADMINOU = "admin" 32 ORDEREROU = "orderer" 33 ) 34 35 var nodeOUMap = map[int]string{ 36 CLIENT: CLIENTOU, 37 PEER: PEEROU, 38 ADMIN: ADMINOU, 39 ORDERER: ORDEREROU, 40 } 41 42 func GenerateLocalMSP( 43 baseDir, 44 name string, 45 sans []string, 46 signCA *ca.CA, 47 tlsCA *ca.CA, 48 nodeType int, 49 nodeOUs bool, 50 ) error { 51 // create folder structure 52 mspDir := filepath.Join(baseDir, "msp") 53 tlsDir := filepath.Join(baseDir, "tls") 54 55 err := createFolderStructure(mspDir, true) 56 if err != nil { 57 return err 58 } 59 60 err = os.MkdirAll(tlsDir, 0o755) 61 if err != nil { 62 return err 63 } 64 65 /* 66 Create the MSP identity artifacts 67 */ 68 // get keystore path 69 keystore := filepath.Join(mspDir, "keystore") 70 71 // generate private key 72 priv, err := csp.GeneratePrivateKey(keystore) 73 if err != nil { 74 return err 75 } 76 77 // generate X509 certificate using signing CA 78 var ous []string 79 if nodeOUs { 80 ous = []string{nodeOUMap[nodeType]} 81 } 82 cert, err := signCA.SignCertificate( 83 filepath.Join(mspDir, "signcerts"), 84 name, 85 ous, 86 nil, 87 &priv.PublicKey, 88 x509.KeyUsageDigitalSignature, 89 []x509.ExtKeyUsage{}, 90 ) 91 if err != nil { 92 return err 93 } 94 95 // write artifacts to MSP folders 96 97 // the signing CA certificate goes into cacerts 98 err = x509Export( 99 filepath.Join(mspDir, "cacerts", x509Filename(signCA.Name)), 100 signCA.SignCert, 101 ) 102 if err != nil { 103 return err 104 } 105 // the TLS CA certificate goes into tlscacerts 106 err = x509Export( 107 filepath.Join(mspDir, "tlscacerts", x509Filename(tlsCA.Name)), 108 tlsCA.SignCert, 109 ) 110 if err != nil { 111 return err 112 } 113 114 // generate config.yaml if required 115 if nodeOUs { 116 exportConfig(mspDir, filepath.Join("cacerts", x509Filename(signCA.Name)), true) 117 } 118 119 // the signing identity goes into admincerts. 120 // This means that the signing identity 121 // of this MSP is also an admin of this MSP 122 // NOTE: the admincerts folder is going to be 123 // cleared up anyway by copyAdminCert, but 124 // we leave a valid admin for now for the sake 125 // of unit tests 126 if !nodeOUs { 127 err = x509Export(filepath.Join(mspDir, "admincerts", x509Filename(name)), cert) 128 if err != nil { 129 return err 130 } 131 } 132 133 /* 134 Generate the TLS artifacts in the TLS folder 135 */ 136 137 // generate private key 138 tlsPrivKey, err := csp.GeneratePrivateKey(tlsDir) 139 if err != nil { 140 return err 141 } 142 143 // generate X509 certificate using TLS CA 144 _, err = tlsCA.SignCertificate( 145 filepath.Join(tlsDir), 146 name, 147 nil, 148 sans, 149 &tlsPrivKey.PublicKey, 150 x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment, 151 []x509.ExtKeyUsage{ 152 x509.ExtKeyUsageServerAuth, 153 x509.ExtKeyUsageClientAuth, 154 }, 155 ) 156 if err != nil { 157 return err 158 } 159 err = x509Export(filepath.Join(tlsDir, "ca.crt"), tlsCA.SignCert) 160 if err != nil { 161 return err 162 } 163 164 // rename the generated TLS X509 cert 165 tlsFilePrefix := "server" 166 if nodeType == CLIENT || nodeType == ADMIN { 167 tlsFilePrefix = "client" 168 } 169 err = os.Rename(filepath.Join(tlsDir, x509Filename(name)), 170 filepath.Join(tlsDir, tlsFilePrefix+".crt")) 171 if err != nil { 172 return err 173 } 174 175 err = keyExport(tlsDir, filepath.Join(tlsDir, tlsFilePrefix+".key")) 176 if err != nil { 177 return err 178 } 179 180 return nil 181 } 182 183 func GenerateVerifyingMSP( 184 baseDir string, 185 signCA, 186 tlsCA *ca.CA, 187 nodeOUs bool, 188 ) error { 189 // create folder structure and write artifacts to proper locations 190 err := createFolderStructure(baseDir, false) 191 if err != nil { 192 return err 193 } 194 // the signing CA certificate goes into cacerts 195 err = x509Export( 196 filepath.Join(baseDir, "cacerts", x509Filename(signCA.Name)), 197 signCA.SignCert, 198 ) 199 if err != nil { 200 return err 201 } 202 // the TLS CA certificate goes into tlscacerts 203 err = x509Export( 204 filepath.Join(baseDir, "tlscacerts", x509Filename(tlsCA.Name)), 205 tlsCA.SignCert, 206 ) 207 if err != nil { 208 return err 209 } 210 211 // generate config.yaml if required 212 if nodeOUs { 213 exportConfig(baseDir, "cacerts/"+x509Filename(signCA.Name), true) 214 } 215 216 // create a throwaway cert to act as an admin cert 217 // NOTE: the admincerts folder is going to be 218 // cleared up anyway by copyAdminCert, but 219 // we leave a valid admin for now for the sake 220 // of unit tests 221 if nodeOUs { 222 return nil 223 } 224 225 ksDir := filepath.Join(baseDir, "keystore") 226 err = os.Mkdir(ksDir, 0o755) 227 defer os.RemoveAll(ksDir) 228 if err != nil { 229 return errors.WithMessage(err, "failed to create keystore directory") 230 } 231 priv, err := csp.GeneratePrivateKey(ksDir) 232 if err != nil { 233 return err 234 } 235 _, err = signCA.SignCertificate( 236 filepath.Join(baseDir, "admincerts"), 237 signCA.Name, 238 nil, 239 nil, 240 &priv.PublicKey, 241 x509.KeyUsageDigitalSignature, 242 []x509.ExtKeyUsage{}, 243 ) 244 if err != nil { 245 return err 246 } 247 248 return nil 249 } 250 251 func createFolderStructure(rootDir string, local bool) error { 252 var folders []string 253 // create admincerts, cacerts, keystore and signcerts folders 254 folders = []string{ 255 filepath.Join(rootDir, "admincerts"), 256 filepath.Join(rootDir, "cacerts"), 257 filepath.Join(rootDir, "tlscacerts"), 258 } 259 if local { 260 folders = append(folders, filepath.Join(rootDir, "keystore"), 261 filepath.Join(rootDir, "signcerts")) 262 } 263 264 for _, folder := range folders { 265 err := os.MkdirAll(folder, 0o755) 266 if err != nil { 267 return err 268 } 269 } 270 271 return nil 272 } 273 274 func x509Filename(name string) string { 275 return name + "-cert.pem" 276 } 277 278 func x509Export(path string, cert *x509.Certificate) error { 279 return pemExport(path, "CERTIFICATE", cert.Raw) 280 } 281 282 func keyExport(keystore, output string) error { 283 return os.Rename(filepath.Join(keystore, "priv_sk"), output) 284 } 285 286 func pemExport(path, pemType string, bytes []byte) error { 287 // write pem out to file 288 file, err := os.Create(path) 289 if err != nil { 290 return err 291 } 292 defer file.Close() 293 294 return pem.Encode(file, &pem.Block{Type: pemType, Bytes: bytes}) 295 } 296 297 func exportConfig(mspDir, caFile string, enable bool) error { 298 config := &fabricmsp.Configuration{ 299 NodeOUs: &fabricmsp.NodeOUs{ 300 Enable: enable, 301 ClientOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{ 302 Certificate: caFile, 303 OrganizationalUnitIdentifier: CLIENTOU, 304 }, 305 PeerOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{ 306 Certificate: caFile, 307 OrganizationalUnitIdentifier: PEEROU, 308 }, 309 AdminOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{ 310 Certificate: caFile, 311 OrganizationalUnitIdentifier: ADMINOU, 312 }, 313 OrdererOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{ 314 Certificate: caFile, 315 OrganizationalUnitIdentifier: ORDEREROU, 316 }, 317 }, 318 } 319 320 configBytes, err := yaml.Marshal(config) 321 if err != nil { 322 return err 323 } 324 325 file, err := os.Create(filepath.Join(mspDir, "config.yaml")) 326 if err != nil { 327 return err 328 } 329 330 defer file.Close() 331 _, err = file.WriteString(string(configBytes)) 332 333 return err 334 }