Mit dem Begriff Betriebssystem verbindet die Mehrzahl der Leser wahrscheinlich zunächst die Megabyte großen Programme für DOS oder Unix Computer. Die wenigen Kilobyte Programmcode eines Betriebssystems für einen Chipkarten-Mikrocontroller muten da etwas winzig an, aber die Funktionalität ist dieselbe. Ein Betriebssystem ist die Grundlage eines digitalen Rechensystems und steuert und überwacht insbesondere die Abwicklung von Programmen. Es besteht allerdings ein grundlegender Unterschied. Betriebssysteme für Chipkarten enthalten keine Benutzeroberfläche oder Zugriffsmöglichkeiten auf externe Speichermedien, dafür spielt die Sicherheit bei der Ausführung von Programmen und der Zugriff auf Daten eine große Rolle. Die Hauptaufgaben eines Chipkartenbetriebssystems sind:
Datenübertragung von und zu den Chipkartenkontakten
Ablaufsteuerung der
Kommandos
Dateiverwaltung
Verwaltung und Ausführung von kryptographischen
Algorithmen
Für ein Chipkartenbetriebssystem hat sich entsprechend der englischen Bezeichnung 'Card Operating System' die Abkürzung COS eingebürgert, die auch häufig in den jeweiligen Produktnamen zu finden ist. Die zwei Hauptvertreter dieser Systeme sind STARCOS und ODS-COS. STARCOS ist eines der populärsten Chipkartenbetriebssysteme das in Zusammenarbeit mit der Gesellschaft für Mathematik und Datenverarbeitung, Darmstadt, und dem Unternehmen Giesecke und Devrient entwickelt wurde. Ein weiteres auf dem Markt befindliches Chipkartenbetriebssystem kommt von der Firma Oldenbourg Datensysteme (ODS). Beide Systeme richten sich nach der ISO-Norm 7816-4 und unterstützen alle dort definierten Befehle und Dateitypen.
Bei Betriebssystemen für große Systeme kommt es immer wieder vor, oder es ist sogar üblich, daß Systemprogrammierer durch eigene Hintertüren in das System gelangen. Bei Chipkartenbetriebssystemen muß dies ausgeschlossen sein. Es darf keine Möglichkeit geben, vorbei am Betriebssystem, Daten unautorisiert auszulesen.
Der Codeumfang eines Chipkartenbetriebssystems liegt im Bereich von drei und 16 Kilobyte, durchschnittlich werden acht Kilobyte benötigt. Es ist ausschließlich im ROM untergebracht. Nach der Herstellung des Chips können keine Änderungen mehr daran vorgenommen werden. Die Beseitigung eines Fehlers ist sehr teuer und beinhaltet eine Rückrufaktion und Beseitigung der alten Chips und Neuproduktion der korrigierten Chips. Neben der extremen Fehlerarmut müssen diese Betriebssysteme zuverlässig und robust sein. Sie dürfen durch keinen von außen kommenden Befehl in ihrer Funktion oder Sicherheit beeinträchtigt werden. Ein streng modularer Aufbau trägt entscheidend dazu bei, daß eventuelle Fehler schon in der Implementierungsphase entdeckt werden können.
Mit diesem modularen Ansatz erkauft man sich jedoch einen Mehraufwand beim Erstellen des Programmcodes und unter Umständen auch einen größeren Speicherplatzbedarf. Die Implementation erfolgt vollständig in Assembler, was die Fehleranfälligkeit erhöht, da dies keine höhere, sondern eher eine hardwareferne Programmiersprache ist. Die Sprache Assembler ist notwendig, um den Speicherplatz optimal auszunutzen. Allerdings können durch den Aufbau in einzelnen vollständig austestbaren Modulen Fehler rechtzeitig beseitigt werden. Das führt zu einem Schichtaufbau des Betriebssystems, wie in der nachfolgend dargestellten Abbildung.

