safing-jess/requirements.go
2021-10-01 13:58:26 +02:00

161 lines
3.8 KiB
Go

package jess
import (
"fmt"
"strings"
)
// Security requirements of a letter.
const (
Confidentiality uint8 = iota
Integrity
RecipientAuthentication
SenderAuthentication
)
// Requirements describe security properties.
type Requirements struct {
all []uint8
}
// newEmptyRequirements returns an empty requirements instance.
func newEmptyRequirements() *Requirements {
return &Requirements{}
}
// NewRequirements returns an attribute instance with all requirements.
func NewRequirements() *Requirements {
return &Requirements{
all: []uint8{
Confidentiality,
Integrity,
RecipientAuthentication,
SenderAuthentication,
},
}
}
// Empty returns whether the requirements are empty.
func (requirements *Requirements) Empty() bool {
return len(requirements.all) == 0
}
// Has returns whether the requirements contain the given attribute.
func (requirements *Requirements) Has(attribute uint8) bool {
for _, attr := range requirements.all {
if attr == attribute {
return true
}
}
return false
}
// Add adds an attribute.
func (requirements *Requirements) Add(attribute uint8) *Requirements {
if !requirements.Has(attribute) {
requirements.all = append(requirements.all, attribute)
}
return requirements
}
// Remove removes an attribute.
func (requirements *Requirements) Remove(attribute uint8) *Requirements {
for i, attr := range requirements.all {
if attr == attribute {
requirements.all = append(requirements.all[:i], requirements.all[i+1:]...)
return requirements
}
}
return requirements
}
// CheckComplianceTo checks if the requirements are compliant to the given required requirements.
func (requirements *Requirements) CheckComplianceTo(requirement *Requirements) error {
var missing *Requirements
for _, attr := range requirement.all {
if !requirements.Has(attr) {
if missing == nil {
missing = newEmptyRequirements()
}
missing.Add(attr)
}
}
if missing != nil {
return fmt.Errorf("missing security requirements: %s", missing.String())
}
return nil
}
// String returns a string representation of the requirements.
func (requirements *Requirements) String() string {
var names []string
for _, attr := range requirements.all {
switch attr {
case Confidentiality:
names = append(names, "Confidentiality")
case Integrity:
names = append(names, "Integrity")
case RecipientAuthentication:
names = append(names, "RecipientAuthentication")
case SenderAuthentication:
names = append(names, "SenderAuthentication")
}
}
return strings.Join(names, ", ")
}
// ShortString returns a short string representation of the requirements.
func (requirements *Requirements) ShortString() string {
var s string
if requirements.Has(Confidentiality) {
s += "C"
}
if requirements.Has(Integrity) {
s += "I"
}
if requirements.Has(RecipientAuthentication) {
s += "R"
}
if requirements.Has(SenderAuthentication) {
s += "S"
}
return s
}
// SerializeToNoSpec returns the requirements as a negated "No" string.
func (requirements *Requirements) SerializeToNoSpec() string {
var s string
if !requirements.Has(Confidentiality) {
s += "C"
}
if !requirements.Has(Integrity) {
s += "I"
}
if !requirements.Has(RecipientAuthentication) {
s += "R"
}
if !requirements.Has(SenderAuthentication) {
s += "S"
}
return s
}
// ParseRequirementsFromNoSpec parses the requirements from a negated "No" string.
func ParseRequirementsFromNoSpec(no string) (*Requirements, error) {
requirements := NewRequirements()
for _, id := range no {
switch id {
case 'C':
requirements.Remove(Confidentiality)
case 'I':
requirements.Remove(Integrity)
case 'R':
requirements.Remove(RecipientAuthentication)
case 'S':
requirements.Remove(SenderAuthentication)
default:
return nil, fmt.Errorf("unknown attribute identifier: %c", id)
}
}
return requirements, nil
}