Preuves Segur

Comment configurer la DevBox-sante MSS pour apporter les preuves SEGUR

Génération de preuves

Pour générer une preuve, il faut :

  1. configurer la DevBox-Sante MSS sur mailiz de formation via le fichier application.yml :

    devbox-sante:
      ms-sante:
        mailiz:
          servicesUrl: https://mss-msg-igcsante.formation.mssante.fr/mss-msg-services/services
          authenticationServiceUrl: https://mss-idp-igcsante.formation.mssante.fr/openam/SSOSoap/metaAlias/asip/idp
        igcsante:
          gammes: ELEMENTAIRE_ORGANISATIONS, ELEMENTAIRE_ORGANISATIONS_TEST
    
  2. configurer les logs de l’IGCSanteTrustoreManager en debug via le fichier application.yml

logging:
  level:
    fr.devboxsante.igsante: DEBUG # à minima
    fr.devboxsante: DEBUG # pour plus de traces
  1. activer les logs de debug SSL de la JVM : javax.net.debug=ssl:handshake

  2. lancer la DevBox-Sante MSS avec cette configuration. Exemple de ligne de commande depuis l’installation de la devbox-sante :

    cd "C:\Program Files\DevBoxSante"
    "jre\bin\java.exe" -Djavax.net.debug=ssl:handshake -Dspring.config.location=application.yml -jar "repository\devboxsante.jar"
    
  3. Une fois lancée, accéder à un endpoint /mssante pour générer les traces nécessaires comparable à celles-ci : all.log

    curl -X GET "http://localhost:9999/mssante/authentification/cps" -H "accept: */*"
    

Ces traces fournissent les preuves de la prise en compte des exigences [MSS1] (Référentiel socle MSSanté #2 -Clients de Messageries Sécurisées de Santé)

Remarque : Les preuves demandées nécessitent l’appel de l’url https://mss-msg-igcsante.formation.mssante.fr/mss-msg-services/services/Annuaire/soap/v1/listEmails qui correspond au endpoint /mssante/emails de la DevBox-santé.

Néanmoins pour que la DevBox-santé MSS se comporte normalement, il faut au préalable appeler un des endpoints d’authentification, c’est à dire /mssante/authentification/otp ou /mssante/authentification/cps

MSS 1 : trust IGCSante seulement

Un client de messagerie MSSanté doit établir une connexion TLS avec un Opérateur MSSanté, quels que soient les transactions et protocoles utilisés entre les 2 parties.

MSS 1.1 Étapes

  1. Vérifier que la configuration TLS du logiciel accepte les certificats serveurs IGC Santé de la branche de TEST

  2. Monter une connexion TLS depuis le logiciel via une requete HTTP GET sur l’URL https://mss-msg-igcsante.formation.mssante.fr/mss-msg-services/services/Annuaire/soap/v1/listEmails.

1.1.1 Preuve

Extrait de configuration TLS du client de messagerie.

La DevBox-sante a développé un IGCSanteTrustoreManager spécifique afin de prendre en compte les différentes IGC-Santé définies sur http://igc-sante.esante.gouv.fr/PC/ . Tous les composants DevBox-Sante comme la MSS peuvent être configurés de manière à accepter les certificats d’une ou plusieurs gammes. Comme par exemple, pour l’environnement de formation de Mailiz :

devbox-sante:
  ms-sante:
    igcsante:
      gammes: ELEMENTAIRE_ORGANISATIONS, ELEMENTAIRE_ORGANISATIONS_TEST

Le choix de cette gamme en configuration permet le téléchargement à la volée des certificat à ajouter au trust store lors de son lancement :

for (IGCSanteGammeCertificat gammeCertificat : gammeCertificats) {
    log.info("Ajout du certificat {} au trustStore", gammeCertificat.getCertificatUrl());
    final X509Certificate certificat = _loadCertificate(gammeCertificat);
    _checkExpirationDate(certificat);
    trustStore.setCertificateEntry(gammeCertificat.getAlias(), certificat);
}

private X509Certificate _loadCertificate(IGCSanteGammeCertificat gammeCertificat) {
        URLConnection urlConnection = HttpHelper.noCheckCertificateOpenConnection(url);
        X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance(X_509).generateCertificate(urlConnection.getInputStream());
        if (certificate == null) {
            certificate = (X509Certificate) CertificateFactory.getInstance(X_509).generateCertificate(this.getClass().getClassLoader().getResourceAsStream(gammeCertificat.getCertificateFilename()));
        }
    }
    return certificate;
}

