# Zertifikate per GDS verwalten

> Anleitung: Anwendungszertifikat und vertrauenswürdige Zertifikate des Servers per GDS aus der Ferne verwalten: Voraussetzungen, Methoden und Einschränkungen.

Beteiligte Typen: `OpcServer`, `OpcServerSecurityRoles`, `OpcCertificateAcl`, `OpcCertificateChangedEventArgs`

Ein Global Discovery Server (GDS) kann das Anwendungszertifikat und die Liste der vertrauenswürdigen Zertifikate (engl. trust list) eines Servers aus der Ferne verwalten. Dieses Verfahren heißt GDS Push Management und ist in OPC UA Teil 12 festgelegt. Dazu stellt der Server die Methoden des Objekts ServerConfiguration und die Trust Lists seiner Zertifikatsgruppen bereit.

## Voraussetzungen

Die Methoden sind nur aufrufbar, wenn alle folgenden Bedingungen erfüllt sind. Andernfalls lehnt der Server den Aufruf mit dem Status `BadUserAccessDenied` ab:

- Mindestens ein Zugriffskontrolleintrag ist der Rolle `SecurityAdmin` zugeordnet. Ohne einen solchen Eintrag ist die Verwaltung abgeschaltet.
- Die Sitzung des GDS verwendet einen Endpunkt mit dem Modus `SignAndEncrypt`. Bieten Sie deshalb mindestens einen solchen Endpunkt an.
- Die Sitzung ist nicht anonym und ihre Identität gehört der Rolle `SecurityAdmin` an.

Verwenden Sie für die Identität mit der Rolle `SecurityAdmin` vorzugsweise ein Zertifikat statt eines Passworts und ordnen Sie die Rolle nur dieser einen Identität zu:

```csharp
var adminCertificate = OpcCertificateManager.LoadCertificate(adminCertificatePath);
 
var admin = server.Security.CertificateAcl.AddEntry(adminCertificate);
admin.Assign(server.Security.Roles.SecurityAdmin);
server.Security.CertificateAcl.IsEnabled = true;
 
server.CertificateChanged += HandleCertificateChanged;
...
private static void HandleCertificateChanged(
        object sender,
        OpcCertificateChangedEventArgs e)
{
    Console.WriteLine(
            "New certificate: {0} ({1})",
            e.Certificate.Subject,
            e.Certificate.Thumbprint);
}
```

```vbnet
Dim adminCertificate = OpcCertificateManager.LoadCertificate(adminCertificatePath)

Dim admin = server.Security.CertificateAcl.AddEntry(adminCertificate)
admin.Assign(server.Security.Roles.SecurityAdmin)
server.Security.CertificateAcl.IsEnabled = True

AddHandler server.CertificateChanged, AddressOf HandleCertificateChanged
...
Private Shared Sub HandleCertificateChanged( _
        ByVal sender As Object, _
        ByVal e As OpcCertificateChangedEventArgs)
    Console.WriteLine( _
            "New certificate: {0} ({1})", _
            e.Certificate.Subject, _
            e.Certificate.Thumbprint)
End Sub

```

Mit einer Benutzername-Passwort-Identität sieht die Freischaltung so aus:

```csharp
var admin = server.Security.UserNameAcl.AddEntry("admin", password: "password");
admin.Assign(server.Security.Roles.SecurityAdmin);
 
server.Security.UserNameAcl.IsEnabled = true;
server.CertificateChanged += HandleCertificateChanged;
...
private static void HandleCertificateChanged(
        object sender,
        OpcCertificateChangedEventArgs e)
{
    Console.WriteLine("New application certificate: {0}", e.Certificate.Thumbprint);
}
```

```vbnet
Dim admin = server.Security.UserNameAcl.AddEntry("admin", password:="password")
admin.Assign(server.Security.Roles.SecurityAdmin)

server.Security.UserNameAcl.IsEnabled = True
AddHandler server.CertificateChanged, AddressOf HandleCertificateChanged
...
Private Shared Sub HandleCertificateChanged( _
        ByVal sender As Object, _
        ByVal e As OpcCertificateChangedEventArgs)
    Console.WriteLine("New application certificate: {0}", e.Certificate.Thumbprint)
End Sub

```

