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 }