Accreditamento SdiCoop_Ricezione, problemi con i certificati

Salve a tutti,
dopo aver fatto richiesta di accreditamento ho scaricato i certificati:

  • SDI-<P.IVA>-client.cer
  • SDI-<P.IVA>-server.cer
    (che ho capito essere binari da convertire in .pem con openssl)
    e il KitDiTest che si è presentato con:
  • UserTrustCA.cer
  • SectigoRSA.cer
  • caentrate.cer
  • servizi.fatturapa.it.cer
  • Sistema_Interscambio_Fattura_PA.cer
  • CAEntratetest.cer
  • SistemaInterscambioFatturaPATest.cer
  • testservizi.fatturapa.it.cer

Con tutti questi ho molta confusione sul da farsi, non sapendo quali vanno installati nel client che invierà richieste allo Sdi e quali nel server che riceverà la notifica di ricezione
Inoltre, quali costituiscono i certificati intermedi? E poi, perché alcuni pur essendo in base64 non hanno le marcature BEGIN/END CERTIFICATE?
Il readme.txt arrivato insieme ai certificati mi è stato poco utile a capire come usare ciascun certificato/dove installarlo/come installarlo; qualcuno ha un “how to for dummies”?

La soluzione che sto implementando è una consoleApp per l’invio della fattura e una WCF Service Application per la ricezione notifica, entrambe in .NET Framework 4.8

Piccola premessa sui formati dei file:

  • Ignora l’estensione del file. Devi guardare dentro al file.
  • Se il file è binario, è in formato DER. Puoi leggerlo con openssl usando -inform der.
  • Se il file è di testo, con il certificato in base64 e i marcatori BEGIN CERTIFICATE e END CERTIFICATE, è in formato pem e si legge con openssl senza specificare il formato.
  • Se il file è codificato in base64 ma non ha i marcatori, hai due opzioni: o lo trasformi in formato pem, aggiungiendo a mano i marcatori BEGIN CERTIFICATE e END CERTIFICATE, o lo trasformi in formato DER, decodificandolo da base64 in binario.

Il “how to for dummies” dipende da cosa usi per implementare il client e cosa usi come server (la parte che gestisce l’SSL, che potrebbe anche essere un reverse proxy).
Dato che usi .NET Framework, per il client ti servirà probabilmente un file pfx con con il certificato client, mentre per il server presumo usi IIS, con cui purtroppo non so aiutarti.

Quello che posso fare è dirti a cosa servono i vari certificati:

  • caentrate.cer o CAEntrate_prod.der : Certificato della CA di produzione dell’Agenzia delle Entrate. Usato per firmare la maggior parte degli altri certificati.
  • CAEntratetest.cer: Certificato della CA di test dell’Agenzia delle Entrate. Usato solo per firmare il certificato client di SdI per l’ambiente di test.
  • SDI-<PIVA>_client.cer: certificato client che devi usare quando ti colleghi con SdI. È firmato dalla CA di produzione dell’AdE. Usato sia in ambiente di test che in produzione.
  • SDI-<PIVA>_server.cer: certificato server che devi esporre sul tuo server al quale si collega il client di SdI (sui tuoi endpoint). Firmato dalla CA di produzione dell’AdE. Usato sia in ambiente di test che in produzione.
  • Sistema_Interscambio_Fattura_PA.cer: questo è il certificato client di SdI usato per autenticarsi quando si collega al tuo server (per consegnarti le fatture o le notifiche) in produzione. Firmato dalla CA di produzione dell’AdE. Spero che il certificato che includono ora nel kit sia quello giusto, perché quando hanno rinnovato i certificati a maggio 2024, ci avevano messo un certificato sbagliato (che non aveva il flag che dice che può essere usato per l’autenticazione client). Lo hanno cambiato dopo un paio d’ore, ma il kit conteneva ancora quello sbagliato.
  • SistemaInterscambioFatturaPATest.cer: questo è il certificato client di SdI usato in ambiente di test (quando si collega al tuo server, agli endpoint di test). Firmato dalla CA di test dell’AdE.
  • testservizi.fatturapa.it.cer: Questo è il certificato server esposto dal server SdI in ambiente di test. N.B. È firmato dalla CA di produzione dell’AdE.
  • servizi.fatturapa.it.cer: Questo è il certificato server esposto dal server SdI in ambiente di produzione. Questo, insieme alle due CA intermedie in SectigoRSA.cer e UserTrustCA.cer, li puoi tranquillamente ignorare perché la CA usata è di quelle riconosciute dal sistema, quindi la verifica avverrà in automatico senza dover installare questi certificati da nessuna parte.

