Provides data for the VerifyCertificate event.
TLS Secure DICOM communications between an SCP and an SCU has a handshake process where the SCP and SCU verify each others provided certificates.
The VerifyCertificate event is called once for each certificate in a certificate chain, and provides information about the verification process.
This is useful for determining why a TLS DICOM Secure communication failed to be established.
The VerifyCertificateEventArgs.CertificateString provides information about a certificate, including:
For example, if an SCU is providing a certificate that is created without SSL Server and SSL Client purposes, the VerifyCertificateEventArgs.ErrorException property will have a value of DicomSecurityCertificateExceptionCode.InvalidPurpose, and show the problem in the Certificate Purposes section of the VerifyCertificateEventArgs.CertificateString.
An example VerifyCertificateEventArgs.CertificateString corresponding to a DicomSecurityCertificateExceptionCode value of InvalidPurpose error is shown below:
Subject Name: CN = Test Client, C = US, ST = Nebraska, L = Omaha, O = Test Client OrganizationIssuer Name: CN = LEAD CA, L = Charlotte, ST = North Carolina, C = US, emailAddress = [email protected], O = "LEAD Technologies, Inc."Valid From: Jun 1 21:31:35 2020 GMTValid To: May 30 21:31:35 2030 GMTSerial Number: ae:8a:75:37:56:03:c4:45Basic Constraints:Not a CA (Certificate Authority)Certificate purposes:SSL client : NoSSL client CA : NoSSL server : NoSSL server CA : NoNetscape SSL server : NoNetscape SSL server CA : NoS/MIME signing : NoS/MIME signing CA : NoS/MIME encryption : NoS/MIME encryption CA : NoCRL signing : NoCRL signing CA : NoAny Purpose : YesAny Purpose CA : YesOCSP helper : YesOCSP helper CA : NoTime Stamp signing : No
The VerifyCertificateEventArgs.ErrorException property is a DicomSecurityCertificateException exception that indicates success or an error.
The VerifyCertificateEventArgs.Ok property determines the verification behavior.
Set VerifyCertificateEventArgs.Ok to 0 to stop the verification process with a "verification failed" state. If the DicomConnection(string,dicomnetsecuritymode,dicomopensslcontextcreationsettings) constructor is used and DicomOpenSslVerificationFlags.Peer is passed via the DicomOpenSslContextCreationSettings argument, a verification failure alert is sent to the SCU and the TLS/SSL handshake is terminated.
Set VerifyCertificateEventArgs.Ok to 1 to continue the verification process. If VerifyCertificateEventArgs.Ok is always set to 1, the TLS/SSL handshake will not be terminated with respect to verification failures and the connection will be established.
Leave VerifyCertificateEventArgs.Ok unchanged to get the default verification behavior.
using Leadtools;using Leadtools.Dicom.Scu;using Leadtools.Dicom.Scu.Common;using Leadtools.Dicom;using Leadtools.Dicom.Common.DataTypes;using Leadtools.Dicom.Common.DataTypes.Status;public void MoveSeriesSecure(){DicomEngine.Startup();DicomNet.Startup();QueryRetrieveScu retrieveSeriesSecure = new QueryRetrieveScu();FindQuery query = new FindQuery();DicomScp scp = new DicomScp();//// Change these parameters to reflect the calling AETitle.//retrieveSeriesSecure.AETitle = "T20_CLIENT64";retrieveSeriesSecure.HostPort = 1030;retrieveSeriesSecure.HostAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork);retrieveSeriesSecure.UseSecureHost = true; // SCU host is secureretrieveSeriesSecure.SecureHostSettings = new DicomOpenSslContextCreationSettings(DicomSslMethodType.SslV23, @"C:\Certificates\ca.pem", DicomOpenSslVerificationFlags.None, 9, DicomOpenSslOptionsFlags.AllBugWorkarounds);//// Change these parameters to reflect the called AETitle (server).//scp.AETitle = "L20_PACS_SCP64";scp.Port = 534;scp.Timeout = 60;scp.PeerAddress = IPAddress.Parse("192.168.5.102");scp.Secure = false; // SCP is unsecureretrieveSeriesSecure.BeforeCMove += new BeforeCMoveDelegate(retrieveSeriesSecure_BeforeCMove);retrieveSeriesSecure.Moved += new MovedDelegate(retrieveSeriesSecure_Moved);retrieveSeriesSecure.AfterCMove += new AfterCMoveDelegate(retrieveSeriesSecure_AfterCMove);retrieveSeriesSecure.HostReady += RetrieveSeriesSecure_HostReady;retrieveSeriesSecure.AfterSecureLinkReady += RetrieveSeriesSecure_AfterSecureLinkReady;retrieveSeriesSecure.Move(scp, string.Empty, "1.2.840.114257.3.6.5.41964868", "1.2.840.114257.3.6.5.5.4214471");retrieveSeriesSecure.VerifyCertificate += RetrieveSeriesSecure_VerifyCertificate;DicomNet.Shutdown();DicomEngine.Shutdown();}private void RetrieveSeriesSecure_VerifyCertificate(object sender, VerifyCertificateEventArgs e){if (e != null){Console.WriteLine("VerifyCertificate\n", e.CertificateString);if (e.ErrorException.Code != DicomSecurityCertificateExceptionCode.Success){Console.WriteLine(e.ErrorException.Message);}}}private void RetrieveSeriesSecure_AfterSecureLinkReady(object sender, AfterSecureLinkReadyEventArgs e){DicomNet net = (DicomNet)sender;if (net != null){if (e.Error != DicomExceptionCode.Success){ClientSecureLinkReadyException exception = new ClientSecureLinkReadyException("Secure handshake (TLS) failed.", e.Error);Console.WriteLine("Secure handshake (TLS) failed: code{0}", exception.Code);throw exception;}}}private void RetrieveSeriesSecure_HostReady(object sender, HostReadyEventArgs e){DicomConnection host = e.ScpHost;if (host != null){Console.WriteLine("HostReady: Host AETitle:{0} Host Port:{1}", e.ScpHost.AETitle, e.ScpHost.HostPort);if (host.SecurityMode == DicomNetSecurityMode.Tls){host.PrivateKeyPassword += Host_PrivateKeyPassword;host.SetTlsClientCertificate(@"C:\Certificates\client.pem", DicomTlsCertificateType.Pem, @"C:\Certificates\client.pem");host.PrivateKeyPassword -= Host_PrivateKeyPassword;host.SetTlsCipherSuiteByIndex(0, 0);host.SetTlsCipherSuiteByIndex(0, DicomTlsCipherSuiteType.DheRsaWithDesCbcSha);host.SetTlsCipherSuiteByIndex(1, DicomTlsCipherSuiteType.DheRsaWith3DesEdeCbcSha);host.SetTlsCipherSuiteByIndex(2, DicomTlsCipherSuiteType.DheRsaAes256Sha);host.SetTlsCipherSuiteByIndex(3, DicomTlsCipherSuiteType.RsaWithAes128CbcSha);host.SetTlsCipherSuiteByIndex(4, DicomTlsCipherSuiteType.RsaWith3DesEdeCbcSha);host.SetTlsCipherSuiteByIndex(5, DicomTlsCipherSuiteType.DheRsaWithAes128GcmSha256);host.SetTlsCipherSuiteByIndex(6, DicomTlsCipherSuiteType.EcdheRsaWithAes128GcmSha256);host.SetTlsCipherSuiteByIndex(7, DicomTlsCipherSuiteType.DheRsaWithAes256GcmSha384);host.SetTlsCipherSuiteByIndex(8, DicomTlsCipherSuiteType.EcdheRsaWithAes256GcmSha384);}}}private void Host_PrivateKeyPassword(object sender, PrivateKeyPasswordEventArgs e){e.PrivateKeyPassword = "test";}void retrieveSeriesSecure_BeforeCMove(object sender, BeforeCMoveEventArgs e){Console.WriteLine("Before CMove");}void retrieveSeriesSecure_Moved(object sender, MovedEventArgs e){Console.WriteLine(e.Patient.Name.Full);Console.WriteLine(e.Study.AccessionNumber);Console.WriteLine(e.Series.Number);Console.WriteLine(e.Instance.SOPInstanceUID);Console.WriteLine("==========================================");}void retrieveSeriesSecure_AfterCMove(object sender, AfterCMoveEventArgs e){Console.WriteLine("After CMove");Console.WriteLine("\t{0} Completed", e.Completed);Console.WriteLine("\t{0} Failed", e.Failed);Console.WriteLine("\t{0} Warning", e.Warning);Console.WriteLine("\tStatus: {0}", e.Status);if (e.Status != DicomCommandStatusType.Success){string statusAllString = e.StatusAll.ToString(StatusFormatFlags.IgnoreStatus, "\n", "\t");Console.WriteLine(statusAllString);}}