gitee.com/zhaochuninhefei/fabric-ca-gm@v0.0.2/lib/serverenroll.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  	"encoding/asn1"
    11  	"encoding/pem"
    12  	"time"
    13  
    14  	"gitee.com/zhaochuninhefei/cfssl-gm/config"
    15  	"gitee.com/zhaochuninhefei/cfssl-gm/csr"
    16  	cferr "gitee.com/zhaochuninhefei/cfssl-gm/errors"
    17  	"gitee.com/zhaochuninhefei/cfssl-gm/signer"
    18  	"gitee.com/zhaochuninhefei/fabric-ca-gm/internal/pkg/api"
    19  	"gitee.com/zhaochuninhefei/fabric-ca-gm/internal/pkg/util"
    20  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/caerrors"
    21  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/user"
    22  	"gitee.com/zhaochuninhefei/gmgo/x509"
    23  	"gitee.com/zhaochuninhefei/zcgolog/zclog"
    24  	"github.com/pkg/errors"
    25  )
    26  
    27  const (
    28  	commonNameLength             = 64
    29  	serialNumberLength           = 64
    30  	countryNameLength            = 2
    31  	localityNameLength           = 128
    32  	stateOrProvinceNameLength    = 128
    33  	organizationNameLength       = 64
    34  	organizationalUnitNameLength = 64
    35  )
    36  
    37  var (
    38  	// The X.509 BasicConstraints object identifier (RFC 5280, 4.2.1.9)
    39  	basicConstraintsOID   = asn1.ObjectIdentifier{2, 5, 29, 19}
    40  	commonNameOID         = asn1.ObjectIdentifier{2, 5, 4, 3}
    41  	serialNumberOID       = asn1.ObjectIdentifier{2, 5, 4, 5}
    42  	countryOID            = asn1.ObjectIdentifier{2, 5, 4, 6}
    43  	localityOID           = asn1.ObjectIdentifier{2, 5, 4, 7}
    44  	stateOID              = asn1.ObjectIdentifier{2, 5, 4, 8}
    45  	organizationOID       = asn1.ObjectIdentifier{2, 5, 4, 10}
    46  	organizationalUnitOID = asn1.ObjectIdentifier{2, 5, 4, 11}
    47  )
    48  
    49  func newEnrollEndpoint(s *Server) *serverEndpoint {
    50  	return &serverEndpoint{
    51  		Path:      "enroll",
    52  		Methods:   []string{"POST"},
    53  		Handler:   enrollHandler,
    54  		Server:    s,
    55  		successRC: 201,
    56  	}
    57  }
    58  
    59  func newReenrollEndpoint(s *Server) *serverEndpoint {
    60  	return &serverEndpoint{
    61  		Path:      "reenroll",
    62  		Methods:   []string{"POST"},
    63  		Handler:   reenrollHandler,
    64  		Server:    s,
    65  		successRC: 201,
    66  	}
    67  }
    68  
    69  // Handle an enroll request, guarded by basic authentication
    70  func enrollHandler(ctx *serverRequestContextImpl) (interface{}, error) {
    71  	zclog.Debug("===== ca服务端开始处理enroll请求")
    72  	id, err := ctx.BasicAuthentication()
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  	resp, err := handleEnroll(ctx, id)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	err = ctx.ui.LoginComplete()
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  	return resp, nil
    85  }
    86  
    87  // Handle a reenroll request, guarded by token authentication
    88  func reenrollHandler(ctx *serverRequestContextImpl) (interface{}, error) {
    89  	// Authenticate the caller
    90  	id, err := ctx.TokenAuthentication()
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	return handleEnroll(ctx, id)
    95  }
    96  
    97  // Handle the common processing for enroll and reenroll
    98  func handleEnroll(ctx *serverRequestContextImpl, id string) (interface{}, error) {
    99  	zclog.Debugf("===== 请求证书的用户信息 Name:%s Type:%s", ctx.ui.GetName(), ctx.ui.GetType())
   100  	var req api.EnrollmentRequestNet
   101  	err := ctx.ReadBody(&req)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	// Get the targeted CA
   106  	ca, err := ctx.GetCA()
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	// Set expiry based on the requested CA profile else use expiry from the default profile
   111  	// 从ca配置中读取 ca.Config.Signing.Default : signing.default
   112  	// zclog.Debugf("===== lib/serverenroll.go handleEnroll before req.NotAfter : %s , req.SignRequest.NotAfter: %s", req.NotAfter.Format(time.RFC3339), req.SignRequest.NotAfter.Format(time.RFC3339))
   113  	profile := ca.Config.Signing.Default
   114  	if req.Profile != "" && ca.Config.Signing != nil &&
   115  		ca.Config.Signing.Profiles != nil && ca.Config.Signing.Profiles[req.Profile] != nil {
   116  		profile = ca.Config.Signing.Profiles[req.Profile]
   117  	}
   118  	req.NotAfter = time.Now().Round(time.Minute).Add(profile.Expiry).UTC()
   119  
   120  	notBefore, notAfter, err := ca.getCACertExpiry()
   121  	if err != nil {
   122  		return nil, errors.New("Failed to get CA certificate information")
   123  	}
   124  
   125  	// Make sure requested expiration for enrollment certificate is not after CA certificate
   126  	// expiration
   127  	if !notAfter.IsZero() && req.NotAfter.After(notAfter) {
   128  		zclog.Debugf("Requested expiry '%s' is after the CA certificate expiry '%s'. Will use CA cert expiry",
   129  			req.NotAfter, notAfter)
   130  		req.NotAfter = notAfter
   131  	}
   132  	// Make sure that requested expiration for enrollment certificate is not before CA certificate
   133  	// expiration
   134  	if !notBefore.IsZero() && req.NotBefore.Before(notBefore) {
   135  		zclog.Debugf("Requested expiry '%s' is before the CA certificate expiry '%s'. Will use CA cert expiry",
   136  			req.NotBefore, notBefore)
   137  		req.NotBefore = notBefore
   138  	}
   139  	// zclog.Debugf("===== lib/serverenroll.go handleEnroll after req.NotAfter : %s , req.SignRequest.NotAfter: %s", req.NotAfter.Format(time.RFC3339), req.SignRequest.NotAfter.Format(time.RFC3339))
   140  
   141  	// Process the sign request from the caller.
   142  	// Make sure it is authorized and do any swizzling appropriate to the request.
   143  	// 内部使用caller补充了OU信息
   144  	err = processSignRequest(id, &req.SignRequest, ca, ctx)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	// Get an attribute extension if one is being requested
   149  	ext, err := ctx.GetAttrExtension(req.AttrReqs, req.Profile)
   150  	if err != nil {
   151  		return nil, errors.WithMessage(err, "Failed to find requested attributes")
   152  	}
   153  	// If there is an extension requested, add it to the request
   154  	if ext != nil {
   155  		// zclog.Debugf("Adding attribute extension to CSR: %+v", ext)
   156  		req.Extensions = append(req.Extensions, *ext)
   157  	}
   158  	// Sign the certificate
   159  	// 使用cfssl-gm,已实现国密改造
   160  	cert, err := ca.enrollSigner.Sign(req.SignRequest)
   161  	if err != nil {
   162  		return nil, errors.WithMessage(err, "Certificate signing failure")
   163  	}
   164  	// Add server info to the response
   165  	resp := &api.EnrollmentResponseNet{
   166  		Cert: util.B64Encode(cert),
   167  	}
   168  	err = ca.fillCAInfo(&resp.ServerInfo)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	// Success
   173  	zclog.Debugf("===== 用户:%s (Type:%s)的证书拉取请求成功", ctx.ui.GetName(), ctx.ui.GetType())
   174  	return resp, nil
   175  }
   176  
   177  // Process the sign request.
   178  // Make any authorization checks needed, depending on the contents
   179  // of the CSR (Certificate Signing Request).
   180  // In particular, if the request is for an intermediate CA certificate,
   181  // the caller must have the "hf.IntermediateCA" attribute.
   182  // Check to see that CSR values do not exceed the character limit
   183  // as specified in RFC 3280, page 103.
   184  // Set the OU fields of the request.
   185  func processSignRequest(id string, req *signer.SignRequest, ca *CA, ctx *serverRequestContextImpl) error {
   186  	// Decode and parse the request into a CSR so we can make checks
   187  	block, _ := pem.Decode([]byte(req.Request))
   188  	if block == nil {
   189  		return caerrors.NewHTTPErr(400, caerrors.ErrBadCSR, "CSR Decode failed")
   190  	}
   191  	if block.Type != "NEW CERTIFICATE REQUEST" && block.Type != "CERTIFICATE REQUEST" {
   192  		return cferr.Wrap(cferr.CSRError,
   193  			cferr.BadRequest, errors.New("not a certificate or csr"))
   194  	}
   195  	var csrReq *x509.CertificateRequest
   196  	var err error
   197  	// if IsGMConfig() {
   198  	// 	sm2csrReq, err := gx509.ParseCertificateRequest(block.Bytes)
   199  	// 	if err == nil {
   200  	// 		csrReq = ParseSm2CertificateRequest2X509(sm2csrReq)
   201  	// 	}
   202  	// } else {
   203  	// 	csrReq, err = x509.ParseCertificateRequest(block.Bytes)
   204  	// }
   205  	csrReq, err = x509.ParseCertificateRequest(block.Bytes)
   206  	if err != nil {
   207  		return err
   208  	}
   209  	// zclog.Debugf("===== req.Subject: %#v", req.Subject)
   210  	// zclog.Debugf("Processing sign request: id=%s, CommonName=%s, Subject=%#v", id, csrReq.Subject.CommonName, csrReq.Subject)
   211  	if (req.Subject != nil && req.Subject.CN != id) || csrReq.Subject.CommonName != id {
   212  		return caerrors.NewHTTPErr(403, caerrors.ErrCNInvalidEnroll, "The CSR subject common name must equal the enrollment ID")
   213  	}
   214  	isForCACert, err := isRequestForCASigningCert(csrReq, ca, req.Profile)
   215  	if err != nil {
   216  		return err
   217  	}
   218  	if isForCACert {
   219  		// This is a request for a CA certificate, so make sure the caller
   220  		// has the 'hf.IntermediateCA' attribute
   221  		err := ca.attributeIsTrue(id, "hf.IntermediateCA")
   222  		if err != nil {
   223  			return caerrors.NewAuthorizationErr(caerrors.ErrInvokerMissAttr, "Enrolled failed: %s", err)
   224  		}
   225  	}
   226  	// Check the CSR input length
   227  	err = csrInputLengthCheck(csrReq)
   228  	if err != nil {
   229  		return caerrors.NewHTTPErr(400, caerrors.ErrInputValidCSR, "CSR input validation failed: %s", err)
   230  	}
   231  	caller, err := ctx.GetCaller()
   232  	if err != nil {
   233  		return err
   234  	}
   235  	// Set the OUs in the request appropriately.
   236  	setRequestOUs(req, caller)
   237  	zclog.Debug("===== Finished processing sign request")
   238  	return nil
   239  }
   240  
   241  // Check to see if this is a request for a CA signing certificate.
   242  // This can occur if the profile or the CSR has the IsCA bit set.
   243  // See the X.509 BasicConstraints extension (RFC 5280, 4.2.1.9).
   244  func isRequestForCASigningCert(csrReq *x509.CertificateRequest, ca *CA, profile string) (bool, error) {
   245  	// Check the profile to see if the IsCA bit is set
   246  	sp := getSigningProfile(ca, profile)
   247  	if sp == nil {
   248  		return false, errors.Errorf("Invalid profile: '%s'", profile)
   249  	}
   250  	if sp.CAConstraint.IsCA {
   251  		zclog.Debugf("Request is for a CA signing certificate as set in profile '%s'", profile)
   252  		return true, nil
   253  	}
   254  	// Check the CSR to see if the IsCA bit is set
   255  	for _, val := range csrReq.Extensions {
   256  		if val.Id.Equal(basicConstraintsOID) {
   257  			var constraints csr.BasicConstraints
   258  			var rest []byte
   259  			var err error
   260  			if rest, err = asn1.Unmarshal(val.Value, &constraints); err != nil {
   261  				return false, caerrors.NewHTTPErr(400, caerrors.ErrBadCSR, "Failed parsing CSR constraints: %s", err)
   262  			} else if len(rest) != 0 {
   263  				return false, caerrors.NewHTTPErr(400, caerrors.ErrBadCSR, "Trailing data after X.509 BasicConstraints")
   264  			}
   265  			if constraints.IsCA {
   266  				zclog.Debug("Request is for a CA signing certificate as indicated in the CSR")
   267  				return true, nil
   268  			}
   269  		}
   270  	}
   271  	// The IsCA bit was not set
   272  	zclog.Debug("Request is not for a CA signing certificate")
   273  	return false, nil
   274  }
   275  
   276  func getSigningProfile(ca *CA, profile string) *config.SigningProfile {
   277  	if profile == "" {
   278  		return ca.Config.Signing.Default
   279  	}
   280  	return ca.Config.Signing.Profiles[profile]
   281  }
   282  
   283  // Checks to make sure that character limits are not exceeded for CSR fields
   284  func csrInputLengthCheck(req *x509.CertificateRequest) error {
   285  	zclog.Debug("Checking CSR fields to make sure that they do not exceed maximum character limits")
   286  
   287  	for _, n := range req.Subject.Names {
   288  		value := n.Value.(string)
   289  		switch {
   290  		case n.Type.Equal(commonNameOID):
   291  			if len(value) > commonNameLength {
   292  				return errors.Errorf("The CN '%s' exceeds the maximum character limit of %d", value, commonNameLength)
   293  			}
   294  		case n.Type.Equal(serialNumberOID):
   295  			if len(value) > serialNumberLength {
   296  				return errors.Errorf("The serial number '%s' exceeds the maximum character limit of %d", value, serialNumberLength)
   297  			}
   298  		case n.Type.Equal(organizationalUnitOID):
   299  			if len(value) > organizationalUnitNameLength {
   300  				return errors.Errorf("The organizational unit name '%s' exceeds the maximum character limit of %d", value, organizationalUnitNameLength)
   301  			}
   302  		case n.Type.Equal(organizationOID):
   303  			if len(value) > organizationNameLength {
   304  				return errors.Errorf("The organization name '%s' exceeds the maximum character limit of %d", value, organizationNameLength)
   305  			}
   306  		case n.Type.Equal(countryOID):
   307  			if len(value) > countryNameLength {
   308  				return errors.Errorf("The country name '%s' exceeds the maximum character limit of %d", value, countryNameLength)
   309  			}
   310  		case n.Type.Equal(localityOID):
   311  			if len(value) > localityNameLength {
   312  				return errors.Errorf("The locality name '%s' exceeds the maximum character limit of %d", value, localityNameLength)
   313  			}
   314  		case n.Type.Equal(stateOID):
   315  			if len(value) > stateOrProvinceNameLength {
   316  				return errors.Errorf("The state name '%s' exceeds the maximum character limit of %d", value, stateOrProvinceNameLength)
   317  			}
   318  		}
   319  	}
   320  
   321  	return nil
   322  }
   323  
   324  // Set the OU fields of the sign request based on the identity's type and affiliation.
   325  // For example, if the type is 'peer' and the affiliation is 'a.b.c', the
   326  // OUs become 'OU=c,OU=b,OU=a,OU=peer'.
   327  // This is necessary because authorization decisions are made based on the OU fields,
   328  // so we ignore any OU values specified in the enroll request and set them according
   329  // to the type and affiliation.
   330  func setRequestOUs(req *signer.SignRequest, caller user.User) {
   331  	s := req.Subject
   332  	if s == nil {
   333  		s = &signer.Subject{}
   334  	}
   335  	names := []csr.Name{}
   336  	// Add non-OU fields from request
   337  	for _, name := range s.Names {
   338  		if name.C != "" || name.L != "" || name.O != "" || name.ST != "" || name.SerialNumber != "" {
   339  			name.OU = ""
   340  			names = append(names, name)
   341  		}
   342  	}
   343  	// Add an OU field with the type
   344  	// zclog.Debugf("===== lib/serverenroll.go setRequestOUs caller.GetType: %s\n", caller.GetType())
   345  	names = append(names, csr.Name{OU: caller.GetType()})
   346  	for _, aff := range caller.GetAffiliationPath() {
   347  		names = append(names, csr.Name{OU: aff})
   348  	}
   349  	// zclog.Debugf("===== lib/serverenroll.go setRequestOUs names: %v\n", names)
   350  	// Replace with new names
   351  	s.Names = names
   352  	req.Subject = s
   353  	// zclog.Debugf("===== lib/serverenroll.go setRequestOUs req.Subject: %#v\n", req.Subject)
   354  }