1.1.2 Preuve

Logs de la connexion TLS

Dans les logs (all.log) on peut s’intéresser à l’initialisation de l’IGCSanteTrustStoreManager :

2022-10-12 12:00:29.519 INFO igcsante.IGCSanteTrustoreManager : Initialisation du truststore
2022-10-12 12:00:29.520 INFO igcsante.IGCSanteTrustoreManager : Ajout du certificat http://igc-sante.esante.gouv.fr/AC/ACI-EL-ORG.cer au trustStore
2022-10-12 12:00:30.357 INFO igcsante.IGCSanteTrustoreManager : Ajout du certificat http://igc-sante.esante.gouv.fr/AC%20TEST/ACI-EL-ORG-TEST.cer au trustStore
trustStore

MSS 2 : TLSv1.2 uniquement

Conformément au référentiel socle MSSanté #2 (Clients de Messageries Sécurisées de Santé): Le client de messageries MSSanté du système doit supporter uniquement la version TLS 1.2 pour établir la connexion TLS avec l’Opérateur MSSanté, lors de la négociation TLS. (cf. RFC 2246 - http://tools.ietf.org/html/rfc2246). Dans le cas contraire, la connexion ne doit pas être établie.

MSS 2.1 Scenario

  1. Vérifier que la configuration TLS du logiciel accepte les certificats serveurs IGC Santé de la branche de TEST

  2. Monter une connexion TLS depuis le logiciel via une requete HTTP GET sur l’URL https://mss-msg-igcsante.formation.mssante.fr/mss-msg-services/services/Annuaire/soap/v1/listEmails.

MSS 2.1.1 Preuve

Extrait de configuration TLS du client de messagerie.

Réponse :

Nous utilisons une JVM en version 11 minimale. Lors de l’initialisation d’un contexte SSL via la JVM nous spécifions de manière statique le protocole TLSv1.2.

SSLContext sslContext = SSLContext.getInstance("TLSv1.2");

MSS 2.1.2 Preuve

Logs de connexion TLS

Dans les logs (all.log) on peut s’intéresser à juste après l’envoi de la requête :

2022-10-12 11:43:32.117  INFO 20756 --- [           main] o.a.c.services.AnnuaireService.REQ_OUT   : REQ_OUT
    Address: https://mss-msg-igcsante.formation.mssante.fr/mss-msg-services/services/Annuaire/soap/v1/listEmails
    HttpMethod: POST
   ...

le Handshake Message du client demande une TLSv1.2:

javax.net.ssl|DEBUG|01|main|2022-10-12 11:43:32.279 CEST|ClientHello.java:653|Produced ClientHello handshake message (
"ClientHello": {
  "client version"      : "TLSv1.2",
  ...
}
)

et la réponse du serveur valide le protocole :

javax.net.ssl|DEBUG|01|main|2022-10-12 11:43:32.337 CEST|ServerHello.java:872|Consuming ServerHello handshake message (
"ServerHello": {
  "server version"      : "TLSv1.2",
  ...
}
)

MSS 3 : choix des cyphers

Conformément au référentiel socle MSSanté #2 (Clients de Messageries Sécurisées de Santé) [MSS1] : Le client de messageries MSSanté du système doit nécessairement utiliser l’une des suites de chiffrement suivantes, lors de la négociation TLS :

  • 0xC030: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
  • 0xC02F: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  • 0xC028: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
  • 0xC027: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA25

Dans le cas contraire, la connexion ne doit pas être établie.

MSS 3.1 Étapes

  1. Vérifier que la configuration TLS du logiciel accepte les certificats serveurs IGC Santé de la branche de TEST

  2. Monter une connexion TLS depuis le logiciel via une requete HTTP GET sur l’URL https://mss-msg-igcsante.formation.mssante.fr/mss-msg-services/services/Annuaire/soap/v1/listEmails.

MSS 3.1.1

Afin de forcer le choix des cyphers nous avons introduit une nouvelle SSLSocketFactory java réduisant le choix des cipher suites par défaute de la JVM :

public abstract class IGCSanteSSLSocketFactory extends SSLSocketFactory {

    public static final String VERSION = "TLSv1.2";

    protected abstract SSLSocketFactory getSocketFactory();

