DR-003-ARCH-ACL-Concept: Common Access Control format for all components#

One Format for Access Control (and following the Access Control List (ACL))
status: proposed
context: Common Access Control format for all components
decision: open
version: 0

Context#

Access Control is required on multiple components; i.e.:

  • IPC (LoLa) Who is allowed to publish which services (who can create/modify a file in the according directory) For Service Providers: Once the IPC Channel/SharedMemory is created, whom to grant which rights to what area (data/control) This permissions will be based on uid.

  • SOME/IP Same to IPC, except the permissions will be based on IP address / netmask. In addition: Should TLS be enforced for a service? Should IP & MACsec be active as basis for a certain service?

  • Crypto Needs to know who (which application - i.e. which uid (every application shall run as own user)) – created/owns a key – is allowed to write/change a key – is allowed to use a key for any operations (e.g. sign/verify/encrypt/decrypt/keyderive/etc.) – is allowed to read/extract a key (e.g. pub keys)

Consequences#

To prevent each component from implementing completley own mechanism for permission enforcement; the decision should be an alignment on a common ACL format, so that all components can use:

  • the same parser as a baselib to read the ACL

  • (optionally) the same “ACLHandler” to update/edit and recompile the ACL One additional big advantage of a harmonized ACL is that:

  • it is easier to review (security reviews, etc.)

  • it is easier to debug

  • only one parser needs to be tested in depth

  • updates due to parser vulnerabilities can be centralized

The base proposal is as follows:

  • a json file as configuration

  • for runtime efficiency: compilation of the json file to a flatbuffer/binary file

Proposed json format & properties (example at the bottom):

