@@ -26,7 +26,13 @@ Please review third_party pinning scripts and patches for more details.
2626package attrmgr
2727
2828import (
29+ "crypto/x509"
30+ "crypto/x509/pkix"
2931 "encoding/asn1"
32+ "encoding/json"
33+ "fmt"
34+
35+ "github.com/pkg/errors"
3036)
3137
3238var (
@@ -53,10 +59,156 @@ type AttributeRequest interface {
5359 IsRequired () bool
5460}
5561
62+ // New constructs an attribute manager
63+ func New () * Mgr { return & Mgr {} }
64+
5665// Mgr is the attribute manager and is the main object for this package
5766type Mgr struct {}
5867
68+ // ProcessAttributeRequestsForCert add attributes to an X509 certificate, given
69+ // attribute requests and attributes.
70+ func (mgr * Mgr ) ProcessAttributeRequestsForCert (requests []AttributeRequest , attributes []Attribute , cert * x509.Certificate ) error {
71+ attrs , err := mgr .ProcessAttributeRequests (requests , attributes )
72+ if err != nil {
73+ return err
74+ }
75+ return mgr .AddAttributesToCert (attrs , cert )
76+ }
77+
78+ // ProcessAttributeRequests takes an array of attribute requests and an identity's attributes
79+ // and returns an Attributes object containing the requested attributes.
80+ func (mgr * Mgr ) ProcessAttributeRequests (requests []AttributeRequest , attributes []Attribute ) (* Attributes , error ) {
81+ attrsMap := map [string ]string {}
82+ attrs := & Attributes {Attrs : attrsMap }
83+ missingRequiredAttrs := []string {}
84+ // For each of the attribute requests
85+ for _ , req := range requests {
86+ // Get the attribute
87+ name := req .GetName ()
88+ attr := getAttrByName (name , attributes )
89+ if attr == nil {
90+ if req .IsRequired () {
91+ // Didn't find attribute and it was required; return error below
92+ missingRequiredAttrs = append (missingRequiredAttrs , name )
93+ }
94+ // Skip attribute requests which aren't required
95+ continue
96+ }
97+ attrsMap [name ] = attr .GetValue ()
98+ }
99+ if len (missingRequiredAttrs ) > 0 {
100+ return nil , errors .Errorf ("The following required attributes are missing: %+v" ,
101+ missingRequiredAttrs )
102+ }
103+ return attrs , nil
104+ }
105+
106+ // AddAttributesToCert adds public attribute info to an X509 certificate.
107+ func (mgr * Mgr ) AddAttributesToCert (attrs * Attributes , cert * x509.Certificate ) error {
108+ buf , err := json .Marshal (attrs )
109+ if err != nil {
110+ return errors .Wrap (err , "Failed to marshal attributes" )
111+ }
112+ ext := pkix.Extension {
113+ Id : AttrOID ,
114+ Critical : false ,
115+ Value : buf ,
116+ }
117+ cert .Extensions = append (cert .Extensions , ext )
118+ return nil
119+ }
120+
121+ // GetAttributesFromCert gets the attributes from a certificate.
122+ func (mgr * Mgr ) GetAttributesFromCert (cert * x509.Certificate ) (* Attributes , error ) {
123+ // Get certificate attributes from the certificate if it exists
124+ buf , err := getAttributesFromCert (cert )
125+ if err != nil {
126+ return nil , err
127+ }
128+ // Unmarshal into attributes object
129+ attrs := & Attributes {}
130+ if buf != nil {
131+ err := json .Unmarshal (buf , attrs )
132+ if err != nil {
133+ return nil , errors .Wrap (err , "Failed to unmarshal attributes from certificate" )
134+ }
135+ }
136+ return attrs , nil
137+ }
138+
59139// Attributes contains attribute names and values
60140type Attributes struct {
61141 Attrs map [string ]string `json:"attrs"`
62142}
143+
144+ // Names returns the names of the attributes
145+ func (a * Attributes ) Names () []string {
146+ i := 0
147+ names := make ([]string , len (a .Attrs ))
148+ for name := range a .Attrs {
149+ names [i ] = name
150+ i ++
151+ }
152+ return names
153+ }
154+
155+ // Contains returns true if the named attribute is found
156+ func (a * Attributes ) Contains (name string ) bool {
157+ _ , ok := a .Attrs [name ]
158+ return ok
159+ }
160+
161+ // Value returns an attribute's value
162+ func (a * Attributes ) Value (name string ) (string , bool , error ) {
163+ attr , ok := a .Attrs [name ]
164+ return attr , ok , nil
165+ }
166+
167+ // True returns nil if the value of attribute 'name' is true;
168+ // otherwise, an appropriate error is returned.
169+ func (a * Attributes ) True (name string ) error {
170+ val , ok , err := a .Value (name )
171+ if err != nil {
172+ return err
173+ }
174+ if ! ok {
175+ return fmt .Errorf ("Attribute '%s' was not found" , name )
176+ }
177+ if val != "true" {
178+ return fmt .Errorf ("Attribute '%s' is not true" , name )
179+ }
180+ return nil
181+ }
182+
183+ // Get the attribute info from a certificate extension, or return nil if not found
184+ func getAttributesFromCert (cert * x509.Certificate ) ([]byte , error ) {
185+ for _ , ext := range cert .Extensions {
186+ if isAttrOID (ext .Id ) {
187+ return ext .Value , nil
188+ }
189+ }
190+ return nil , nil
191+ }
192+
193+ // Is the object ID equal to the attribute info object ID?
194+ func isAttrOID (oid asn1.ObjectIdentifier ) bool {
195+ if len (oid ) != len (AttrOID ) {
196+ return false
197+ }
198+ for idx , val := range oid {
199+ if val != AttrOID [idx ] {
200+ return false
201+ }
202+ }
203+ return true
204+ }
205+
206+ // Get an attribute from 'attrs' by its name, or nil if not found
207+ func getAttrByName (name string , attrs []Attribute ) Attribute {
208+ for _ , attr := range attrs {
209+ if attr .GetName () == name {
210+ return attr
211+ }
212+ }
213+ return nil
214+ }
0 commit comments