Abbildung 20: Befehlsabarbeitung in einem Chipkartenbetriebssystem
Eine typische Befehlsabarbeitung läuft wie folgt ab:
Alle Befehle an den Mikrocontroller empfängt dieser über die serielle Ein-/Ausgabe-Schnittstelle. Fehlererkennungs- und Korrekturmechanismen führt der Ein-/Ausgabe-Manager unabhängig von den übrigen, darüberliegenden, hardwareferneren Schichten aus. Nachdem ein Befehl vollständig und korrekt empfangen wurde, muß der Sicherheitsnachrichten-Manager diesen gegebenenfalls entschlüsseln oder auf Richtigkeit prüfen. Nach dieser Bearbeitung versucht die darüberliegende Schicht, der Kommandointerpreter, herauszufinden, ob dieser Befehl bekannt und ausführbar ist. Wenn dies nicht möglich ist, folgt ein Aufruf des Rückmeldung-Managers, welcher eine entsprechende Rückmeldung generiert und via Ein-/Ausgabe-Manager an das Terminal zurücksendet.
Ist der Befehl jedoch ausführbar, tritt der Kanal-Manager in Kraft. Sind auf einer Chipkarte mehrere Anwendungen vorhanden, so kann jede über einen unterschiedlichen logischen Kanal angesprochen werden. Vorgesehen sind bis zu vier Kanäle, die parallel mit einem Terminal Daten austauschen können. Danach wird ein Zustandsautomat aufgerufen.
Ein Zustandsautomat modelliert einen Befehlsablauf mit verschiedenen Zuständen und Übergängen. In der Informatik werden unter Verwendung von Graphen Zustandsautomaten beschrieben. Ein Graph stellt eine Menge von Zuständen und Beziehungen dieser Zustände zueinander dar. Dabei werden Zustände als Knoten und Beziehungen der Knoten, nämlich Übergänge, als Kanten dargestellt. Die Übergänge sind meistens gerichtet, deshalb gibt der Pfeil an, in welche Richtung ein Zustandsübergang stattfinden soll.
Der Zustandsautomat prüft, ob der vorliegende Befehl mit den gesetzten Parametern im aktuellen Zustand überhaupt erlaubt ist. Ist das der Fall, wird der Anwendungsbefehl in den eigentlichen Programmcode, die interne Bitdarstellung des Befehls, umgewandelt und ausgeführt. Falls der Befehl im aktuellen Zustand verboten ist, oder die Parameter dazu nicht erlaubt sind, erhält das Terminal über Rückmeldung- und Ein-Ausgabe-Manager eine entsprechende Meldung.
Sollte es während der Befehlsabarbeitung notwendig sein, auf eine Datei zuzugreifen, dann geschieht dies nur über die Dateiverwaltung, die alle logischen Adressen in die interne physikalische Adreßdarstellung umwandelt. Desweiteren überwacht sie die Adressen auf ihre Bereichsgrenzen und prüft die Zugriffsbedingungen auf die jeweilige Datei. Die Dateiverwaltung benutzt einen Speicher-Manager , der die komplette Verwaltung des physikalisch adressierten EEPROMs übernimmt. Damit ist sichergestellt, daß nur in diesem Modul mit physikalischen Adressen gearbeitet wird und diese nicht nach außen transparent sind.
Der Rückmeldung-Manager ist ein zentrales Modul und übernimmt die Verwaltung und Erzeugung aller möglichen Rückmeldungen, ob Fehlermeldungen oder erfolgreiche Meldungen.
Der Lebenszyklus eines Chipkartenbetriebssystems ist in drei Teile gegliedert. Unmittelbar bei der Herstellung werden die ROM-Inhalte, also das Betriebssystem, als eine sogenannte Maske eingegeben. Das EEPROM ist vollkommen leer. Der Chip wird auf seine Funktionsfähigkeit getestet. Stellt sich heraus, daß ein Fehler vorliegt, so muß die gesamte produzierte Charge der Mikrocontroller vernichtet werden, da alle Chips diesen Fehler enthalten. Funktioniert der Chip einwandfrei, werden anschließend Schmelzbrücken physikalisch aufgetrennt, die die Testfunktionen auf Dauer blockieren. Ein Zugriff ist nicht mehr möglich, da die physikalische Verbindung fehlt.
Die Übergabe vom Hersteller zum Chipkartenherausgeber wird meistens durch einen Transportcode gesichert, der dann vom Herausgeber eingegeben werden muß, um den Mikrocontroller zu verändern. Die Chipkarten gelangen somit in die Phase der Personalisierung. Es wird der EEPROM-Inhalt programmiert. Dies kann ein Arbeitsprogramm sein, daß den ROM-Teil für seine eigentliche Anwendung anpaßt. Der ROM-Teil entspricht dann einer großen Bibilothek, die durch das EEPROM zu einer funktionsfähigen Anwendung ausgebaut wird. Für diesen Fall wurde das Programm OSCAR entwickelt. Es stellt Instruktionen zum Generieren und Verwalten von mehreren virtuellen Karten auf einem Mikrocontroller bereit und wurde von der Firma General Information Systems Ltd. in England entwickelt. Einige Betriebssysteme laufen auch nach der Personalisierung vollständig im ROM ab, nur die Daten sind im EEPROM untergebracht. Außerdem werden individuelle Daten, etwa persönliche Daten des künftigen Karteninhabers programmiert, was den Ausdruck Personalisierung erklärt. Was nach außen hin nicht lesbar sein soll, wird elektronisch gesichert.
In diesem Zustand werden die Chipkarten an die Anwender ausgegeben und kommen in den dritten und letzten Teil ihres Lebenszyklus. Die Anwender benutzen die Karten so lange, bis die Gültigkeit der Karte abläuft, die Kontakte nach 100.000 Steckzyklen ihre Benutzbarkeit verlieren oder das EEPROM nicht mehr beschreibbar ist. Dann werden die Karten weggeworfen. Der PVC-Anteil der Chipkarten könnte wiederverwendet werden, aber die laminierten Folien sind nur schwer davon zu trennen. Im Moment bleibt nur die Lösung, die Karten bei hohen Temperaturen zu verbrennen. Wenn der Einsatz der Chipkarten wirklich so ansteigt wie vorhergesagt, müßte ein Weg gefunden werden, Chipkarten wiederzuverwenden, da die Umweltbelastung durch die Abgase enorm wäre.
Die drei verschiedenen Speicherarten RAM, ROM und EEPROM haben verschiedene Eigenschaften und Funktionen. Der im ROM enthaltene Programmcode für das Betriebssystem muß in keiner bestimmten Struktur angeordnet sein. Die einzelnen Programmodule können in beliebiger Reihenfolge miteinander verbunden sein. Ein Ziel sollte es aber sein, Sprünge in der Software zu minimieren, um auf diese Weise Speicherplatz zu sparen.
Das folgende Bild zeigt eine übliche Aufteilung eines durchschnittlichen RAMs in die vom Prozessor genutzten Bereiche Register, Stack, allgemeine Variablen, Arbeitsbereich für kryptographische Algorithmen und Ein-/Ausgabe-Puffer.

