github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/accesscontrol/crypto/attr/attr_support.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 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  package attr
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/x509"
    22  	"errors"
    23  
    24  	"github.com/hyperledger/fabric/accesscontrol"
    25  	"github.com/hyperledger/fabric/accesscontrol/attributes"
    26  	"github.com/hyperledger/fabric/accesscontrol/crypto/utils"
    27  )
    28  
    29  // chaincodeHolder is the struct that hold the certificate and the metadata. An implementation is ChaincodeStub
    30  type chaincodeHolder interface {
    31  	// GetCreator returns caller certificate
    32  	GetCreator() ([]byte, error)
    33  
    34  	// GetCallerMetadata returns caller metadata
    35  	/*
    36  			TODO: ##attributes-keys-pending This code have be redefined to avoid use of metadata field.
    37  		GetCallerMetadata() ([]byte, error)
    38  	*/
    39  }
    40  
    41  //AttributesHandler is an entity can be used to both verify and read attributes.
    42  //		The functions declared can be used to access the attributes stored in the transaction certificates from the application layer. Can be used directly from the ChaincodeStub API but
    43  //		 if you need multiple access create a hanlder is better:
    44  // 	Multiple accesses
    45  // 		If multiple calls to the functions above are required, a best practice is to create an AttributesHandler instead of calling the functions multiple times, this practice will avoid creating a new AttributesHandler for each of these calls thus eliminating an unnecessary overhead.
    46  //    Example:
    47  //
    48  //		AttributesHandler, err := ac.NewAttributesHandlerImpl(stub)
    49  //		if err != nil {
    50  //			return false, err
    51  //		}
    52  //		AttributesHandler.VerifyAttribute(attributeName, attributeValue)
    53  //		... you can make other verifications and/or read attribute values by using the AttributesHandler
    54  type AttributesHandler interface {
    55  
    56  	//VerifyAttributes does the same as VerifyAttribute but it checks for a list of attributes and their respective values instead of a single attribute/value pair
    57  	// Example:
    58  	//    containsAttrs, error:= handler.VerifyAttributes(&ac.Attribute{"position",  "Software Engineer"}, &ac.Attribute{"company", "ACompany"})
    59  	VerifyAttributes(attrs ...*accesscontrol.Attribute) (bool, error)
    60  
    61  	//VerifyAttribute is used to verify if the transaction certificate has an attribute with name *attributeName* and value *attributeValue* which are the input parameters received by this function.
    62  	//Example:
    63  	//    containsAttr, error := handler.VerifyAttribute("position", "Software Engineer")
    64  	VerifyAttribute(attributeName string, attributeValue []byte) (bool, error)
    65  
    66  	//GetValue is used to read an specific attribute from the transaction certificate, *attributeName* is passed as input parameter to this function.
    67  	// Example:
    68  	//  attrValue,error:=handler.GetValue("position")
    69  	GetValue(attributeName string) ([]byte, error)
    70  }
    71  
    72  //AttributesHandlerImpl is an implementation of AttributesHandler interface.
    73  type AttributesHandlerImpl struct {
    74  	cert      *x509.Certificate
    75  	cache     map[string][]byte
    76  	keys      map[string][]byte
    77  	header    map[string]int
    78  	encrypted bool
    79  }
    80  
    81  type chaincodeHolderImpl struct {
    82  	Certificate []byte
    83  }
    84  
    85  // GetCreator returns caller certificate
    86  func (holderImpl *chaincodeHolderImpl) GetCreator() ([]byte, error) {
    87  	return holderImpl.Certificate, nil
    88  }
    89  
    90  //GetValueFrom returns the value of 'attributeName0' from a cert.
    91  func GetValueFrom(attributeName string, cert []byte) ([]byte, error) {
    92  	handler, err := NewAttributesHandlerImpl(&chaincodeHolderImpl{Certificate: cert})
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	return handler.GetValue(attributeName)
    97  }
    98  
    99  //NewAttributesHandlerImpl creates a new AttributesHandlerImpl from a pb.ChaincodeSecurityContext object.
   100  func NewAttributesHandlerImpl(holder chaincodeHolder) (*AttributesHandlerImpl, error) {
   101  	// Getting certificate
   102  	certRaw, err := holder.GetCreator()
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  	if certRaw == nil {
   107  		return nil, errors.New("The certificate can't be nil.")
   108  	}
   109  	var tcert *x509.Certificate
   110  	tcert, err = utils.DERToX509Certificate(certRaw)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	keys := make(map[string][]byte)
   116  
   117  	/*
   118  			TODO: ##attributes-keys-pending This code have be redefined to avoid use of metadata field.
   119  
   120  		//Getting Attributes Metadata from security context.
   121  		var attrsMetadata *attributespb.AttributesMetadata
   122  		var rawMetadata []byte
   123  		rawMetadata, err = holder.GetCallerMetadata()
   124  		if err != nil {
   125  			return nil, err
   126  		}
   127  
   128  		if rawMetadata != nil {
   129  			attrsMetadata, err = attributes.GetAttributesMetadata(rawMetadata)
   130  			if err == nil {
   131  				for _, entry := range attrsMetadata.Entries {
   132  					keys[entry.AttributeName] = entry.AttributeKey
   133  				}
   134  			}
   135  		}*/
   136  
   137  	cache := make(map[string][]byte)
   138  	return &AttributesHandlerImpl{tcert, cache, keys, nil, false}, nil
   139  }
   140  
   141  func (attributesHandler *AttributesHandlerImpl) readHeader() (map[string]int, bool, error) {
   142  	if attributesHandler.header != nil {
   143  		return attributesHandler.header, attributesHandler.encrypted, nil
   144  	}
   145  	header, encrypted, err := attributes.ReadAttributeHeader(attributesHandler.cert, attributesHandler.keys[attributes.HeaderAttributeName])
   146  	if err != nil {
   147  		return nil, false, err
   148  	}
   149  	attributesHandler.header = header
   150  	attributesHandler.encrypted = encrypted
   151  	return header, encrypted, nil
   152  }
   153  
   154  //GetValue is used to read an specific attribute from the transaction certificate, *attributeName* is passed as input parameter to this function.
   155  //	Example:
   156  //  	attrValue,error:=handler.GetValue("position")
   157  func (attributesHandler *AttributesHandlerImpl) GetValue(attributeName string) ([]byte, error) {
   158  	if attributesHandler.cache[attributeName] != nil {
   159  		return attributesHandler.cache[attributeName], nil
   160  	}
   161  	header, encrypted, err := attributesHandler.readHeader()
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  	value, err := attributes.ReadTCertAttributeByPosition(attributesHandler.cert, header[attributeName])
   166  	if err != nil {
   167  		return nil, errors.New("Error reading attribute value '" + err.Error() + "'")
   168  	}
   169  
   170  	if encrypted {
   171  		if attributesHandler.keys[attributeName] == nil {
   172  			return nil, errors.New("Cannot find decryption key for attribute")
   173  		}
   174  
   175  		value, err = attributes.DecryptAttributeValue(attributesHandler.keys[attributeName], value)
   176  		if err != nil {
   177  			return nil, errors.New("Error decrypting value '" + err.Error() + "'")
   178  		}
   179  	}
   180  	attributesHandler.cache[attributeName] = value
   181  	return value, nil
   182  }
   183  
   184  //VerifyAttribute is used to verify if the transaction certificate has an attribute with name *attributeName* and value *attributeValue* which are the input parameters received by this function.
   185  //	Example:
   186  //  	containsAttr, error := handler.VerifyAttribute("position", "Software Engineer")
   187  func (attributesHandler *AttributesHandlerImpl) VerifyAttribute(attributeName string, attributeValue []byte) (bool, error) {
   188  	valueHash, err := attributesHandler.GetValue(attributeName)
   189  	if err != nil {
   190  		return false, err
   191  	}
   192  	return bytes.Compare(valueHash, attributeValue) == 0, nil
   193  }
   194  
   195  //VerifyAttributes does the same as VerifyAttribute but it checks for a list of attributes and their respective values instead of a single attribute/value pair
   196  //	Example:
   197  //  	containsAttrs, error:= handler.VerifyAttributes(&ac.Attribute{"position",  "Software Engineer"}, &ac.Attribute{"company", "ACompany"})
   198  func (attributesHandler *AttributesHandlerImpl) VerifyAttributes(attrs ...*accesscontrol.Attribute) (bool, error) {
   199  	for _, attribute := range attrs {
   200  		val, err := attributesHandler.VerifyAttribute(attribute.Name, attribute.Value)
   201  		if err != nil {
   202  			return false, err
   203  		}
   204  		if !val {
   205  			return val, nil
   206  		}
   207  	}
   208  	return true, nil
   209  }