    @Override
    public String[] getDefaultCipherSuites() {
        return new String[]{
                "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
                "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
                "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
                "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"};
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return getDefaultCipherSuites();
    }

MSS 3.1.2

Dans les logs (all.log) on peut s’intéresser à juste après l’envoi de la requête :

2022-10-12 11:43:32.117  INFO 20756 --- [           main] o.a.c.services.AnnuaireService.REQ_OUT   : REQ_OUT
    Address: https://mss-msg-igcsante.formation.mssante.fr/mss-msg-services/services/Annuaire/soap/v1/listEmails
    HttpMethod: POST
   ...

le Handshake Message du client demande les cyphers suivants :

javax.net.ssl|DEBUG|01|main|2022-10-12 12:00:38.363 CEST|ClientHello.java:653|Produced ClientHello handshake message (
"ClientHello": {
  "client version"      : "TLSv1.2",
  ...
  "cipher suites"       : "[TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(0xC02C), TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(0xC02B), TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030), TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(0xC02F), TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(0x009F), TLS_DHE_DSS_WITH_AES_256_GCM_SHA384(0x00A3), TLS_DHE_RSA_WITH_AES_128_GCM_SHA256(0x009E), TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(0x00A2), TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384(0xC024), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384(0xC028), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256(0xC023), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256(0xC027), TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(0x006B), TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(0x006A), TLS_DHE_RSA_WITH_AES_128_CBC_SHA256(0x0067), TLS_DHE_DSS_WITH_AES_128_CBC_SHA256(0x0040), TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384(0xC02E), TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384(0xC032), TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256(0xC02D), TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256(0xC031), TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384(0xC026), TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384(0xC02A), TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256(0xC025), TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256(0xC029), TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA(0xC00A), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(0xC014), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA(0xC009), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(0xC013), TLS_DHE_RSA_WITH_AES_256_CBC_SHA(0x0039), TLS_DHE_DSS_WITH_AES_256_CBC_SHA(0x0038), TLS_DHE_RSA_WITH_AES_128_CBC_SHA(0x0033), TLS_DHE_DSS_WITH_AES_128_CBC_SHA(0x0032), TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA(0xC005), TLS_ECDH_RSA_WITH_AES_256_CBC_SHA(0xC00F), TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA(0xC004), TLS_ECDH_RSA_WITH_AES_128_CBC_SHA(0xC00E), TLS_RSA_WITH_AES_256_GCM_SHA384(0x009D), TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C), TLS_RSA_WITH_AES_256_CBC_SHA256(0x003D), TLS_RSA_WITH_AES_128_CBC_SHA256(0x003C), TLS_RSA_WITH_AES_256_CBC_SHA(0x0035), TLS_RSA_WITH_AES_128_CBC_SHA(0x002F), TLS_EMPTY_RENEGOTIATION_INFO_SCSV(0x00FF)]",
  ...
}
)

Le serveur choisit :

javax.net.ssl|DEBUG|01|main|2022-10-12 12:00:38.415 CEST|ServerHello.java:872|Consuming ServerHello handshake message (
"ServerHello": {
  "server version"      : "TLSv1.2",
  ...
  "cipher suite"        : "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030)",
}
)

MSS 4 : certificat IGC Santé

Les clients de messageries MSSanté du système doivent être en capacité d’établir une connexion TLS avec un Opérateur MSSanté présentant un certificat serveur de l’IGC Santé,conformément au référentiel socle MSSanté #2 (Clients de Messageries Sécurisées de Santé) [MSS1].

MSS 4.1 Étapes

  1. Vérifier que la configuration TLS du logiciel accepte les certificats serveurs IGC Santé de la branche de TEST

  2. Monter une connexion TLS depuis le logiciel via une requete HTTP GET sur l’URL https://mss-msg-igcsante.formation.mssante.fr/mss-msg-services/services/Annuaire/soap/v1/listEmails.

MSS 4.1.1

Extrait de configuration des AC supportées par le client de messagerie.

idem 1.1.1

MSS 5 : certificat Opérateur non expiré

Le client de messageries MSSanté du système DOIT vérifier que le certificat présenté par l’opérateur MSSanté n’est pas expiré, conformément au référentiel socle MSSanté #2 (Clients de Messageries Sécurisées de Santé) [MSS1].

MSS 5.1 Étapes

  1. Vérifier que la configuration TLS du logiciel accepte les certificats serveurs IGC Santé de la branche de TEST