Abbildung 21: Beispiel für die Aufteilung eines 256 Byte großen RAMs
Die Strukturierung des EEPROM ist komplizierter als die der beiden anderen Speicherarten. In einem modernen Betriebssystem sieht sie etwa so aus wie in Bild 24 dargestellt.

Abbildung 22: Beispiel für die Aufteilung des EEPROMs in modernen Betriebssystemen
Viele Mikrocontroller haben am Anfang des EEPROMs einen 32 Byte großen Bereich, der mit Fertigungsdaten dieser Chipkarte beschrieben wird. Oft sind diese Bereiche nur für einen WORM-Zugriff ausgelegt, d.h. sie können nur einmal beschrieben und anschließend nur noch ausgelesen werden. Der einmalige Schreibzugriff wird von der Software gesteuert, da es solch einen Hardware-Baustein nicht gibt.
Es folgt ein Bereich für die Zusätze zum Betriebssystem, die bei der Personalisierung geladen werden. Um das Betriebssystem immer in einem sicheren stabilen Zustand betreiben zu können, ist dieser Bereich durch eine Prüfsumme (EDC) geschützt, die vor jedem Zugriff nachgerechnet wird. Die Entdeckung eines Fehlers führt dazu, daß Teile des Betriebssystems nicht mehr benutzt werden.
Im nächsten Bereich können zusätzliche anwendungsspezifische Befehle oder Algorithmen stehen, die sich entweder nicht im ROM befinden sollen oder aus Speicherplatzmangel dort keinen Platz mehr gefunden haben. Unter Umständen ist auch dieser Bereich mit einer Prüfsumme gegen Veränderungen gesichert.
Der sich anschließende Dateibereich enthält den nach außen hin sichtbaren Dateibaum, der im folgenden Kapitel näher beschrieben wird. Die neueren Betriebssysteme sind üblicherweise objektorientiert aufgebaut. Das bedeutet, daß alle Informationen über eine Datei in dieser Datei gespeichert sind, und daß eine Datei vor einer Aktion immer erst selektiert werden muß. Dateien sind in zwei Teile aufgespalten: den sogenannten Kopf der Datei, der Informationen über Struktur, Name, Typ, Größe, Position im Dateisystem und Zugriffsbedingungen enthält und den mit einem Zeiger verbundenen Rumpf der Datei, in dem die Nutzdaten stehen.

