Invio dati ad un Web Service REST con utilizzo di un certificato P12 con codifica ECDH o ECDSA e token JWT

' Il seguente codice invia dati ad un Web Service REST con utilizzo di un certificato P12 con codifica ECDH o ECDSA.
' Da notare che questo tipo di codifica è la più recente e più sicura e che il codice può essere adattato anche per codifica RSA.
' Questo codice funziona con QualiWare 2023.02.14 o successivo.

' L'esempio da cui è tratto questo codice si trova qui: https://demoapi.rentri.gov.it/docs?page=esempi#certificato-di-dominio

Dim certificatePath As String = "<percorso del file del certificato in formato P12 o PFX>"
Dim tempPath As String = form.GetSession().GetLocalTempFileName(".p12")
System.IO.File.Copy(certificatePath, tempPath)

Dim password As String = "<password del certificato>"
Try
       
    dim certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(tempPath, password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable)
    Dim p12 as String=Convert.ToBase64String(certificate.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12, password), Base64FormattingOptions.InsertLineBreaks)   

    ' Generazione del JWT
    Dim jsonData1 As String = "[{""riferimenti"":{""numero_registrazione"":{""anno"":2024,""progressivo"":1},""data_ora_registrazione"":""2024-05-09T09:16:54.729Z"",""causale_operazione"":""aT""},""rifiuto"":{""codice_eer"":""150101"",""stato_fisico"":""SP"",""quantita"":{""valore"":5000.1234,""unita_misura"":""kg""}}}]"  ' Dati da spedire
    
    Dim content as New System.Net.Http.StringContent(jsonData1, System.Text.Encoding.UTF8, "application/json")

    Dim cert1 as New System.Security.Cryptography.X509Certificates.X509Certificate2(Convert.FromBase64String(p12), password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.MachineKeySet Or System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.EphemeralKeySet)
    Dim algo = Microsoft.IdentityModel.Tokens.SecurityAlgorithms.EcdsaSha256

    Dim issuer = "01687751204"
    Dim regId = "RCEZ3LS9SJ0"
    Dim aud = "rentrigov.demo.api"
    Dim baseApi = "https://demoapi.rentri.gov.it"
    Dim api = $"{baseApi}/dati-registri/v1.0/operatore/{regId}/movimenti"
    Dim jti = Guid.NewGuid().ToString()

    Dim tokenHandler = New Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler()
    Dim tokenDescriptor = New Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor With {
    .AdditionalHeaderClaims = New System.Collections.Generic.Dictionary(Of String, Object) From {
        {"x5c", New String() {Convert.ToBase64String(cert1.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Cert))}}
        },
        .Audience = aud,
        .Issuer = issuer,
        .Claims = New System.Collections.Generic.Dictionary(Of String, Object) From {
            {"jti", jti}
        },
        .SigningCredentials = New Microsoft.IdentityModel.Tokens.SigningCredentials(New Microsoft.IdentityModel.Tokens.ECDsaSecurityKey(System.Security.Cryptography.X509Certificates.ECDsaCertificateExtensions.GetECDsaPrivateKey(cert1)), "ES256")
    }
    Dim idAuth = tokenHandler.CreateToken(tokenDescriptor)

    dim sha256 As System.Security.Cryptography.SHA256 = System.Security.Cryptography.SHA256.Create()
    dim digest = $"SHA-256={Convert.ToBase64String(sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(jsonData1)))}"

    ' Aggiunge le intestazioni firmate ai claim
    tokenDescriptor.Claims.Add("signed_headers", New System.Collections.Generic.Dictionary(Of String, String)() {
        New System.Collections.Generic.Dictionary(Of String, String)() From {{"digest", digest}}, 
        New System.Collections.Generic.Dictionary(Of String, String)() From {{"content-type", content.Headers.ContentType.ToString()}}
    })

    dim integrity = tokenHandler.CreateToken(tokenDescriptor)

    ' Configura la richiesta HTTP
    Dim request As System.Net.HttpWebRequest = CType(System.Net.WebRequest.Create(api), System.Net.HttpWebRequest)
    request.Method = "POST"
    request.ContentType=content.Headers.ContentType.ToString()
    request.Headers.Add("Authorization", "Bearer " & idAuth)
    request.Headers.Add("Agid-JWT-Signature", integrity)
    request.Headers.Add("Digest", digest)

    Using requestStream As System.IO.Stream = request.GetRequestStream()
        Using writer As New System.IO.StreamWriter(requestStream)
            writer.Write(jsonData1)
        End Using
    End Using

    ' Ottieni la risposta
    try
        Using response As System.Net.HttpWebResponse = CType(request.GetResponse(), System.Net.HttpWebResponse)
            If response.StatusCode = 200 Then
                Using streamReader As New System.IO.StreamReader(response.GetResponseStream())
                    Dim responseText As String = streamReader.ReadToEnd()
                    form.Alert("Risposta ricevuta: " & responseText)
                End Using
            Else
                form.Alert("Status: " & LTrim(Str(response.StatusCode)) & " " & response.StatusDescription)
            End If
        End Using
    Catch e as Exception
        form.alert(e.message)
    End Try
Catch ex As Exception
    form.Alert("Errore: " & ex.Message & vbCrLf & ex.StackTrace)
End Try