proposed json scheme:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "acl-policy.schema.json",
  "title": "ACL Configuration Schema",
  "type": "object",
  "additionalProperties": false,
  "required": [
	"policyVersion",
	"policyId",
	"defaultEffect",
	"generatedBy",
	"generatedAt",
	"services"
  ],
  "properties": {
	"policyVersion": {
	  "type": "integer",
	  "minimum": 1
	},
	"policyId": {
	  "type": "string",
	  "minLength": 1,
	  "maxLength": 128
	},
	"defaultEffect": {
	  "type": "string",
	  "enum": [
		"deny",
		"allow"
	  ],
	  "maxLength": 128
	},
	"generatedBy": {
	  "type": "string",
	  "minLength": 1,
	  "maxLength": 128
	},
	"generatedAt": {
	  "type": "string",
	  "description": "ISO-8601 UTC timestamp without fractional seconds",
	  "maxLength": 20,
	  "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$"
	},
	"services": {
	  "type": "object",
	  "propertyNames": {
		"$ref": "#/$defs/uint16Key"
	  },
	  "additionalProperties": {
		"$ref": "#/$defs/service"
	  }
	},
	"crypto": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"keyspaces"
	  ],
	  "properties": {
		"profiles": {
		  "type": "object",
		  "propertyNames": {
			"$ref": "#/$defs/uint16Key"
		  },
		  "additionalProperties": {
			"$ref": "#/$defs/cryptoProfile"
		  }
		},
		"operationalRights": {
		  "type": "object",
		  "propertyNames": {
			"$ref": "#/$defs/subjectKey"
		  },
		  "additionalProperties": {
			"$ref": "#/$defs/operationalRight"
		  }
		},
		"keyspaces": {
		  "type": "object",
		  "propertyNames": {
			"$ref": "#/$defs/uint16Key"
		  },
		  "additionalProperties": {
			"$ref": "#/$defs/keyspace"
		  }
		},
		"certspace": {
		  "type": "object",
		  "propertyNames": {
			"$ref": "#/$defs/uint16Key"
		  },
		  "additionalProperties": {
			"$ref": "#/$defs/certspace"
		  }
		}
	  }
	}
  },
  "$defs": {
    "version": {
	  "type": "array",
	  "items": {
	    "anyOf": [
		  {
			"type": "integer",
			"minimum": 0,
			"maximum": 65535
		  },
		  {
			"type": "string",
			"maxLength": 128
		  }
		]
	  }
	},
	"uint16Key": {
	  "type": "string",
	  "pattern": "^(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$"
	},
	"uidKey": {
	  "type": "string",
	  "pattern": "^(0|[1-9][0-9]{0,8}|1[0-9]{9}|20[0-9]{8}|21[0-3][0-9]{7}|214[0-6][0-9]{6}|2147[0-3][0-9]{5}|21474[0-7][0-9]{4}|214748[0-2][0-9]{3}|2147483[0-5][0-9]{2}|21474836[0-3][0-9]|214748364[0-7])$"
	},
	"binaryFlag": {
	  "type": "integer",
	  "enum": [
		0,
		1
	  ]
	},
	"specifics": {
	  "description": "OEM-specific or project-specific extension object. Unknown properties are allowed only here.",
	  "type": "object",
	  "additionalProperties": {
		"$ref": "#/$defs/specificValue"
	  }
	},
	"specificValue": {
	  "anyOf": [
		{
		  "type": "string",
		  "maxLength": 128
		},
		{
		  "type": "number"
		},
		{
		  "type": "integer"
		},
		{
		  "type": "boolean"
		},
		{
		  "type": "null"
		},
		{
		  "type": "array",
		  "items": {
			"$ref": "#/$defs/specificValue"
		  }
		},
		{
		  "type": "object",
		  "additionalProperties": {
			"$ref": "#/$defs/specificValue"
		  }
		}
	  ]
	},
	"service": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"serviceName",
		"serviceInstances"
	  ],
	  "properties": {
		"serviceName": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"serviceInstances": {
		  "type": "object",
		  "propertyNames": {
			"$ref": "#/$defs/uint16Key"
		  },
		  "additionalProperties": {
			"$ref": "#/$defs/serviceInstance"
		  }
		}
	  }
	},
	"serviceInstance": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"providerName",
		"version",
		"precondition_tlsenabled",
		"precondition_ipsecenabled",
		"precondition_macsecenabled",
		"specifics",
		"allow"
	  ],
	  "properties": {
		"providerName": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"version": {
		  "type": "integer",
		  "minimum": 0,
		  "maximum": 65535
		},
		"precondition_tlsenabled": {
		  "$ref": "#/$defs/binaryFlag"
		},
		"precondition_ipsecenabled": {
		  "$ref": "#/$defs/binaryFlag"
		},
		"precondition_macsecenabled": {
		  "$ref": "#/$defs/binaryFlag"
		},
		"specifics": {
		  "$ref": "#/$defs/specifics"
		},
		"allow": {
		  "$ref": "#/$defs/allow"
		}
	  }
	},
	"allow": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"uids",
		"ips"
	  ],
	  "properties": {
		"uids": {
		  "type": "object",
		  "propertyNames": {
			"$ref": "#/$defs/uidKey"
		  },
		  "additionalProperties": {
			"$ref": "#/$defs/uidSubject"
		  }
		},
		"ips": {
		  "type": "object",
		  "propertyNames": {
			"$ref": "#/$defs/ipOrCidrKey"
		  },
		  "additionalProperties": {
			"$ref": "#/$defs/ipSubject"
		  }
		}
	  }
	},
	"uidSubject": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"name",
		"rights",
		"specifics"
	  ],
	  "properties": {
		"name": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"rights": {
		  "$ref": "com.rights.schema.json"
		},
		"version": {
		  "$ref": "#/$defs/version"
		},
		"specifics": {
		  "$ref": "#/$defs/specifics"
		}
	  }
	},
	"ipSubject": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"name",
		"rights",
		"specifics"
	  ],
	  "properties": {
		"name": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"rights": {
		  "$ref": "com.rights.schema.json"
		},
		"specifics": {
		  "$ref": "#/$defs/specifics"
		},
		"version": {
		  "$ref": "#/$defs/version"
		}
	  }
	},
	"ipOrCidrKey": {
	  "type": "string",
	  "maxLength": 128,
	  "anyOf": [
		{
		  "description": "IPv4 address",
		  "pattern": "^(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}$"
		},
		{
		  "description": "IPv4 CIDR subnet",
		  "pattern": "^(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}\\/(3[0-2]|[1-2]?[0-9])$"
		},
		{
		  "description": "IPv6 address or IPv6 CIDR subnet, simplified validation",
		  "pattern": "^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}(\\/(12[0-8]|1[0-1][0-9]|[1-9]?[0-9]))?$"
		}
	  ]
	},
	"keyspace": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"keyspaceName",
		"keys"
	  ],
	  "properties": {
		"keyspaceName": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"keys": {
		  "type": "object",
		  "propertyNames": {
			"$ref": "#/$defs/uint16Key"
		  },
		  "additionalProperties": {
			"$ref": "#/$defs/key"
		  }
		}
	  }
	},
	"key": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"name",
		"read",
		"use",
		"write"
	  ],
	  "properties": {
		"name": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"read": {
		  "$ref": "#/$defs/keyAccessMap"
		},
		"use": {
		  "$ref": "#/$defs/keyAccessMap"
		},
		"write": {
		  "$ref": "#/$defs/keyAccessMap"
		}
	  }
	},
	"subjectKey": {
      "type": "string",
      "maxLength": 512,
      "description": "Canonical access subject key. Components use '=' and are separated by '|'. Fixed order: otherid, vmid, uid, policy. Components in one key have AND semantics.",
      "oneOf": [
        {
          "description": "UID only, optionally followed by policy",
          "pattern": "^uid=(-1|0|[1-9][0-9]{0,9})(\\|policy=[A-Za-z0-9._-]+)?$"
        },
        {
          "description": "VMID and UID, optionally followed by policy",
          "pattern": "^vmid=(0|[1-9][0-9]{0,9})\\|uid=(-1|0|[1-9][0-9]{0,9})(\\|policy=[A-Za-z0-9._-]+)?$"
        },
        {
          "description": "Other ID alone, or with UID, optionally followed by policy",
          "pattern": "^otherid=[A-Za-z0-9._-]+(\\|uid=(-1|0|[1-9][0-9]{0,9}))?(\\|policy=[A-Za-z0-9._-]+)?$"
        },
        {
          "description": "Other ID, VMID and UID, optionally followed by policy",
          "pattern": "^otherid=[A-Za-z0-9._-]+\\|vmid=(0|[1-9][0-9]{0,9})\\|uid=(-1|0|[1-9][0-9]{0,9})(\\|policy=[A-Za-z0-9._-]+)?$"
        },
        {
          "description": "Policy only",
          "pattern": "^policy=[A-Za-z0-9._-]+$"
        }
      ]
    },
    "cryptoOperation": {
      "type": "string",
      "enum": [
        "hash",
        "encrypt",
        "decrypt",
        "sign",
        "verify",
        "keyderive",
        "wrap",
        "unwrap",
        "mac",
        "random",
        "keygen",
        "keyimport",
        "keyexport",
        "keydelete"
      ]
    },
    "keyAccessOptions": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "operations": {
          "description": "Optional restriction to the listed cryptographic operations. If absent, the access category itself is not further restricted by operation.",
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "items": {
            "$ref": "#/$defs/cryptoOperation"
          }
        }
      }
    },
	"keyAccessMap": {
	  "type": "object",
	  "propertyNames": {
		"$ref": "#/$defs/subjectKey"
	  },
      "additionalProperties": {
        "$ref": "#/$defs/keyAccessOptions"
      }
	},
	"certspaceOperation": {
	  "type": "string",
	  "enum": [
		"add",
		"remove"
	  ]
	},
	"certspaceAccessOptions": {
	  "type": "object",
	  "additionalProperties": false,
	  "properties": {
		"operations": {
		  "type": "array",
		  "minItems": 1,
		  "uniqueItems": true,
		  "items": {
			"$ref": "#/$defs/certspaceOperation"
		  }
		}
	  }
	},
	"certspaceRights": {
	  "type": "object",
	  "propertyNames": {
		"$ref": "#/$defs/subjectKey"
	  },
	  "additionalProperties": {
		"$ref": "#/$defs/certspaceAccessOptions"
	  }
	},
	"cert": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"name"
	  ],
	  "properties": {
		"name": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"read": {
		  "$ref": "#/$defs/keyAccessMap"
		},
		"use": {
		  "$ref": "#/$defs/keyAccessMap"
		},
		"write": {
		  "$ref": "#/$defs/keyAccessMap"
		},
		"removeable": {
		  "description": "If false, this certificate cannot be removed, even if certspaceRights grants the remove operation.",
		  "type": "boolean"
		}
	  }
	},
	"certspace": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"certspaceName",
		"defaultReadDeny",
		"defaultWriteDeny",
		"defaultUseDeny",
		"certspaceRights"
	  ],
	  "properties": {
		"certspaceName": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 128
		},
		"defaultReadDeny": {
		  "type": "boolean"
		},
		"defaultWriteDeny": {
		  "type": "boolean"
		},
		"defaultUseDeny": {
		  "type": "boolean"
		},
		"certspaceRights": {
		  "$ref": "#/$defs/certspaceRights"
		},
		"certs": {
		  "type": "object",
		  "propertyNames": {
			"$ref": "#/$defs/uint16Key"
		  },
		  "additionalProperties": {
			"$ref": "#/$defs/cert"
		  }
		}
	  }
	},    
	"memoryLimiting": {
	  "type": "object",
	  "additionalProperties": false,
	  "minProperties": 1,
	  "properties": {
		"bytes": {
		  "type": "integer",
		  "minimum": 0
		},
		"slots": {
		  "type": "integer",
		  "minimum": 0
		}
	  }
	},
	"jobLimiting": {
	  "oneOf": [
		{
		  "type": "object",
		  "additionalProperties": false,
		  "required": ["parallel"],
		  "properties": {
			"parallel": {
			  "type": "integer",
			  "minimum": 1
			}
		  }
		},
		{
		  "type": "object",
		  "additionalProperties": false,
		  "required": ["interval", "intervaltype"],
		  "properties": {
			"interval": {
			  "type": "integer",
			  "minimum": 1
			},
			"intervaltype": {
			  "type": "string",
			  "enum": ["cycle", "second"]
			}
		  }
		}
	  ]
	},
	"cryptoProviderRights": {
	  "type": "object",
	  "additionalProperties": false,
	  "properties": {
		"nonKeyspaceDependent": {
		  "description": "Operations not using a key from a configured keyspace, including operations where the caller supplies the key with the request.",
		  "type": "array",
		  "minItems": 1,
		  "uniqueItems": true,
		  "items": {
			"$ref": "#/$defs/cryptoOperation"
		  }
		},
		"memoryLimiting": {
		  "$ref": "#/$defs/memoryLimiting"
		},
		"jobLimiting": {
		  "$ref": "#/$defs/jobLimiting"
		}
	  }
	},
	"cryptoRights": {
	  "type": "object",
	  "minProperties": 1,
	  "propertyNames": {
		"type": "string",
		"minLength": 1,
		"maxLength": 48
	  },
	  "additionalProperties": {
		"$ref": "#/$defs/cryptoProviderRights"
	  }
	},
	"cryptoProfile": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": [
		"profileName",
		"rights"
	  ],
	  "properties": {
		"profileName": {
		  "type": "string",
		  "minLength": 1,
		  "maxLength": 48
		},
		"rights": {
		  "$ref": "#/$defs/cryptoRights"
		}
	  }
	},
	"profileReference": {
	  "type": "object",
	  "additionalProperties": false,
	  "required": ["profileId"],
	  "properties": {
		"profileId": {
		  "$ref": "#/$defs/uint16Key"
		}
	  }
	},
	"operationalRight": {
	  "oneOf": [
		{
		  "$ref": "#/$defs/cryptoRights"
		},
		{
		  "$ref": "#/$defs/profileReference"
		}
	  ]
	}
  }
}

