github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/initializer/common/enroller/swenroller.go (about) 1 /* 2 * Copyright contributors to the Hyperledger Fabric Operator project 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package enroller 20 21 import ( 22 "crypto/x509" 23 "encoding/pem" 24 "fmt" 25 "io/ioutil" 26 "os" 27 "path/filepath" 28 "time" 29 30 current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" 31 "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/common/config" 32 "github.com/IBM-Blockchain/fabric-operator/pkg/util" 33 "github.com/hyperledger/fabric-ca/api" 34 "github.com/hyperledger/fabric-ca/lib" 35 "github.com/pkg/errors" 36 ) 37 38 //go:generate counterfeiter -o mocks/caclient.go -fake-name CAClient . CAClient 39 40 type CAClient interface { 41 Init() error 42 Enroll(*api.EnrollmentRequest) (*lib.EnrollmentResponse, error) 43 GetEnrollmentRequest() *current.Enrollment 44 GetHomeDir() string 45 GetTLSCert() []byte 46 PingCA(time.Duration) error 47 } 48 49 type SWEnroller struct { 50 Client CAClient 51 } 52 53 func NewSWEnroller(caClient CAClient) *SWEnroller { 54 return &SWEnroller{ 55 Client: caClient, 56 } 57 } 58 59 func (e *SWEnroller) GetEnrollmentRequest() *current.Enrollment { 60 return e.Client.GetEnrollmentRequest() 61 } 62 63 func (e *SWEnroller) PingCA(timeout time.Duration) error { 64 return e.Client.PingCA(timeout) 65 } 66 67 func (e *SWEnroller) Enroll() (*config.Response, error) { 68 resp, err := enroll(e.Client) 69 if err != nil { 70 return nil, err 71 } 72 73 key, err := e.ReadKey() 74 if err != nil { 75 return nil, err 76 } 77 resp.Keystore = key 78 79 return resp, nil 80 } 81 82 func (e *SWEnroller) ReadKey() ([]byte, error) { 83 keystoreDir := filepath.Join(e.Client.GetHomeDir(), "msp", "keystore") 84 files, err := ioutil.ReadDir(keystoreDir) 85 if err != nil { 86 return nil, err 87 } 88 89 if len(files) > 1 { 90 return nil, errors.Errorf("expecting only one key file to present in keystore '%s', but found multiple", keystoreDir) 91 } 92 93 for _, file := range files { 94 fileBytes, err := ioutil.ReadFile(filepath.Clean(filepath.Join(keystoreDir, file.Name()))) 95 if err != nil { 96 return nil, err 97 } 98 99 block, _ := pem.Decode(fileBytes) 100 if block == nil { 101 continue 102 } 103 104 _, err = x509.ParsePKCS8PrivateKey(block.Bytes) 105 if err == nil { 106 return fileBytes, nil 107 } 108 } 109 110 return nil, errors.Errorf("failed to read private key") 111 } 112 113 func enroll(client CAClient) (*config.Response, error) { 114 req := client.GetEnrollmentRequest() 115 log.Info(fmt.Sprintf("Enrolling with CA '%s'", req.CAHost)) 116 117 err := os.MkdirAll(client.GetHomeDir(), 0750) 118 if err != nil { 119 return nil, err 120 } 121 122 err = util.WriteFile(filepath.Join(client.GetHomeDir(), "tlsCert.pem"), client.GetTLSCert(), 0755) 123 if err != nil { 124 return nil, err 125 } 126 127 err = client.Init() 128 if err != nil { 129 return nil, errors.Wrap(err, "failed to initialize CA client") 130 } 131 132 // Enroll with CA 133 enrollReq := &api.EnrollmentRequest{ 134 Type: "x509", 135 Name: req.EnrollID, 136 Secret: req.EnrollSecret, 137 CAName: req.CAName, 138 } 139 if req.CSR != nil && len(req.CSR.Hosts) > 0 { 140 enrollReq.CSR = &api.CSRInfo{ 141 Hosts: req.CSR.Hosts, 142 } 143 } 144 145 enrollResp, err := client.Enroll(enrollReq) 146 if err != nil { 147 return nil, errors.Wrap(err, "failed to enroll with CA") 148 } 149 150 resp := &config.Response{} 151 resp, err = ParseEnrollmentResponse(resp, &enrollResp.CAInfo) 152 if err != nil { 153 return nil, err 154 } 155 156 id := enrollResp.Identity 157 if id.GetECert() != nil { 158 resp.SignCert = id.GetECert().Cert() 159 } 160 161 return resp, nil 162 }