  2. Monter une connexion TLS depuis le logiciel via une requete HTTP GET sur l’URL https://mss-msg-igcsante.formation.mssante.fr/mss-msg-services/services/Annuaire/soap/v1/listEmails.

MSS 5.1.1

Extrait de configuration qui permet de montrer que le client a bien configuré pour respecter cette exigence.

Pas de configuration ici, les traces parlent d’elles mêmes.

A l’initialisation, l’IGCSanteTrustoreManager vérifie que les certificats de confiance utilisés ne sont pas expirés.

private Optional<CertStore> _loadCRL(String url) {
    URLConnection urlConnection = HttpHelper.noCheckCertificateOpenConnection(url);
    InputStream is = urlConnection.getInputStream();
    var crls = certificateFactory.generateCRLs(is);
    var certStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(crls));
    certStoreMap.put(url, certStore);
    is.close();
    return Optional.of(certStore);
}
2022-10-12 12:00:29.519  INFO - igcsante.IGCSanteTrustoreManager : Initialisation du truststore
2022-10-12 12:00:29.520  INFO - igcsante.IGCSanteTrustoreManager : Ajout du certificat http://igc-sante.esante.gouv.fr/AC/ACI-EL-ORG.cer au trustStore
2022-10-12 12:00:30.357 DEBUG - igcsante.IGCSanteTrustoreManager : Date expiration du certificat (CN=AC IGC-SANTE ELEMENTAIRE ORGANISATIONS, OU=IGC-SANTE, OU=0002 187512751, O=ASIP-SANTE, C=FR) est : Fri Jun 24 02:00:00 CEST 2033
2022-10-12 12:00:30.357  INFO - igcsante.IGCSanteTrustoreManager : Ajout du certificat http://igc-sante.esante.gouv.fr/AC%20TEST/ACI-EL-ORG-TEST.cer au trustStore
2022-10-12 12:00:30.756 DEBUG - igcsante.IGCSanteTrustoreManager : Date expiration du certificat (CN=TEST AC IGC-SANTE ELEMENTAIRE ORGANISATIONS, OU=IGC-SANTE TEST, OU=0002 187512751, O=ASIP-SANTE, C=FR) est : Fri Jun 24 02:00:00 CEST 2033

Puis plus tard lors de la vérification du certificat présenté par le serveur :

