github.com/boxboat/in-toto-golang@v0.0.3-0.20210303203820-2fa16ecbe6f6/in_toto/certconstraint.go (about)

     1  package in_toto
     2  
     3  import (
     4  	"crypto/x509"
     5  	"net/url"
     6  )
     7  
     8  const (
     9  	AllowAllConstraint = "*"
    10  )
    11  
    12  // CertificateConstraint defines the attributes a certificate must have to act as a functionary.
    13  // A wildcard `*` allows any value in the specified attribute, where as an empty array or value
    14  // asserts that the certificate must have nothing for that attribute. A certificate must have
    15  // every value defined in a constraint to match.
    16  type CertificateConstraint struct {
    17  	CommonName string   `json:"common_name"`
    18  	URIs       []string `json:"uris"`
    19  }
    20  
    21  // Check tests the provided certificate against the constraint. True is returned if the certificate
    22  // satisifies the constraint, false will be returned otherwise.
    23  func (cc CertificateConstraint) Check(cert *x509.Certificate) bool {
    24  	if cc.CommonName != AllowAllConstraint && cc.CommonName != cert.Subject.CommonName {
    25  		return false
    26  	}
    27  
    28  	return checkConstraintAttribute(cc.URIs, urisToStrings(cert.URIs))
    29  }
    30  
    31  // urisToStrings is a helper that converts a list of URL objects to the string that represents them
    32  func urisToStrings(uris []*url.URL) []string {
    33  	res := make([]string, 0, len(uris))
    34  	for _, uri := range uris {
    35  		res = append(res, uri.String())
    36  	}
    37  
    38  	return res
    39  }
    40  
    41  // checkConstraintAttribute tests that the provided test values match the allowed values of the constraint.
    42  // All allowed values must be met one-to-one to be considered a successful match.
    43  func checkConstraintAttribute(allowed, test []string) bool {
    44  	if len(allowed) == 1 && allowed[0] == AllowAllConstraint {
    45  		return true
    46  	}
    47  
    48  	unmet := NewSet(allowed...)
    49  	for _, t := range test {
    50  		// if our test has a value we didn't expect, fail early
    51  		if !unmet.Has(t) {
    52  			return false
    53  		}
    54  
    55  		// consider the constraint met
    56  		unmet.Remove(t)
    57  	}
    58  
    59  	// if we have any unmet left after going through each test value, fail.
    60  	return len(unmet) == 0
    61  }