github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/accesscontrol/attributes/attributes.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 attributes
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/x509"
    22  	"encoding/asn1"
    23  	"errors"
    24  	"fmt"
    25  	"strconv"
    26  	"strings"
    27  
    28  	pb "github.com/hyperledger/fabric/accesscontrol/attributes/proto"
    29  	"github.com/hyperledger/fabric/core/crypto/primitives"
    30  
    31  	"github.com/golang/protobuf/proto"
    32  	"github.com/hyperledger/fabric/accesscontrol/crypto/utils"
    33  )
    34  
    35  var (
    36  	// TCertEncAttributesBase is the base ASN1 object identifier for attributes.
    37  	// When generating an extension to include the attribute an index will be
    38  	// appended to this Object Identifier.
    39  	TCertEncAttributesBase = asn1.ObjectIdentifier{1, 2, 3, 4, 5, 6}
    40  
    41  	// TCertAttributesHeaders is the ASN1 object identifier of attributes header.
    42  	TCertAttributesHeaders = asn1.ObjectIdentifier{1, 2, 3, 4, 5, 6, 9}
    43  
    44  	padding = []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
    45  
    46  	//headerPrefix is the prefix used in the header extension of the certificate.
    47  	headerPrefix = "00HEAD"
    48  
    49  	//HeaderAttributeName is the name used to derive the K used to encrypt/decrypt the header.
    50  	HeaderAttributeName = "attributeHeader"
    51  )
    52  
    53  //ParseAttributesHeader parses a string and returns a map with the attributes.
    54  func ParseAttributesHeader(header string) (map[string]int, error) {
    55  	if !strings.HasPrefix(header, headerPrefix) {
    56  		return nil, errors.New("Invalid header")
    57  	}
    58  	headerBody := strings.Replace(header, headerPrefix, "", 1)
    59  	tokens := strings.Split(headerBody, "#")
    60  	result := make(map[string]int)
    61  
    62  	for _, token := range tokens {
    63  		pair := strings.Split(token, "->")
    64  
    65  		if len(pair) == 2 {
    66  			key := pair[0]
    67  			valueStr := pair[1]
    68  			value, err := strconv.Atoi(valueStr)
    69  			if err != nil {
    70  				return nil, err
    71  			}
    72  			result[key] = value
    73  		}
    74  	}
    75  
    76  	return result, nil
    77  }
    78  
    79  //ReadAttributeHeader read the header of the attributes.
    80  func ReadAttributeHeader(tcert *x509.Certificate, headerKey []byte) (map[string]int, bool, error) {
    81  	var err error
    82  	var headerRaw []byte
    83  	encrypted := false
    84  	if headerRaw, err = utils.GetCriticalExtension(tcert, TCertAttributesHeaders); err != nil {
    85  		return nil, encrypted, err
    86  	}
    87  	headerStr := string(headerRaw)
    88  	var header map[string]int
    89  	header, err = ParseAttributesHeader(headerStr)
    90  	if err != nil {
    91  		if headerKey == nil {
    92  			return nil, false, errors.New("Is not possible read an attribute encrypted without the headerKey")
    93  		}
    94  		headerRaw, err = DecryptAttributeValue(headerKey, headerRaw)
    95  
    96  		if err != nil {
    97  			return nil, encrypted, errors.New("error decrypting header value '" + err.Error() + "''")
    98  		}
    99  		headerStr = string(headerRaw)
   100  		header, err = ParseAttributesHeader(headerStr)
   101  		if err != nil {
   102  			return nil, encrypted, err
   103  		}
   104  		encrypted = true
   105  	}
   106  	return header, encrypted, nil
   107  }
   108  
   109  //ReadTCertAttributeByPosition read the attribute stored in the position "position" of the tcert.
   110  func ReadTCertAttributeByPosition(tcert *x509.Certificate, position int) ([]byte, error) {
   111  	if position <= 0 {
   112  		return nil, fmt.Errorf("Invalid attribute position. Received [%v]", position)
   113  	}
   114  
   115  	oid := asn1.ObjectIdentifier{1, 2, 3, 4, 5, 6, 9 + position}
   116  	value, err := utils.GetCriticalExtension(tcert, oid)
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  	return value, nil
   121  }
   122  
   123  //ReadTCertAttribute read the attribute with name "attributeName" and returns the value and a boolean indicating if the returned value is encrypted or not.
   124  func ReadTCertAttribute(tcert *x509.Certificate, attributeName string, headerKey []byte) ([]byte, bool, error) {
   125  	header, encrypted, err := ReadAttributeHeader(tcert, headerKey)
   126  	if err != nil {
   127  		return nil, false, err
   128  	}
   129  	position := header[attributeName]
   130  	if position == 0 {
   131  		return nil, encrypted, errors.New("Failed attribute '" + attributeName + "' doesn't exists in the TCert.")
   132  	}
   133  	value, err := ReadTCertAttributeByPosition(tcert, position)
   134  	if err != nil {
   135  		return nil, encrypted, err
   136  	}
   137  	return value, encrypted, nil
   138  }
   139  
   140  //EncryptAttributeValue encrypts "attributeValue" using "attributeKey"
   141  func EncryptAttributeValue(attributeKey []byte, attributeValue []byte) ([]byte, error) {
   142  	value := append(attributeValue, padding...)
   143  	return utils.CBCPKCS7Encrypt(attributeKey, value)
   144  }
   145  
   146  //getAttributeKey returns the attributeKey derived from the preK0 to the attributeName.
   147  func getAttributeKey(preK0 []byte, attributeName string) []byte {
   148  	return primitives.HMACTruncated(preK0, []byte(attributeName), 32)
   149  }
   150  
   151  //EncryptAttributeValuePK0 encrypts "attributeValue" using a key derived from preK0.
   152  func EncryptAttributeValuePK0(preK0 []byte, attributeName string, attributeValue []byte) ([]byte, error) {
   153  	attributeKey := getAttributeKey(preK0, attributeName)
   154  	return EncryptAttributeValue(attributeKey, attributeValue)
   155  }
   156  
   157  //DecryptAttributeValue decrypts "encryptedValue" using "attributeKey" and return the decrypted value.
   158  func DecryptAttributeValue(attributeKey []byte, encryptedValue []byte) ([]byte, error) {
   159  	value, err := utils.CBCPKCS7Decrypt(attributeKey, encryptedValue)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	lenPadding := len(padding)
   164  	lenValue := len(value)
   165  	if lenValue < lenPadding {
   166  		return nil, errors.New("Error invalid value. Decryption verification failed.")
   167  	}
   168  	lenWithoutPadding := lenValue - lenPadding
   169  	if bytes.Compare(padding[0:lenPadding], value[lenWithoutPadding:lenValue]) != 0 {
   170  		return nil, errors.New("Error generating decryption key for value. Decryption verification failed.")
   171  	}
   172  	value = value[0:lenWithoutPadding]
   173  	return value, nil
   174  }
   175  
   176  //getKAndValueForAttribute derives K for the attribute "attributeName", checks the value padding and returns both key and decrypted value
   177  func getKAndValueForAttribute(attributeName string, preK0 []byte, cert *x509.Certificate) ([]byte, []byte, error) {
   178  	headerKey := getAttributeKey(preK0, HeaderAttributeName)
   179  	value, encrypted, err := ReadTCertAttribute(cert, attributeName, headerKey)
   180  	if err != nil {
   181  		return nil, nil, err
   182  	}
   183  
   184  	attributeKey := getAttributeKey(preK0, attributeName)
   185  	if encrypted {
   186  		value, err = DecryptAttributeValue(attributeKey, value)
   187  		if err != nil {
   188  			return nil, nil, err
   189  		}
   190  	}
   191  	return attributeKey, value, nil
   192  }
   193  
   194  //GetKForAttribute derives the K for the attribute "attributeName" and returns the key
   195  func GetKForAttribute(attributeName string, preK0 []byte, cert *x509.Certificate) ([]byte, error) {
   196  	key, _, err := getKAndValueForAttribute(attributeName, preK0, cert)
   197  	return key, err
   198  }
   199  
   200  //GetValueForAttribute derives the K for the attribute "attributeName" and returns the value
   201  func GetValueForAttribute(attributeName string, preK0 []byte, cert *x509.Certificate) ([]byte, error) {
   202  	_, value, err := getKAndValueForAttribute(attributeName, preK0, cert)
   203  	return value, err
   204  }
   205  
   206  func createAttributesHeaderEntry(preK0 []byte) *pb.AttributesMetadataEntry {
   207  	attKey := getAttributeKey(preK0, HeaderAttributeName)
   208  	return &pb.AttributesMetadataEntry{AttributeName: HeaderAttributeName, AttributeKey: attKey}
   209  }
   210  
   211  func createAttributesMetadataEntry(attributeName string, preK0 []byte) *pb.AttributesMetadataEntry {
   212  	attKey := getAttributeKey(preK0, attributeName)
   213  	return &pb.AttributesMetadataEntry{AttributeName: attributeName, AttributeKey: attKey}
   214  }
   215  
   216  //CreateAttributesMetadataObjectFromCert creates an AttributesMetadata object from certificate "cert", metadata and the attributes keys.
   217  func CreateAttributesMetadataObjectFromCert(cert *x509.Certificate, metadata []byte, preK0 []byte, attributeKeys []string) *pb.AttributesMetadata {
   218  	var entries []*pb.AttributesMetadataEntry
   219  	for _, key := range attributeKeys {
   220  		if len(key) == 0 {
   221  			continue
   222  		}
   223  
   224  		entry := createAttributesMetadataEntry(key, preK0)
   225  		entries = append(entries, entry)
   226  	}
   227  	headerEntry := createAttributesHeaderEntry(preK0)
   228  	entries = append(entries, headerEntry)
   229  
   230  	return &pb.AttributesMetadata{Metadata: metadata, Entries: entries}
   231  }
   232  
   233  //CreateAttributesMetadataFromCert creates the AttributesMetadata from the original metadata and certificate "cert".
   234  func CreateAttributesMetadataFromCert(cert *x509.Certificate, metadata []byte, preK0 []byte, attributeKeys []string) ([]byte, error) {
   235  	attributesMetadata := CreateAttributesMetadataObjectFromCert(cert, metadata, preK0, attributeKeys)
   236  
   237  	return proto.Marshal(attributesMetadata)
   238  }
   239  
   240  //CreateAttributesMetadata create the AttributesMetadata from the original metadata
   241  func CreateAttributesMetadata(raw []byte, metadata []byte, preK0 []byte, attributeKeys []string) ([]byte, error) {
   242  	cert, err := utils.DERToX509Certificate(raw)
   243  	if err != nil {
   244  		return nil, err
   245  	}
   246  
   247  	return CreateAttributesMetadataFromCert(cert, metadata, preK0, attributeKeys)
   248  }
   249  
   250  //GetAttributesMetadata object from the original metadata "metadata".
   251  func GetAttributesMetadata(metadata []byte) (*pb.AttributesMetadata, error) {
   252  	attributesMetadata := &pb.AttributesMetadata{}
   253  	err := proto.Unmarshal(metadata, attributesMetadata)
   254  	return attributesMetadata, err
   255  }
   256  
   257  //BuildAttributesHeader builds a header attribute from a map of attribute names and positions.
   258  func BuildAttributesHeader(attributesHeader map[string]int) ([]byte, error) {
   259  	var header []byte
   260  	var headerString string
   261  	var positions = make(map[int]bool)
   262  
   263  	for k, v := range attributesHeader {
   264  		if positions[v] {
   265  			return nil, errors.New("Duplicated position found in attributes header")
   266  		}
   267  		positions[v] = true
   268  
   269  		vStr := strconv.Itoa(v)
   270  		headerString = headerString + k + "->" + vStr + "#"
   271  	}
   272  	header = []byte(headerPrefix + headerString)
   273  	return header, nil
   274  }