javax.net.ssl|DEBUG|01|main|2022-10-12 12:00:40.074 CEST|CertificateMessage.java:366|Consuming server Certificate handshake message (
"Certificates": [
  "certificate" : {
    "version"            : "v3",
    "serial number"      : "1D 5D E2 5E 3D C1 4B DE 21 0F 2C 0F 23 0E 86 52",
    "signature algorithm": "SHA256withRSA",
    "issuer"             : "CN=TEST AC IGC-SANTE ELEMENTAIRE ORGANISATIONS, OU=IGC-SANTE TEST, OU=0002 187512751, O=ASIP-SANTE, C=FR",
    "not before"         : "2022-06-02 13:49:28.000 CEST",
    "not  after"         : "2024-06-02 13:49:28.000 CEST",
    ...
]
)
2022-10-12 12:00:40.075 DEBUG 7092 --- [           main] f.d.igcsante.IGCSanteTrustoreManager     : Date expiration du certificat (CN=mss-msg-igcsante.formation.mssante.fr, OU=300000000099622, O=GIP - TEST9962, ST=Paris (75), C=FR) est : Sun Jun 02 13:49:28 CEST 2024
2022-10-12 12:00:40.075 DEBUG 7092 --- [           main] f.d.igcsante.IGCSanteTrustoreManager     : Date expiration du certificat (CN=TEST AC IGC-SANTE ELEMENTAIRE ORGANISATIONS, OU=IGC-SANTE TEST, OU=0002 187512751, O=ASIP-SANTE, C=FR) est : Fri Jun 24 02:00:00 CEST 2033

On voit que l’IGCSanteTrustoreManager vérifie la date d’expiration de la chaîne de certificats utilisée.

MSS 5.1.2

Si besoin, extrait du code qui vérifie la non expiration du certificat

Lors de l’initialisation d’une connexion et une fois le certificat validé par le truststore la date d’expiration du certificat présenté par l’opérateur MSS est vérifiée :

log.debug("Date expiration du certificat ({}) est : {}", certificat.getSubjectDN().toString(), certificat.getNotAfter());

if (Instant.now().isAfter(certificat.getNotAfter().toInstant())) {
    throw new IGCSanteException(String.format("Le certificat (%s) est expiré. La date d'expiration est : " ,
            certificat.getSubjectDN().toString(),
            certificat.getNotAfter())
    );
}

MSS 6 : non révocation du certificat

Le client de messageries MSSanté du système doit vérifier que le certificat présenté par l’Opérateur MSSanté n’est pas révoqué au moyen des CRL ou d’un répondeur OCSP, et ce quelle que soit l’autorité de certification utilisée par un Opérateur MSSanté, conformément au référentiel socle MSSanté #2 (Clients de Messageries Sécurisées de Santé) [MSS1].

MSS 6.1 : Étapes

  1. Vérifier que la configuration TLS du logiciel accepte les certificats serveurs IGC Santé de la branche de TEST

  2. Monter une connexion TLS depuis le logiciel via une requête HTTP GET sur l’URL https://mss-msg-igcsante.formation.mssante.fr/mss-msg-services/services/Annuaire/soap/v1/listEmails.

MSS 6.1.1

Extrait de configuration qui permet de montrer que le client a bien configuré pour respecter cette exigence.

Lors du lancement de la JVM (version 11 minimal) du connecteur MSS un truststore est généré avec un sous ensemble de la gamme de certificats de l’AC définit à l’url suivante : http://igc-sante.esante.gouv.fr/PC/

Nous prenons en compte les CRL disponibles pour chaque certificat donné à cette même URL.

Les logs montrent cette prise en charge :

2022-10-12 12:00:30.758 - igcsante.IGCSanteTrustoreManager : Ajout de la CRL http://igc-sante.esante.gouv.fr/CRL/ACI-EL-ORG.crl au trustStore
2022-10-12 12:00:31.848 - igcsante.IGCSanteTrustoreManager : Ajout de la CRL http://igc-sante.esante.gouv.fr/CRL/ACI-EL-ORG-TEST.crl au trustStore

MSC 6.1.2

Si besoin, extrait du code qui vérifie la non révocation du certificat

L’IGCSanteTrustoreManager est codé pour vérifier les CRLs disponibles sur http://igc-sante.esante.gouv.fr/PC/, dont voici l’extrait de code (implémentation basé sur https://stackoverflow.com/questions/45460015/crl-check-in-java):

 public TrustManager[] getTrustManagers() {

        return new X509TrustManager[]{
            new X509TrustManager() {
             ...
                @Override
                public void checkServerTrusted(X509Certificate[] x509Certificates, String string) throws CertificateException {
                        getWrapped().checkServerTrusted(x509Certificates, string);
                }
...
                private X509TrustManager getWrapped() {
                    if (trustManagerFactory.getTrustManagers() == null || trustManagerFactory.getTrustManagers().length == 0) {
                        init(gammeCertificats);
                    }
                    return (X509TrustManager) trustManagerFactory.getTrustManagers()[0];
                }
            }
        };
    }


public final void init(List<IGCSanteGammeCertificat> gammeCertificats) {
    this.gammeCertificats = gammeCertificats;
    
        trustManagerFactory = TrustManagerFactory.getInstance(PKIX);
        ...
        _initCRLs(gammeCertificats);
        ...
}


private void _initCRLs(List<IGCSanteGammeCertificat> gammeCertificats) throws KeyStoreException, InvalidAlgorithmParameterException {
  PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(trustStore, new X509CertSelector());
  for (IGCSanteGammeCertificat gammeCertificat : gammeCertificats) {
      String crlUrl = gammeCertificat.getCrlUrl();
      log.info("Ajout de la CRL {} au trustStore", crlUrl);
      pkixParams.addCertStore(_loadCRL(crlUrl));
  }
  pkixParams.setRevocationEnabled(true);
  ManagerFactoryParameters trustParams = new CertPathTrustManagerParameters(pkixParams);
  ...
  trustManagerFactory.init(trustParams);
}

private Optional<CertStore> _loadCRL(String url) {
    log.info("Chargement de la CRL {} dans un certStore", url);
    try {
        URLConnection urlConnection = HttpHelper.openConnection(url);
        InputStream is = urlConnection.getInputStream();
        var crls = certificateFactory.generateCRLs(is);
        var certStore = CertStore.getInstance( 
                "Collection",
                new CollectionCertStoreParameters(crls));
        certStoreMap.put(url, certStore);
        is.close();
        return Optional.of(certStore);

    } catch (IOException | CRLException | InvalidAlgorithmParameterException | NoSuchAlgorithmException e) {
    // gestion d'erreur
    }
}