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