github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/hyperledger/fabric/common/attrmgr/attrmgr.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8                   http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  /*
    18   * The attrmgr package contains utilities for managing attributes.
    19   * Attributes are added to an X509 certificate as an extension.
    20   */
    21  
    22  package attrmgr
    23  
    24  import (
    25  	"encoding/asn1"
    26  	"encoding/json"
    27  	"fmt"
    28  	"github.com/hellobchain/newcryptosm/x509"
    29  	"github.com/hellobchain/newcryptosm/x509/pkix"
    30  
    31  	"github.com/pkg/errors"
    32  )
    33  
    34  var (
    35  	// AttrOID is the ASN.1 object identifier for an attribute extension in an
    36  	// X509 certificate
    37  	AttrOID = asn1.ObjectIdentifier{1, 2, 3, 4, 5, 6, 7, 8, 1}
    38  	// AttrOIDString is the string version of AttrOID
    39  	AttrOIDString = "1.2.3.4.5.6.7.8.1"
    40  )
    41  
    42  // Attribute is a name/value pair
    43  type Attribute interface {
    44  	// GetName returns the name of the attribute
    45  	GetName() string
    46  	// GetValue returns the value of the attribute
    47  	GetValue() string
    48  }
    49  
    50  // AttributeRequest is a request for an attribute
    51  type AttributeRequest interface {
    52  	// GetName returns the name of an attribute
    53  	GetName() string
    54  	// IsRequired returns true if the attribute is required
    55  	IsRequired() bool
    56  }
    57  
    58  // New constructs an attribute manager
    59  func New() *Mgr { return &Mgr{} }
    60  
    61  // Mgr is the attribute manager and is the main object for this package
    62  type Mgr struct{}
    63  
    64  // ProcessAttributeRequestsForCert add attributes to an X509 certificate, given
    65  // attribute requests and attributes.
    66  func (mgr *Mgr) ProcessAttributeRequestsForCert(requests []AttributeRequest, attributes []Attribute, cert *x509.Certificate) error {
    67  	attrs, err := mgr.ProcessAttributeRequests(requests, attributes)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	return mgr.AddAttributesToCert(attrs, cert)
    72  }
    73  
    74  // ProcessAttributeRequests takes an array of attribute requests and an identity's attributes
    75  // and returns an Attributes object containing the requested attributes.
    76  func (mgr *Mgr) ProcessAttributeRequests(requests []AttributeRequest, attributes []Attribute) (*Attributes, error) {
    77  	attrsMap := map[string]string{}
    78  	attrs := &Attributes{Attrs: attrsMap}
    79  	missingRequiredAttrs := []string{}
    80  	// For each of the attribute requests
    81  	for _, req := range requests {
    82  		// Get the attribute
    83  		name := req.GetName()
    84  		attr := getAttrByName(name, attributes)
    85  		if attr == nil {
    86  			if req.IsRequired() {
    87  				// Didn't find attribute and it was required; return error below
    88  				missingRequiredAttrs = append(missingRequiredAttrs, name)
    89  			}
    90  			// Skip attribute requests which aren't required
    91  			continue
    92  		}
    93  		attrsMap[name] = attr.GetValue()
    94  	}
    95  	if len(missingRequiredAttrs) > 0 {
    96  		return nil, errors.Errorf("The following required attributes are missing: %+v",
    97  			missingRequiredAttrs)
    98  	}
    99  	return attrs, nil
   100  }
   101  
   102  // AddAttributesToCert adds public attribute info to an X509 certificate.
   103  func (mgr *Mgr) AddAttributesToCert(attrs *Attributes, cert *x509.Certificate) error {
   104  	buf, err := json.Marshal(attrs)
   105  	if err != nil {
   106  		return errors.Wrap(err, "Failed to marshal attributes")
   107  	}
   108  	ext := pkix.Extension{
   109  		Id:       AttrOID,
   110  		Critical: false,
   111  		Value:    buf,
   112  	}
   113  	cert.Extensions = append(cert.Extensions, ext)
   114  	return nil
   115  }
   116  
   117  // GetAttributesFromCert gets the attributes from a certificate.
   118  func (mgr *Mgr) GetAttributesFromCert(cert *x509.Certificate) (*Attributes, error) {
   119  	// Get certificate attributes from the certificate if it exists
   120  	buf, err := getAttributesFromCert(cert)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  	// Unmarshal into attributes object
   125  	attrs := &Attributes{}
   126  	if buf != nil {
   127  		err := json.Unmarshal(buf, attrs)
   128  		if err != nil {
   129  			return nil, errors.Wrap(err, "Failed to unmarshal attributes from certificate")
   130  		}
   131  	}
   132  	return attrs, nil
   133  }
   134  
   135  // Attributes contains attribute names and values
   136  type Attributes struct {
   137  	Attrs map[string]string `json:"attrs"`
   138  }
   139  
   140  // Names returns the names of the attributes
   141  func (a *Attributes) Names() []string {
   142  	i := 0
   143  	names := make([]string, len(a.Attrs))
   144  	for name := range a.Attrs {
   145  		names[i] = name
   146  		i++
   147  	}
   148  	return names
   149  }
   150  
   151  // Contains returns true if the named attribute is found
   152  func (a *Attributes) Contains(name string) bool {
   153  	_, ok := a.Attrs[name]
   154  	return ok
   155  }
   156  
   157  // Value returns an attribute's value
   158  func (a *Attributes) Value(name string) (string, bool, error) {
   159  	attr, ok := a.Attrs[name]
   160  	return attr, ok, nil
   161  }
   162  
   163  // True returns nil if the value of attribute 'name' is true;
   164  // otherwise, an appropriate error is returned.
   165  func (a *Attributes) True(name string) error {
   166  	val, ok, err := a.Value(name)
   167  	if err != nil {
   168  		return err
   169  	}
   170  	if !ok {
   171  		return fmt.Errorf("Attribute '%s' was not found", name)
   172  	}
   173  	if val != "true" {
   174  		return fmt.Errorf("Attribute '%s' is not true", name)
   175  	}
   176  	return nil
   177  }
   178  
   179  // Get the attribute info from a certificate extension, or return nil if not found
   180  func getAttributesFromCert(cert *x509.Certificate) ([]byte, error) {
   181  	for _, ext := range cert.Extensions {
   182  		if isAttrOID(ext.Id) {
   183  			return ext.Value, nil
   184  		}
   185  	}
   186  	return nil, nil
   187  }
   188  
   189  // Is the object ID equal to the attribute info object ID?
   190  func isAttrOID(oid asn1.ObjectIdentifier) bool {
   191  	if len(oid) != len(AttrOID) {
   192  		return false
   193  	}
   194  	for idx, val := range oid {
   195  		if val != AttrOID[idx] {
   196  			return false
   197  		}
   198  	}
   199  	return true
   200  }
   201  
   202  // Get an attribute from 'attrs' by its name, or nil if not found
   203  func getAttrByName(name string, attrs []Attribute) Attribute {
   204  	for _, attr := range attrs {
   205  		if attr.GetName() == name {
   206  			return attr
   207  		}
   208  	}
   209  	return nil
   210  }