Quindi i certificati vanno usati nel seguente modo:

  • In ambiente di test:
    • Sul tuo server, devi esporre la chain SDI-<PIVA>_server.cer + caentrate.cer
    • Sempre sul tuo server, devi autenticare il client di SdI usando la chain SistemaInterscambioFatturaPATest.cer + CAEntratetest.cer
    • Il tuo client deve autenticarsi usando la chain SDI-<PIVA>_client.cer + caentrate.cer.
    • Il tuo client deve usare la chain testservizi.fatturapa.it.cer + CAEntratetest.cer per verificare il server di test di AdE. Puoi installare la CA di test nel certificate store di Windows, oppure semplicemente disabilitare la verifica SSL in ambiente di test.
  • In ambiente di produzione:
    • Sul tuo server, devi esporre la chain SDI-<PIVA>_server.cer + caentrate.cer
    • Sempre sul tuo server, devi autenticare il client di SdI usando la chain Sistema_Interscambio_Fattura_PA.cer + caentrate.cer
    • Il tuo client deve autenticarsi usando la chain SDI-<PIVA>_client.cer + caentrate.cer.
    • La verifica del server SdI da parte del client avviene in automatico, dato che il sistema operativo contiene già la CA usata (“AAA Certificate Services” di Sectigo).

Come dicevo non conosco IIS quindi non so dirti come si configurano i vari certificati.
Posso però darti un paio di dritte per quanto riguarda il client, dato che per quello usiamo anche noi .NET Framework (ma non WCF).
Dovrai usare un binding di tipo basicHttpBinding, impostando messageEncoding="Mtom", security con mode="Transport" e transport con clientCredentialType="Certificate". Il certificato client lo puoi caricare nel certificate store di Windows, oppure lo puoi caricare da codice.

Grazie della risposta esaustiva, avevo già configurato il client come hai indicato:

BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
binding.MessageEncoding = WSMessageEncoding.Mtom;

SdIRiceviFileClient client = new SdIRiceviFileClient(binding, endpoint);
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Ho installato testservizi.fatturapa.it.cer e CAEntratetest.cer nel certificate store di windows e ho creato un .pfx con SDI--client.cer, la mia chiave e caentrate.cer che poi ho aggiunto al client

var ccert = new X509Certificate2(certPath);
client.ChannelFactory.Credentials.ClientCertificate.Certificate = ccert;

A questo punto richiamo client.RiceviFile passando una delle fatture di test (firmata cades) e mi viene ritornato un generico “Interal Error”

Non so se può essere questo il problema, ma il caricamento del certificato è un po’ incasinato.

Non ne sono sicuro, ma mi pare che se nel pfx metti la chiave privata devi per forza crittarla con una password che devi passare al costruttore di X509Certificate2. Ma su questo forse ti avrebbe dato errore subito.

Dai test fatti a suo tempo (almeno questo c’è scritto nei commenti del mio codice), bisogna anche passare il parametro keyStorageFlags che deve essere X509KeyStorageFlags.DefaultKeySet in ambiente di sviluppo (Visual Studio + IIS Express) e X509KeyStorageFlags.MachineKeySet in produzione (IIS).

Questa è la funzione che uso per caricare il certificato:

private X509Certificate2 LoadSDIClientCertificate(string certFilePath, string certPassword)
{
    // N.B. Il parametro keyStorageFlags al costruttore di X509Certificate2 specifica
    // dove andra' memorizzata la chiave privata. Per come funziona SSL/TLS in Windows
    // questa DEVE venir memorizzata, salvo venir poi eliminata (se non si specifica di memorizzarla permanentemente).
    // Specificando MachineKeySet viene memorizzata nel key store dell macchina,
    // mentre specificando UserKeySet viene memorizzata nel key store dell'utente.
    // Dai test effettuati, in produzione con IIS, bisogna usare MachineKeySet,
    // mentre nell'ambiente di sviluppo bisogna usare DefaultKeySet.

    // Da .NET 4.7 in poi, esiste anche il valore EphemeralKeySet, ma a quanto pare non e' supportato in Windows!

    // N.B.2: Eventuali problemi di memorizzazione della chiave non si verificano qui, nel momento
    // in cui il certificato viene letto dal file, ma la prima volta che viene usato per stabilire
    // una connessione SSL/TLS.

    X509KeyStorageFlags keyStorageFlags = X509KeyStorageFlags.MachineKeySet;
    string sdiClientCertificateStorage = ConfigurationManager.AppSettings["SDIClientCertificateStorage"];
    if (sdiClientCertificateStorage != null && sdiClientCertificateStorage.ToLower() == "defaultkeyset") {
        keyStorageFlags = X509KeyStorageFlags.DefaultKeySet;
    }
    return new X509Certificate2(certFilePath, certPassword, keyStorageFlags);
}

Purtroppo questo non ha risolto il problema, penso che l’autenticazione ora vada a buon fine poiché se uso un certificato sbagliato mi ritorna l’errore 403 invece che 500.
L’errore deve essere quindi nell’invio della richiesta o nella firma della fattura; questo è il codice che ho preso sempre da questo forum per inviare la richiesta:

byte[] febyte;
string str64;
RiceviFileRequest sdiRequest = new RiceviFileRequest();
rispostaSdIRiceviFile_Type sdiResponse = new rispostaSdIRiceviFile_Type();
string signedXmlPath = @"C:\Temp\IT01234567890_FPA01.xml.p7m";

febyte = File.ReadAllBytes(signedXmlPath);
sdiRequest.fileSdIAccoglienza = new fileSdIBase_Type();
sdiRequest.fileSdIAccoglienza.NomeFile = Path.GetFileName(signedXmlPath);
str64 = Convert.ToBase64String(febyte);

sdiRequest.fileSdIAccoglienza.File = Convert.FromBase64String(str64);

sdiResponse = client.RiceviFile(sdiRequest.fileSdIAccoglienza);

Ci sono indicazioni particolari sulla firma digitale? L’autore dev’essere lo stesso che fa la richiesta?

Il codice mi sembra a posto (a parte che converti inutilmente a/da base64).

Anche se fosse un problema con la firma digitale non dovrebbe darti un errore 500.
Però potresti provare a mandare una fattura non firmata. Per le fatture B2B e B2C (FPR12) la firma non è obbligatoria.

Non sono riuscito a risolvere l’Internal Error, nel frattempo sto pubblicando su IIS il service per controllare se dopo la richiesta client ricevo almeno la notifica di scarto.
Sono però passati 15 giorni dalla richiesta di accreditamento e non ho completato i test, mi è stato chiuso il servizio? Dovrei contattare sogei e richiedere una proroga?

se usi IIS… i Web Service che espongono i metodi di recezione fatture e Notifiche …devono contenere nella sezione “Configuration Editor” → “OneToOneMappings” il certificato Client o server non ricordo più …mi scuso… accompagnato da utente e password (Domain\Administrator)

Su IIS dovrei usare il .pfx creato da SDI-<PIVA>_server.cer + caentrate.cer come certificato SSL e invece la chain SistemaInterscambioFatturaPATest.cer + CAEntratetest.cer per il OneToOneMappings… è corretto? L’unico dubbio con questa impostazione è che quest’ultimo certificato di autenticazione dovrei specificarlo come stringa base64 ma essendo una concatenazione di due certificati non so se i tag BEGIN CERTIFICATE e END CERTIFICATE creano problemi…