## Ablauf

| Methode | Wirkung |
|---|---|
| `UpdateCertificate` | Übergibt ein neues Anwendungszertifikat, optional mit privatem Schlüssel und Ausstellerzertifikaten. Der Server prüft es und merkt es vor; aktiv wird es erst mit `ApplyChanges`. |
| `CreateSigningRequest` | Erzeugt eine Zertifikatsanforderung (engl. certificate signing request) für den vorhandenen Schlüssel des Servers, die der GDS von seiner Zertifizierungsstelle signieren lässt. Den Antragsteller (engl. subject) übernimmt der Server vom GDS; ohne Angabe verwendet er den des aktuellen Zertifikats. Fehlt darin die Organisation (O), ergänzt der Server sie aus `OpcServerInfo.CompanyName`. Die Anforderung enthält außerdem die Anwendungs-URI und die Domainnamen des aktuellen Zertifikats. |
| `ApplyChanges` | Übernimmt das vorgemerkte Zertifikat in den `ApplicationStore`, legt die Ausstellerzertifikate im `TrustedIssuerStore` ab, trennt danach alle Sitzungen und verwendet ab dann das neue Zertifikat mit dem zugehörigen privaten Schlüssel. Anschließend löst der Server das Ereignis `CertificateChanged` aus. |
| `GetRejectedList` | Liefert die Zertifikate aus dem `RejectedStore`, also die Zertifikate, die der Server abgelehnt hat. |
| Methoden der Trust List (`Open`, `Read`, `Write`, `CloseAndUpdate`, `AddCertificate`, `RemoveCertificate`) | Lesen und ändern die vertrauenswürdigen Zertifikate und Aussteller der Zertifikatsgruppe; der Server schreibt die Änderungen in den `TrustedPeerStore` beziehungsweise `TrustedIssuerStore`. |

Wenn eine Zertifikatsgruppe nur einen Zertifikatstyp hat, nimmt der Server `CreateSigningRequest` und `UpdateCertificate` auch ohne Angabe des Zertifikatstyps an.

## Einschränkungen

- Einen neuen privaten Schlüssel nimmt `UpdateCertificate` nur in den Formaten PEM und PFX an. Diese beiden Formate nennt der Server dem GDS auch als unterstützte Formate.
- Der Common Name (CN) im Antragsteller des neuen Zertifikats muss mit dem des bisherigen übereinstimmen, Groß- und Kleinschreibung zählt dabei nicht. Andere Teile des Antragstellers dürfen abweichen, zum Beispiel eine Organisation, die die Zertifizierungsstelle ergänzt hat. Wenn der Common Name abweicht, lehnt der Server das Zertifikat mit dem Status `BadSecurityChecksFailed` ab.
- Zu einem selbstsignierten Zertifikat dürfen keine Ausstellerzertifikate übergeben werden. Alle anderen Zertifikate prüft der Server gegen die übergebenen Aussteller.
- `CreateSigningRequest` erzeugt die Anforderung immer für den vorhandenen Schlüssel. Einen neuen Schlüssel erzeugt der Server dabei nicht: Die Argumente `regeneratePrivateKey` und `nonce` wertet er nicht aus. Einen übergebenen Antragsteller, der kein gültiger Distinguished Name ist, lehnt er mit dem Status `BadInvalidArgument` ab.

## Auswirkungen im Betrieb

`ApplyChanges` trennt alle bestehenden Sitzungen. Clients verbinden sich danach neu und müssen dem neuen Zertifikat vertrauen, zum Beispiel weil sie der ausstellenden Zertifizierungsstelle vertrauen. Planen Sie den Zertifikatswechsel deshalb wie ein Wartungsfenster.