Abbildung 23: Interner Aufbau einer Datei
Das EEPROM ist in immer gleichgroße Einheiten aufgeteilt, die sogenannten Seiten. Kopf und Rumpf einer Datei befinden sich immer auf getrennten Seiten. Da der Kopf normalerweise nie verändert wird, dort aber alle Zugriffsbedingungen gespeichert sind, kann durch einen Schreib- oder Löschfehler der Rumpf nicht beeinflußt werden. Dieser Aufbau hat neben der besseren Strukturierung der Daten auch noch den Vorteil der größeren physikalischen Sicherheit der Datenbestände.
Am Ende des EEPROMs befindet sich eventuell ein Freispeicherbereich, dessen Verwaltung ein eigener Manager durchführt. Dieser Bereich ist für eventuell neu anzulegende Dateien gedacht. Der Verwaltungsaufwand mit Listen für belegte und freie Speicherbereiche ist sehr hoch und benötigt viel Speicherplatz. Deshalb ist oftmals dieser Freispeicher auf einzelne Anwendungen im Dateibereich aufgeteilt, wobei keine aufwendige Freispeicherverwaltung vorhanden ist, weil die Aktionen Löschen und Erzeugen einer Datei sehr selten, wenn überhaupt, vorkommen. Wird eine Datei gelöscht, ist es nicht selbstverständlich, daß der freiwerdende Platz von einer neu zu erzeugenden Datei eingenommen werden kann.
Die ersten Chipkarten wiesen nur mehr oder minder direkt adressierbare Speicherbereiche auf, in die Daten geschrieben oder gelesen werden konnten. Der Zugriff erfolgte unter Angabe von physikalischen Speicheradressen. Mittlerweile verfügen alle Chipkarten über ein vollständiges und hierarchisch organisiertes Dateiverwaltungssystem mit symbolischer und hardwareunabhängiger Adressierung.
Der Aufbau von Chipkarten-Dateiverwaltungssystemen ist ähnlich dem von DOS oder Unix. Für den Bereich Chipkarten ist dieser in der ISO 7816-4 festgelegt.
Es existieren Verzeichnisse, die als eine Art Ordner für mehrere zusammengehörige Dateien fungieren.
Das Wurzelverzeichnis ist das oberste Verzeichnis im Dateiverwaltungssystem, das einem auf dem Kopf stehenden Baum mit Wurzel, Ästen und Blättern ähnelt. Dieses Hauptverzeichnis, das implizit nach einem Reset der Chipkarte selektiert ist, hat die englische Bezeichnung 'Master File', kurz MF. Unter dem Wurzelverzeichnis können bei Bedarf noch 'Dedacated Files' (DF), im folgenden als Unterverzeichnisse bezeichnet, stehen. Dieser Bedarf tritt auf, wenn eine Chipkarte mehrere Anwendungen in sich vereinen soll. Dann bekommt jede Anwendung ein eigenes Unterverzeichnis. Unter den Unterverzeichnissen können weitere Unterverzeichnisse in beliebiger Schachtelungstiefe existieren, allerdings führt der limitierte Speicherplatz dazu, daß selten mehr als eine Ebene von Unterverzeichnissen unter dem Wurzelverzeichnis aufgebaut ist.
Die Nutzdaten befinden sich in Anwendungsdateien, englisch 'Elementary Files' (EF). Diese befinden sich entweder direkt unter dem Wurzelverzeichnis oder unter einem Unterverzeichnis.