Own rights schema which (can be if required adapted) for communication (IPC, SOME/IP) Default support for: read := subscribe/1:1/consume/request aka receive response write := publish/1:1/produce/send response monitor := observe, without ability to lock while reading or influence the program flow

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "com.rights.schema.json",
  "title": "Access Control for Communication Schema",
  "description": "Allowed access rights for communication.",
  "type": "array",
  "items": {
    "type": "string",
    "enum": [
      "read",
      "write",
      "monitor"
    ],
    "maxLength": 128
  },
  "uniqueItems": true
}

Example:

{
  "policyVersion": 1,
  "policyId": "example-acl-policy-001",
  "defaultEffect": "deny",
  "generatedBy": "install-update-manager",
  "generatedAt": "2026-06-17T14:28:00Z",

  "services": 
  {
	"111":
	{
	  "serviceName": "someservice",
	  "serviceInstances": {
		"500":
		{
		  "providerName": "fancy_name",		  
		  "version": 5,
		  "precondition_tlsenabled": 1,
		  "precondition_ipsecenabled": 1,
		  "precondition_macsecenabled":1,			  
		  "specifics": {},
		  "allow": 
		  {
			"uids": 
			{
			  "101":{"rights": ["write"],"name": "oem.app.1","version": [],"specifics": {}},
			  "102":{"rights": ["read"],"name": "oem.app.2","version": [],"specifics": {}},
			  "103":{"rights": ["read"],"name": "tier1.daemon.1","version": [],"specifics": {}}
			},
			"ips": 
			{ 
				"10.1.15.2":{"name": "ecu_1","rights": ["write"],"version": [],"specifics": {}},
				"10.1.15.3":{"name": "ecu_2_app3","rights": ["read"],"version": [],"specifics": {}}
			}
		  }
		}
	  }
	}
  },
  "crypto": 
  {
	"profiles":
	{
		"1":
		{
			"profileName":"encrypt_and_sign_software",
			"rights":
			{
				"Software":
				{
					"nonKeyspaceDependent": ["hash","keygen","keyimport"],
					"memoryLimiting": {"slots":4,"bytes":896},
					"jobLimiting": {"parallel":3}				
				}
			}
		}
	},
	"operationalRights": 
	{
		"uid=1": 
		{
			"Software":
			{
				"nonKeyspaceDependent": ["hash","keygen","keyimport"],
				"memoryLimiting": {"bytes":8178},
				"jobLimiting": {"parallel":3}				
			},
			"PKCS11_HW":
			{
				"nonKeyspaceDependent": ["hash"],
				"memoryLimiting": {"slots":4,"bytes":896},
				"jobLimiting": {"parallel":1}	
			}
		},
		"vmid=3|uid=1": 
		{
			"profileId":"1"
		},
		"otherid=someipd": 
		{
			"PKCS11_HW":
			{
				"nonKeyspaceDependent": ["hash"],
				"memoryLimiting": {"slots":4},
				"jobLimiting": {"parallel":1}	
			}
		}
	},
	"keyspaces":
	{
		"0":
		{
			"keyspaceName": "tls_auth",
			"keys": 
			{
				"1":
				{	
					"name": "tls_auth_priv",
					"read": {},
					"use":
					{
						"otherid=special_handling_1|uid=1": {},
						"vmid=4|uid=2": {"operations": ["sign"]}
					},
					"write":
					{
						"uid=1|policy=someipd_t": {}
					}
				},
				"2":
				{ 
					"name": "tls_auth_pub",
					"read": 
					{
						"uid=-1":{}
					},
					"use": 
					{
						"uid=1": {},
						"vmid=4|uid=2": {}
					},
					"write": 
					{
						"uid=1|policy=someipd_t":{}
					}
				}
			}
		}
	},
	"certspace":
	{
		"0":
		{
			"certspaceName":"oemcerts",
			"defaultReadDeny":false,
			"defaultWriteDeny":true,
			"defaultUseDeny":false,
			"certspaceRights": 
			{
				"uid=1": {"operations":["add"]}, 
				"vmid=4|uid=2": {"operations":["add","remove"]}
			},
			"certs":
			{
				"1": 
				{
					"name":"signing_root",
					"removeable":false,
					"write":
					{
						"uid=1":{}
					}						
				},
				"2":
				{
					"name":"signing_authority_1",
					"write":
					{
						"uid=1":{}
					}
				}
			}
		}
	}
}
}

Justification for the Decision#

open