github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/integration/msp/rsaca_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package msp 8 9 import ( 10 "crypto" 11 "crypto/ecdsa" 12 "crypto/elliptic" 13 "crypto/rand" 14 "crypto/rsa" 15 "crypto/sha256" 16 "crypto/x509" 17 "crypto/x509/pkix" 18 "encoding/pem" 19 "fmt" 20 "io/ioutil" 21 "math/big" 22 "net" 23 "os" 24 "path/filepath" 25 "syscall" 26 "time" 27 28 docker "github.com/fsouza/go-dockerclient" 29 "github.com/hechain20/hechain/integration/nwo" 30 "github.com/hechain20/hechain/integration/nwo/commands" 31 fabricmsp "github.com/hechain20/hechain/msp" 32 . "github.com/onsi/ginkgo" 33 . "github.com/onsi/gomega" 34 "github.com/onsi/gomega/gexec" 35 "github.com/tedsuo/ifrit" 36 "gopkg.in/yaml.v2" 37 ) 38 39 var _ = Describe("MSPs with RSA Certificate Authorities", func() { 40 var ( 41 client *docker.Client 42 testDir string 43 network *nwo.Network 44 process ifrit.Process 45 ) 46 47 BeforeEach(func() { 48 var err error 49 testDir, err = ioutil.TempDir("", "msp") 50 Expect(err).NotTo(HaveOccurred()) 51 52 client, err = docker.NewClientFromEnv() 53 Expect(err).NotTo(HaveOccurred()) 54 55 network = nwo.New(nwo.BasicEtcdRaft(), testDir, client, StartPort(), components) 56 network.GenerateConfigTree() 57 58 By("manually bootstrapping MSPs with RSA CAs") 59 generateRSACACrypto(network) 60 network.CreateDockerNetwork() 61 sess, err := network.ConfigTxGen(commands.OutputBlock{ 62 ChannelID: network.SystemChannel.Name, 63 Profile: network.SystemChannel.Profile, 64 ConfigPath: network.RootDir, 65 OutputBlock: network.OutputBlockPath(network.SystemChannel.Name), 66 }) 67 Expect(err).NotTo(HaveOccurred()) 68 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 69 70 for _, c := range network.Channels { 71 sess, err := network.ConfigTxGen(commands.CreateChannelTx{ 72 ChannelID: c.Name, 73 Profile: c.Profile, 74 BaseProfile: c.BaseProfile, 75 ConfigPath: network.RootDir, 76 OutputCreateChannelTx: network.CreateChannelTxPath(c.Name), 77 }) 78 Expect(err).NotTo(HaveOccurred()) 79 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 80 } 81 network.ConcatenateTLSCACertificates() 82 83 By("starting all processes for fabric") 84 networkRunner := network.NetworkGroupRunner() 85 process = ifrit.Invoke(networkRunner) 86 Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed()) 87 }) 88 89 AfterEach(func() { 90 if process != nil { 91 process.Signal(syscall.SIGTERM) 92 Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive()) 93 } 94 if network != nil { 95 network.Cleanup() 96 } 97 os.RemoveAll(testDir) 98 }) 99 100 It("executes transactions endorsed with ECDSA signing certs", func() { 101 org1Peer0 := network.Peer("Org1", "peer0") 102 orderer := network.Orderer("orderer") 103 104 chaincode := nwo.Chaincode{ 105 Name: "mycc", 106 Version: "0.0", 107 Path: components.Build("github.com/hechain20/hechain/integration/chaincode/simple/cmd"), 108 Lang: "binary", 109 PackageFile: filepath.Join(testDir, "simplecc.tar.gz"), 110 Ctor: `{"Args":["init","a","100","b","200"]}`, 111 SignaturePolicy: `AND ('Org1MSP.member','Org2MSP.member')`, 112 Sequence: "1", 113 InitRequired: true, 114 Label: "my_prebuilt_chaincode", 115 } 116 117 network.CreateAndJoinChannels(orderer) 118 nwo.EnableCapabilities( 119 network, 120 "testchannel", 121 "Application", "V2_0", 122 orderer, 123 network.Peer("Org1", "peer0"), 124 network.Peer("Org2", "peer0"), 125 ) 126 nwo.DeployChaincode(network, "testchannel", orderer, chaincode) 127 RunQueryInvokeQuery(network, orderer, org1Peer0, 100) 128 }) 129 }) 130 131 // What follows is a bunch of code to build a hand-crafted set of MSPs where 132 // everything except signing certificates use RSA keys. It's not pretty but it 133 // gets the job done for testing. 134 135 func generateRSACACrypto(n *nwo.Network) { 136 cryptoDir := n.CryptoPath() 137 for _, o := range n.OrdererOrgs() { 138 orgDir := filepath.Join(cryptoDir, "ordererOrganizations", o.Domain) 139 signCA, tlsCA, adminCert := createMSP(orgDir, o.Domain, o.EnableNodeOUs) 140 for i := 1; i <= o.Users; i++ { 141 name := fmt.Sprintf("User%d@%s", i, o.Domain) 142 dir := filepath.Join(orgDir, "users", name) 143 var ous []string 144 if o.EnableNodeOUs { 145 ous = append(ous, "client") 146 } 147 writeLocalMSP(dir, name, ous, nil, signCA, tlsCA, adminCert, o.EnableNodeOUs, true) 148 } 149 for _, orderer := range n.OrderersInOrg(o.Name) { 150 name := orderer.Name + "." + o.Domain 151 dir := filepath.Join(orgDir, "orderers", name) 152 sans := []string{"127.0.0.1", "::1", "localhost"} 153 var ous []string 154 if o.EnableNodeOUs { 155 ous = append(ous, "orderer") 156 } 157 writeLocalMSP(dir, name, ous, sans, signCA, tlsCA, adminCert, o.EnableNodeOUs, false) 158 } 159 } 160 161 for _, o := range n.PeerOrgs() { 162 orgDir := filepath.Join(cryptoDir, "peerOrganizations", o.Domain) 163 signCA, tlsCA, adminCert := createMSP(orgDir, o.Domain, o.EnableNodeOUs) 164 for i := 1; i <= o.Users; i++ { 165 name := fmt.Sprintf("User%d@%s", i, o.Domain) 166 dir := filepath.Join(orgDir, "users", name) 167 var ous []string 168 if o.EnableNodeOUs { 169 ous = append(ous, "client") 170 } 171 writeLocalMSP(dir, name, ous, nil, signCA, tlsCA, adminCert, o.EnableNodeOUs, true) 172 } 173 for _, peer := range n.PeersInOrg(o.Name) { 174 name := peer.Name + "." + o.Domain 175 dir := filepath.Join(orgDir, "peers", name) 176 sans := []string{"127.0.0.1", "::1", "localhost"} 177 var ous []string 178 if o.EnableNodeOUs { 179 ous = append(ous, "peer") 180 } 181 writeLocalMSP(dir, name, ous, sans, signCA, tlsCA, adminCert, o.EnableNodeOUs, false) 182 } 183 } 184 } 185 186 func createMSP(baseDir, domain string, nodeOUs bool) (signCA *CA, tlsCA *CA, adminPemCert []byte) { 187 caDir := filepath.Join(baseDir, "ca") 188 signCA = newCA(domain, "ca") 189 writeCA(signCA, caDir) 190 191 tlsCADir := filepath.Join(baseDir, "tlsca") 192 tlsCA = newCA(domain, "tlsca") 193 writeCA(tlsCA, tlsCADir) 194 195 mspDir := filepath.Join(baseDir, "msp") 196 writeVerifyingMSP(mspDir, signCA, tlsCA, nodeOUs) 197 198 adminUsername := "Admin@" + domain 199 adminDir := filepath.Join(baseDir, "users", adminUsername) 200 err := os.MkdirAll(adminDir, 0o755) 201 Expect(err).NotTo(HaveOccurred()) 202 203 var ous []string 204 if nodeOUs { 205 ous = append(ous, "admin") 206 } 207 208 writeLocalMSP(adminDir, adminUsername, ous, nil, signCA, tlsCA, nil, nodeOUs, true) 209 adminPemCert, err = ioutil.ReadFile(filepath.Join(adminDir, "msp", "signcerts", certFilename(adminUsername))) 210 Expect(err).NotTo(HaveOccurred()) 211 err = ioutil.WriteFile(filepath.Join(adminDir, "msp", "admincerts", certFilename(adminUsername)), adminPemCert, 0o644) 212 Expect(err).NotTo(HaveOccurred()) 213 214 if !nodeOUs { 215 err := ioutil.WriteFile(filepath.Join(mspDir, "admincerts", certFilename(adminUsername)), adminPemCert, 0o644) 216 Expect(err).NotTo(HaveOccurred()) 217 } 218 219 return signCA, tlsCA, adminPemCert 220 } 221 222 func writeCA(ca *CA, dir string) { 223 err := os.MkdirAll(dir, 0o755) 224 Expect(err).NotTo(HaveOccurred()) 225 226 certFilename := filepath.Join(dir, ca.certFilename()) 227 writeCertificate(certFilename, ca.certBytes) 228 229 keyFilename := filepath.Join(dir, fmt.Sprintf("%x_sk", ca.cert.SubjectKeyId)) 230 writeKey(keyFilename, ca.signer) 231 } 232 233 func writeCertificate(filename string, der []byte) { 234 certFile, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE, 0o644) 235 Expect(err).NotTo(HaveOccurred()) 236 defer certFile.Close() 237 err = pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: der}) 238 Expect(err).NotTo(HaveOccurred()) 239 } 240 241 func writeKey(filename string, signer crypto.Signer) { 242 keyFile, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE, 0o600) 243 Expect(err).NotTo(HaveOccurred()) 244 defer keyFile.Close() 245 derKey, err := x509.MarshalPKCS8PrivateKey(signer) 246 Expect(err).NotTo(HaveOccurred()) 247 err = pem.Encode(keyFile, &pem.Block{Type: "PRIVATE KEY", Bytes: derKey}) 248 Expect(err).NotTo(HaveOccurred()) 249 } 250 251 func writeVerifyingMSP(mspDir string, signCA, tlsCA *CA, nodeOUs bool) { 252 for _, dir := range []string{"admincerts", "cacerts", "tlscacerts"} { 253 err := os.MkdirAll(filepath.Join(mspDir, dir), 0o755) 254 Expect(err).NotTo(HaveOccurred()) 255 } 256 if nodeOUs { 257 configFilename := filepath.Join(mspDir, "config.yaml") 258 writeConfigYaml(configFilename, filepath.Join("cacerts", signCA.certFilename()), nodeOUs) 259 } 260 writeCertificate(filepath.Join(mspDir, "cacerts", signCA.certFilename()), signCA.certBytes) 261 writeCertificate(filepath.Join(mspDir, "tlscacerts", tlsCA.certFilename()), tlsCA.certBytes) 262 } 263 264 func writeLocalMSP(baseDir, name string, signOUs, sans []string, signCA, tlsCA *CA, adminCertPem []byte, nodeOUs, client bool) { 265 mspDir := filepath.Join(baseDir, "msp") 266 err := os.MkdirAll(mspDir, 0o755) 267 Expect(err).NotTo(HaveOccurred()) 268 writeVerifyingMSP(mspDir, signCA, tlsCA, nodeOUs) 269 270 for _, dir := range []string{"admincerts", "keystore", "signcerts"} { 271 err := os.MkdirAll(filepath.Join(mspDir, dir), 0o755) 272 Expect(err).NotTo(HaveOccurred()) 273 } 274 275 if !nodeOUs && len(adminCertPem) != 0 { 276 block, _ := pem.Decode(adminCertPem) 277 adminCert, err := x509.ParseCertificate(block.Bytes) 278 Expect(err).NotTo(HaveOccurred()) 279 err = ioutil.WriteFile(filepath.Join(mspDir, "admincerts", certFilename(adminCert.Subject.CommonName)), adminCertPem, 0o644) 280 Expect(err).NotTo(HaveOccurred()) 281 } 282 283 // create signcert 284 priv := generateECKey() 285 signcertBytes, signcert := signCA.issueSignCertificate(name, signOUs, priv.Public()) 286 signcertFilename := filepath.Join(mspDir, "signcerts", certFilename(name)) 287 writeCertificate(signcertFilename, signcertBytes) 288 signcertKeyFilename := filepath.Join(mspDir, "keystore", fmt.Sprintf("%x_sk", signcert.SubjectKeyId)) 289 writeKey(signcertKeyFilename, priv) 290 291 // populate tls 292 tlsDir := filepath.Join(baseDir, "tls") 293 err = os.MkdirAll(tlsDir, 0o755) 294 Expect(err).NotTo(HaveOccurred()) 295 writeCertificate(filepath.Join(tlsDir, "ca.crt"), tlsCA.certBytes) 296 297 tlsKey := generateRSAKey() 298 tlsCertBytes, _ := tlsCA.issueTLSCertificate(name, sans, tlsKey.Public()) 299 if client { 300 writeCertificate(filepath.Join(tlsDir, "client.crt"), tlsCertBytes) 301 writeKey(filepath.Join(tlsDir, "client.key"), tlsKey) 302 } else { 303 writeCertificate(filepath.Join(tlsDir, "server.crt"), tlsCertBytes) 304 writeKey(filepath.Join(tlsDir, "server.key"), tlsKey) 305 } 306 } 307 308 func writeConfigYaml(configFilename, caFile string, enable bool) { 309 config := &fabricmsp.Configuration{ 310 NodeOUs: &fabricmsp.NodeOUs{ 311 Enable: enable, 312 ClientOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{ 313 Certificate: caFile, 314 OrganizationalUnitIdentifier: "client", 315 }, 316 PeerOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{ 317 Certificate: caFile, 318 OrganizationalUnitIdentifier: "peer", 319 }, 320 AdminOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{ 321 Certificate: caFile, 322 OrganizationalUnitIdentifier: "admin", 323 }, 324 OrdererOUIdentifier: &fabricmsp.OrganizationalUnitIdentifiersConfiguration{ 325 Certificate: caFile, 326 OrganizationalUnitIdentifier: "orderer", 327 }, 328 }, 329 } 330 331 configFile, err := os.Create(configFilename) 332 Expect(err).NotTo(HaveOccurred()) 333 defer configFile.Close() 334 335 err = yaml.NewEncoder(configFile).Encode(config) 336 Expect(err).NotTo(HaveOccurred()) 337 } 338 339 type CA struct { 340 signer crypto.Signer 341 cert *x509.Certificate 342 certBytes []byte 343 } 344 345 func newCA(orgName, caName string) *CA { 346 signer := generateRSAKey() 347 348 template := x509Template() 349 template.IsCA = true 350 template.KeyUsage |= x509.KeyUsageDigitalSignature 351 template.KeyUsage |= x509.KeyUsageKeyEncipherment 352 template.KeyUsage |= x509.KeyUsageCertSign 353 template.KeyUsage |= x509.KeyUsageCRLSign 354 template.ExtKeyUsage = []x509.ExtKeyUsage{ 355 x509.ExtKeyUsageClientAuth, 356 x509.ExtKeyUsageServerAuth, 357 } 358 template.Subject = pkix.Name{ 359 CommonName: caName + "." + orgName, 360 Organization: []string{orgName}, 361 } 362 template.SubjectKeyId = computeSKI(signer.Public()) 363 364 certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, signer.Public(), signer) 365 Expect(err).NotTo(HaveOccurred()) 366 cert, err := x509.ParseCertificate(certBytes) 367 Expect(err).NotTo(HaveOccurred()) 368 369 return &CA{ 370 signer: signer, 371 cert: cert, 372 certBytes: certBytes, 373 } 374 } 375 376 func (ca *CA) issueSignCertificate(name string, ous []string, pub crypto.PublicKey) ([]byte, *x509.Certificate) { 377 template := x509Template() 378 template.KeyUsage = x509.KeyUsageDigitalSignature 379 template.ExtKeyUsage = nil 380 template.Subject = pkix.Name{ 381 CommonName: name, 382 Organization: ca.cert.Subject.Organization, 383 OrganizationalUnit: ous, 384 } 385 template.SubjectKeyId = computeSKI(pub) 386 387 certBytes, err := x509.CreateCertificate(rand.Reader, &template, ca.cert, pub, ca.signer) 388 Expect(err).NotTo(HaveOccurred()) 389 cert, err := x509.ParseCertificate(certBytes) 390 Expect(err).NotTo(HaveOccurred()) 391 return certBytes, cert 392 } 393 394 func (ca *CA) issueTLSCertificate(name string, sans []string, pub crypto.PublicKey) ([]byte, *x509.Certificate) { 395 template := x509Template() 396 template.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment 397 template.ExtKeyUsage = []x509.ExtKeyUsage{ 398 x509.ExtKeyUsageServerAuth, 399 x509.ExtKeyUsageClientAuth, 400 } 401 template.Subject = pkix.Name{ 402 CommonName: name, 403 Organization: ca.cert.Subject.Organization, 404 } 405 template.SubjectKeyId = computeSKI(pub) 406 407 for _, san := range sans { 408 if ip := net.ParseIP(san); ip != nil { 409 template.IPAddresses = append(template.IPAddresses, ip) 410 } else { 411 template.DNSNames = append(template.DNSNames, san) 412 } 413 } 414 certBytes, err := x509.CreateCertificate(rand.Reader, &template, ca.cert, pub, ca.signer) 415 Expect(err).NotTo(HaveOccurred()) 416 cert, err := x509.ParseCertificate(certBytes) 417 Expect(err).NotTo(HaveOccurred()) 418 return certBytes, cert 419 } 420 421 func (ca *CA) certFilename() string { 422 return certFilename(ca.cert.Subject.CommonName) 423 } 424 425 func certFilename(stem string) string { 426 return stem + "-cert.pem" 427 } 428 429 func generateRSAKey() crypto.Signer { 430 signer, err := rsa.GenerateKey(rand.Reader, 4096) 431 Expect(err).NotTo(HaveOccurred()) 432 return signer 433 } 434 435 func generateECKey() crypto.Signer { 436 signer, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 437 Expect(err).NotTo(HaveOccurred()) 438 return signer 439 } 440 441 func x509Template() x509.Certificate { 442 serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) 443 serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit) 444 notBefore := time.Now().Round(time.Minute).Add(-5 * time.Minute).UTC() 445 446 return x509.Certificate{ 447 SerialNumber: serialNumber, 448 NotBefore: notBefore, 449 NotAfter: notBefore.Add(3650 * 24 * time.Hour).UTC(), 450 BasicConstraintsValid: true, 451 } 452 } 453 454 func computeSKI(key crypto.PublicKey) []byte { 455 var raw []byte 456 switch key := key.(type) { 457 case *rsa.PublicKey: 458 raw = x509.MarshalPKCS1PublicKey(key) 459 case *ecdsa.PublicKey: 460 raw = elliptic.Marshal(key.Curve, key.X, key.Y) 461 default: 462 panic(fmt.Sprintf("unexpected type: %T", key)) 463 } 464 hash := sha256.Sum256(raw) 465 return hash[:] 466 }