Abbildung 24: Beispiel einer Verzeichnisstruktur auf einer Chipkarte nach ISO 7816-4
Die objektorientierten Dateiverwaltungssysteme erfordern es, vor dem Zugriff auf eine Datei, diese zu selektieren. Dazu muß eine eindeutige Identifikation dieser Datei möglich sein. Es kann immer nur eine Datei zur gleichen Zeit selektiert sein. Alle Dateien erhalten einen individuellen Namen, auch File Identifier (FID) genannt. Dieser Name besteht nicht aus Buchstaben, sondern aus Zahlen, die im Hexadezimalsystem codiert sind. Jede Datei, einschließlich der Verzeichnisse, besitzt einen zwei Byte langen Namen. Das Wurzelverzeichnis zum Beispiel hat aus historischen Gründen die Bezeichnung '3F00'.
Unterverzeichnisse stellen im allgemeinen einzelne Anwendungen dar. Deshalb besitzen sie zusätzlich noch einen Anwendungsnamen. Er hat eine Länge von fünf bis 15 Bytes und besteht aus zwei Komponenten. Die erste Komponente enthält eine Identifikationskennung (RID) mit einer festen Länge von fünf Bytes. Sie wird entweder von einer nationalen oder internationalen Registrierungsstelle vergeben und beinhaltet einen Ländercode, eine Anwendungskategorie und eine Nummer für den Anwendungsanbieter. Diese Kennung führt zu einer individuellen RID, die weltweit zur Identifizierung einer bestimmten Anwendung benutzt werden kann.
Falls es notwendig ist, kann der Anwendungsanbieter der RID eine zweite optionale Kennung (PIX) nachstellen. Sie kann zwischen null und elf Bytes lang sein und enthält z.B. eine Serien- oder Versionsnummer.
Die Auswahl einer Datei kann durch zwei verschiedene Methoden stattfinden. Bei der expliziten Selektion muß der Pfad im Dateibaum angegeben werden, gefolgt vom Dateinamen der gewünschten Datei. Dabei kann entweder der direkte Weg von der aktuellen Datei zur gesuchten oder der indirekte vom Wurzelverzeichnis zur gewünschten Datei angegeben werden.
Die implizite Selektion funktioniert nur für Anwendungsdateien innerhalb eines Verzeichnisses. Hier reicht ein Teil des Dateinamens aus, um die Selektion eindeutig durchzuführen.
Die Speicherung oder Übertragung von Daten erfordert immer eine exakte Definition der verwendeten Daten und ihrer Struktur. Datenstrukturen mit fester Länge und nicht änderbarer Reihenfolge, die erweitert oder gekürzt werden sollen, verursachen über kurz oder lang immer erheblichen Aufwand. Sie können sogar Systeme zum 'Platzen' bringen, mit der Folge, daß das System neu programmiert werden muß.
Ein Lösungsansatz ist die ASN.1 (Abstract Syntax Notation One). Sie ist eine codierungsunabhängige, künstliche Sprache zur Beschreibung von Daten und ihren Strukturen. Genormt ist die Syntax in der ISO 8824, die Beschreibungsregeln befinden sich in der ISO 8825. In die 1993 publizierte ISO-Norm 7816-5 für Chipkarten wurde die ASN.1 zur Datenbeschreibung aufgenommen, da sie sich in der Anwendung (z.B. Krankenversichertenkarte) durchgesetzt hat.
Da der Speicherplatz auf einer Chipkarte im Regelfall zu klein ist, kann durch die Verwendung von Datenobjekten auf der Grundlage von ASN.1 erheblich Speicherplatz gespart werden. Daten können mit variabler Länge ohne große Komplikationen übertragen oder abgespeichert werden. Sind allerdings die Nutzdaten sehr gering, ist der Verwaltungsaufwand für die Struktur der Datenelemente groß, was der Hauptnachteil der ASN.1 ist.
Ein Datenobjekt wird grundsätzlich durch zwei vorangestellte Felder gekennzeichnet. Das erste Feld gibt an, worum es sich bei dem Datenobjekt handelt, es wird als 'tag' (englisch tag = Zettel) bezeichnet. Das zweite Feld gibt die Länge (englisch 'length') des nachfolgenden Datenobjektes in Byte an. Danach folgt das eigentliche Datenobjekt (englisch 'value'). Diese Architektur wird deshalb auch als Tag-Length-Value-Format oder kurz TLV-Format bezeichnet.

