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 }