gitee.com/hyperledger/fabric-ca@v2.0.0-alpha+incompatible/lib/util.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lib
     8  
     9  import (
    10  	"crypto/tls"
    11  	"crypto/x509"
    12  	"encoding/hex"
    13  	"encoding/json"
    14  	"encoding/pem"
    15  	"fmt"
    16  	"io/ioutil"
    17  	"net/http"
    18  	"os"
    19  	"path/filepath"
    20  
    21  	"github.com/cloudflare/cfssl/log"
    22  	"github.com/grantae/certinfo"
    23  	"github.com/hyperledger/fabric-ca/api"
    24  	"github.com/hyperledger/fabric-ca/lib/caerrors"
    25  	"github.com/hyperledger/fabric-ca/util"
    26  	"github.com/pkg/errors"
    27  	"github.com/spf13/viper"
    28  )
    29  
    30  var clientAuthTypes = map[string]tls.ClientAuthType{
    31  	"noclientcert":               tls.NoClientCert,
    32  	"requestclientcert":          tls.RequestClientCert,
    33  	"requireanyclientcert":       tls.RequireAnyClientCert,
    34  	"verifyclientcertifgiven":    tls.VerifyClientCertIfGiven,
    35  	"requireandverifyclientcert": tls.RequireAndVerifyClientCert,
    36  }
    37  
    38  // GetCertID returns both the serial number and AKI (Authority Key ID) for the certificate
    39  func GetCertID(bytes []byte) (string, string, error) {
    40  	cert, err := BytesToX509Cert(bytes)
    41  	if err != nil {
    42  		return "", "", err
    43  	}
    44  	serial := util.GetSerialAsHex(cert.SerialNumber)
    45  	aki := hex.EncodeToString(cert.AuthorityKeyId)
    46  	return serial, aki, nil
    47  }
    48  
    49  // BytesToX509Cert converts bytes (PEM or DER) to an X509 certificate
    50  func BytesToX509Cert(bytes []byte) (*x509.Certificate, error) {
    51  	dcert, _ := pem.Decode(bytes)
    52  	if dcert != nil {
    53  		bytes = dcert.Bytes
    54  	}
    55  	cert, err := x509.ParseCertificate(bytes)
    56  	if err != nil {
    57  		return nil, errors.Wrap(err, "Buffer was neither PEM nor DER encoding")
    58  	}
    59  	return cert, err
    60  }
    61  
    62  // LoadPEMCertPool loads a pool of PEM certificates from list of files
    63  func LoadPEMCertPool(certFiles []string) (*x509.CertPool, error) {
    64  	certPool := x509.NewCertPool()
    65  
    66  	if len(certFiles) > 0 {
    67  		for _, cert := range certFiles {
    68  			log.Debugf("Reading cert file: %s", cert)
    69  			pemCerts, err := ioutil.ReadFile(cert)
    70  			if err != nil {
    71  				return nil, err
    72  			}
    73  
    74  			log.Debugf("Appending cert %s to pool", cert)
    75  			if !certPool.AppendCertsFromPEM(pemCerts) {
    76  				return nil, errors.New("Failed to load cert pool")
    77  			}
    78  		}
    79  	}
    80  
    81  	return certPool, nil
    82  }
    83  
    84  // UnmarshalConfig unmarshals a configuration file
    85  func UnmarshalConfig(config interface{}, vp *viper.Viper, configFile string,
    86  	server bool) error {
    87  
    88  	vp.SetConfigFile(configFile)
    89  	err := vp.ReadInConfig()
    90  	if err != nil {
    91  		return errors.Wrapf(err, "Failed to read config file '%s'", configFile)
    92  	}
    93  
    94  	err = vp.Unmarshal(config)
    95  	if err != nil {
    96  		return errors.Wrapf(err, "Incorrect format in file '%s'", configFile)
    97  	}
    98  	if server {
    99  		serverCfg := config.(*ServerConfig)
   100  		err = vp.Unmarshal(&serverCfg.CAcfg)
   101  		if err != nil {
   102  			return errors.Wrapf(err, "Incorrect format in file '%s'", configFile)
   103  		}
   104  	}
   105  	return nil
   106  }
   107  
   108  func getMaxEnrollments(userMaxEnrollments int, caMaxEnrollments int) (int, error) {
   109  	log.Debugf("Max enrollment value verification - User specified max enrollment: %d, CA max enrollment: %d", userMaxEnrollments, caMaxEnrollments)
   110  	if userMaxEnrollments < -1 {
   111  		return 0, caerrors.NewHTTPErr(400, caerrors.ErrInvalidMaxEnroll, "Max enrollment in registration request may not be less than -1, but was %d", userMaxEnrollments)
   112  	}
   113  	switch caMaxEnrollments {
   114  	case -1:
   115  		if userMaxEnrollments == 0 {
   116  			// The user is requesting the matching limit of the CA, so gets infinite
   117  			return caMaxEnrollments, nil
   118  		}
   119  		// There is no CA max enrollment limit, so simply use the user requested value
   120  		return userMaxEnrollments, nil
   121  	case 0:
   122  		// The CA max enrollment is 0, so registration is disabled.
   123  		return 0, caerrors.NewHTTPErr(400, caerrors.ErrInvalidMaxEnroll, "Registration is disabled")
   124  	default:
   125  		switch userMaxEnrollments {
   126  		case -1:
   127  			// User requested infinite enrollments is not allowed
   128  			return 0, caerrors.NewHTTPErr(400, caerrors.ErrInvalidMaxEnroll, "Registration for infinite enrollments is not allowed")
   129  		case 0:
   130  			// User is requesting the current CA maximum
   131  			return caMaxEnrollments, nil
   132  		default:
   133  			// User is requesting a specific positive value; make sure it doesn't exceed the CA maximum.
   134  			if userMaxEnrollments > caMaxEnrollments {
   135  				return 0, caerrors.NewHTTPErr(400, caerrors.ErrInvalidMaxEnroll, "Requested enrollments (%d) exceeds maximum allowable enrollments (%d)", userMaxEnrollments, caMaxEnrollments)
   136  			}
   137  			// otherwise, use the requested maximum
   138  			return userMaxEnrollments, nil
   139  		}
   140  	}
   141  }
   142  
   143  func addQueryParm(req *http.Request, name, value string) {
   144  	url := req.URL.Query()
   145  	url.Add(name, value)
   146  	req.URL.RawQuery = url.Encode()
   147  }
   148  
   149  // IdentityDecoder decodes streams of data coming from the server into an Identity object
   150  func IdentityDecoder(decoder *json.Decoder) error {
   151  	var id api.IdentityInfo
   152  	err := decoder.Decode(&id)
   153  	if err != nil {
   154  		return err
   155  	}
   156  	fmt.Printf("Name: %s, Type: %s, Affiliation: %s, Max Enrollments: %d, Attributes: %+v\n", id.ID, id.Type, id.Affiliation, id.MaxEnrollments, id.Attributes)
   157  	return nil
   158  }
   159  
   160  // AffiliationDecoder decodes streams of data coming from the server into an Affiliation object
   161  func AffiliationDecoder(decoder *json.Decoder) error {
   162  	var aff api.AffiliationInfo
   163  	err := decoder.Decode(&aff)
   164  	if err != nil {
   165  		return err
   166  	}
   167  	fmt.Printf("%s\n", aff.Name)
   168  	return nil
   169  }
   170  
   171  // CertificateDecoder is needed to keep track of state, to see how many certificates
   172  // have been returned for each enrollment ID.
   173  type CertificateDecoder struct {
   174  	certIDCount map[string]int
   175  	storePath   string
   176  }
   177  
   178  // NewCertificateDecoder returns decoder for certificates
   179  func NewCertificateDecoder(storePath string) *CertificateDecoder {
   180  	cd := &CertificateDecoder{}
   181  	cd.certIDCount = make(map[string]int)
   182  	cd.storePath = storePath
   183  	return cd
   184  }
   185  
   186  // CertificateDecoder decodes streams of data coming from the server
   187  func (cd *CertificateDecoder) CertificateDecoder(decoder *json.Decoder) error {
   188  	var cert certPEM
   189  	err := decoder.Decode(&cert)
   190  	if err != nil {
   191  		return err
   192  	}
   193  	block, rest := pem.Decode([]byte(cert.PEM))
   194  	if block == nil || len(rest) > 0 {
   195  		return errors.New("Certificate decoding error")
   196  	}
   197  	certificate, err := x509.ParseCertificate(block.Bytes)
   198  	if err != nil {
   199  		return err
   200  	}
   201  	enrollmentID := certificate.Subject.CommonName
   202  	if cd.storePath != "" {
   203  		err = cd.StoreCert(enrollmentID, cd.storePath, []byte(cert.PEM))
   204  		if err != nil {
   205  			return err
   206  		}
   207  	}
   208  
   209  	result, err := certinfo.CertificateText(certificate)
   210  	if err != nil {
   211  		return err
   212  	}
   213  	fmt.Printf(result)
   214  	return nil
   215  }
   216  
   217  // StoreCert stores the certificate on the file system
   218  func (cd *CertificateDecoder) StoreCert(enrollmentID, storePath string, cert []byte) error {
   219  	cd.certIDCount[enrollmentID] = cd.certIDCount[enrollmentID] + 1
   220  
   221  	err := os.MkdirAll(storePath, os.ModePerm)
   222  	if err != nil {
   223  		return err
   224  	}
   225  
   226  	var filePath string
   227  	singleCertName := fmt.Sprintf("%s.pem", enrollmentID)
   228  	switch cd.certIDCount[enrollmentID] {
   229  	case 1: // Only one certificate returned, don't need to append number to certificate file name
   230  		filePath = filepath.Join(storePath, singleCertName)
   231  	case 2: // Two certificates returned, rename the old certificate to have number at the end
   232  		err := os.Rename(filepath.Join(storePath, singleCertName), filepath.Join(storePath, fmt.Sprintf("%s-1.pem", enrollmentID)))
   233  		if err != nil {
   234  			return errors.WithMessage(err, fmt.Sprintf("Failed to rename certificate: %s", singleCertName))
   235  		}
   236  		filePath = filepath.Join(storePath, fmt.Sprintf("%s-%d.pem", enrollmentID, cd.certIDCount[enrollmentID]))
   237  	default:
   238  		filePath = filepath.Join(storePath, fmt.Sprintf("%s-%d.pem", enrollmentID, cd.certIDCount[enrollmentID]))
   239  	}
   240  
   241  	err = ioutil.WriteFile(filePath, cert, 0644)
   242  	if err != nil {
   243  		return errors.WithMessage(err, fmt.Sprintf("Failed to store certificate at: %s", storePath))
   244  	}
   245  
   246  	return nil
   247  }