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  }