Abbildung 25: Aufbau eines ASN.1-Datenelementes
Darstellung des tag-Bytes:
Anhand der Bits b7 und b8 werden vier verschiedene Klassen von Datenobjekten unterschieden:
| Bit 8 | Bit 7 | Objektklasse | Beschreibung |
|---|---|---|---|
| 0 | 0 | universal | universelle, standardisierte Datenobjekte |
| 0 | 1 | application | anwendungsspezifische Datenobjekte |
| 1 | 0 | context-specific | nur im Rahmen des Kontextes gültige Datenobjekte |
| 1 | 1 | private | private, anwenderdefinierte Datenobjekte |
Das Bit b6 zeigt an, ob das Datenobjekt ein Einzelobjekt (b6 = 0) oder ein ganzer Datensatz (b6 = 1) ist, der in weitere Datenobjekte aufgeteilt werden kann.
Die Bits b5 bis b1 stellen eine freiwählbare Zahl zwischen 0 und 30 dar, die eine Identifizierung für ein Datenobjekt ist. Sollte es in einer Anwendung mehr als 31 verschiedene Datenobjekte geben, so werden die Bits b5 bis b1 alle auf Eins gesetzt, was anzeigt, daß ein zweiter tag folgt. Im zweiten und allen eventuell folgenden tag-Bytes zeigt das Bit b8 an, ob noch ein weiterer tag folgt.
In den Bits b7 bis b1 des zweiten Bytes können schon bis zu 128 verschiedene Datenobjekte dargestellt werden. Folgen zwei weitere Bytes können 214 = 16384 Datenobjekte unterschieden werden.
Codierung des Längenfeldes:
Ist die darzustellende Länge zwischen Null und 127 Bytes, so reichen die Bits b7 bis b1 aus, um diese Zahlen darzustellen. Das Bit b8 ist dann immer Null.
Bei Datenobjekten, die länger sind als 127 Bytes, muß auf die Langform des Längenfeldes zurückgegriffen werden. In diesem Fall wird Bit b8 auf Eins gesetzt und die Bits b7 bis b1 geben an, wieviele Längenfelder noch folgen. Diese noch folgenden Längenfelder stellen eine Zahl dar, welche die eigentliche Länge des Datenobjektes angibt. In der Chipkartentechnik wird bis auf drei Bytes erweitert. Hiermit lassen sich Längen bis einschließlich 65535 Bytes darstellen.
Beispiel:

Abbildung 26: Darstellung eines Namens mittels TLV in Hexadezimal-Codierung
Hexadezimalsystem:
In Hexadezimal-Darstellung basiert alles auf der Zahl 16, im Gegensatz zum üblichen Dezimalsystem zur Basis 10. Das bedeutet es gibt 16 verschiedene Zeichen, die unterschiedliche Wertigkeiten haben:
hexadezimal ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , A , B , C , D , E , F )
dezimal ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ,10, 11, 12, 13, 14, 15)
Zahlendarstellungen in hexadezimal werden in dieser Arbeit in Hochzeichen dargestellt ( 'Zahl' ).
Genau wie im Dezimalsystem nach der Zahl 9 eine neue Stelle zur 10 eingeführt wird, so wird im Hexadezimalsystem nach der 15='F' zur 16='1'||'0' übergegangen. Eine Umrechnung von Hexadezimaldarstellung in die Dezimaldarstellung funktioniert wie folgt:
'0F1A' = ?
Entsprechend der Position eines Zeichens in einer Hexadezimalzahl, wird die Wertigkeit des Zeichens gewichtet. Steht das Zeichen ganz rechts, so ist die Wertigkeit 160.
'0' * 163 + 'F' * 162 + '1' * 161 + 'A' * 160 = ?
Nun werden die Wertigkeiten der einzelnen Zeichen eingesetzt:
0 * 163 + 15 * 162 + 1 * 161 + 10 * 160 = ?
0 + 3840 + 16 + 10 = 3866
'0F1A' = 3866