uso 0 Posted April 24, 2023 (edited) Hello Delphians, following scenario: A server w/o support for encryption needs to be "guarded" by a encrypting reverse proxy (server <=> proxy - no encryption; proxy <=> client - encrypted) Each valid client should authenticate against the proxy with a specific SSL certificate ("sslCliCertRequire") configured using IcsHosts. For testing purposes I generated a root CA cert and one "child" certificate signed by this CA. Now I set up proxy and client (for the sake of simplicity the client is "Firefox") to connect a demo SOAP service (client => proxy => SOAP-Service). Firefox is asking for a certificate to authenticate against the proxy but connection is always closed with "SSL_ERROR_HANDSHAKE_FAILED". openssl c_client -connect localhost:4711 gives the following: CONNECTED(000000FC) Can't use SSL_get_servername depth=0 CN = localhost, OU = Child OU, ST = Some State, O = "Some Company", C = DE, L = City, emailAddress = info@contoso.com verify error:num=20:unable to get local issuer certificate verify return:1 depth=0 CN = localhost, OU = Child OU, ST = Some State, O = "Some Company", C = DE, L = City, emailAddress = info@contoso.com verify error:num=21:unable to verify the first certificate verify return:1 depth=0 CN = localhost, OU = Child OU, ST = Some State, O = "Some Company", C = DE, L = City, emailAddress = info@contoso.com verify return:1 --- Certificate chain 0 s:CN = localhost, OU = Child OU, ST = Some State, O = "Some Company", C = DE, L = City, emailAddress = info@contoso.com i:CN = Personal Root CA, OU = Personal Root CA, ST = Some State, O = "Some Company", C = DE, L = City, emailAddress = info@contoso.com a:PKEY: id-ecPublicKey, 521 (bit); sigalg: ecdsa-with-SHA512 v:NotBefore: Apr 24 12:29:14 2023 GMT; NotAfter: Apr 25 12:29:14 2033 GMT -----BEGIN CERTIFICATE----- [...] -----END CERTIFICATE----- --- Server certificate subject=CN = localhost, OU = Child OU, ST = Some State, O = "Some Company", C = DE, L = City, emailAddress = info@contoso.com issuer=CN = Personal Root CA, OU = Personal Root CA, ST = Some State, O = "Some Company", C = DE, L = City, emailAddress = info@contoso.com --- No client certificate CA names sent Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:Ed25519:Ed448:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224 Shared Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:Ed25519:Ed448:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512 Peer signing digest: SHA512 Peer signature type: ECDSA Server Temp Key: X25519, 253 bits --- SSL handshake has read 1334 bytes and written 403 bytes Verification error: unable to verify the first certificate --- New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 Server public key is 521 bit This TLS version forbids renegotiation. Compression: NONE Expansion: NONE No ALPN negotiated Early data was not sent Verify return code: 21 (unable to verify the first certificate) --- read:errno=10054 What I'm doing wrong, what am I missing to get such a simple setup up and running?! Thanks! Edited April 24, 2023 by uso Share this post Link to post
Keesver 23 Posted April 25, 2023 Maybe this link helps: node.js - Error: unable to verify the first certificate in nodejs - Stack Overflow Share this post Link to post
Angus Robertson 577 Posted April 25, 2023 From your description, I'm not sure how anything is set-up here, or why you are using an OpenSSL tool for testing. The proxy server needs it's own SSL/TLS certificate matching the host name localhost which you seem to have created, but this will fail validation by clients unless those clients have the root certificate installed, Personal Root CA in your case. But this is unrelated to the client certificate which should be installed in the Firefox certificate store, and then validated by the proxy server. Your openssl c_client command line does not have a client certificate which is the reason for the errors. Angus Share this post Link to post
Fr0sT.Brutal 900 Posted April 27, 2023 Won't already implemented Apache/Nginx be better? Share this post Link to post
Angus Robertson 577 Posted April 27, 2023 The ICS web server supports client certificates, but this scenario seems to be using an old SOAP server that does not support SSL/TLS. Angus Share this post Link to post
uso 0 Posted June 2, 2023 (edited) On 4/27/2023 at 5:24 PM, Fr0sT.Brutal said: Won't already implemented Apache/Nginx be better? No. We are developing against customer specifications and a full-fledged web server is not on the "wishlist". On 4/27/2023 at 5:45 PM, Angus Robertson said: The ICS web server supports client certificates, but this scenario seems to be using an old SOAP server that does not support SSL/TLS. Angus The backend is using std. SOAP components from Delphi - yes. But one of the requirements is a state of the art encryption so we are stuck with the SOAP components and I tried to handle the encryption by a proxy in front of the main service. The proxy is working so far - encryption too. Last thing, I couldn't figure out, is how to get the proxy to deny client connections, if the client does not send the right certificate. At the moment the proxy processes every client request, even if the client sends a cert that is not signed by "my" CA. I set TIcsProxy.RootCA to my own root certificate and I cleared TIcsProxy.SourceServer.RootCAList - but no success. TIcsProxy Settings: MProxy := TIcsProxy.Create(nil); MProxy.Name := 'xxx'; MLogger := TIcsLogger.Create(MProxy); if Assigned(MProxy.FIcsLog) then begin FreeAndNil(MProxy.FIcsLog); end; MLogger.LogOptions := [ TLogOption.loDestEvent, TLogOption.loDestFile, TLogOption.loAddStamp, TLogOption.loWsockErr, TLogOption.loWsockInfo, TLogOption.loWsockDump, TLogOption.loSslErr, TLogOption.loSslInfo, TLogOption.loSslDevel, TLogOption.loSslDump, TLogOption.loProtSpecErr, TLogOption.loProtSpecInfo, TLogOption.loProtSpecDump, TLogOption.loProgress]; MLogger.LogFileName := GetLogfilePath(); {$IFDEF DEBUG} MLogger.OnIcsLogEvent := OnOnIcsLogEvent; {$ENDIF} MLogger.OpenLogFile; MLogger.DoDebugLog(MLogger, TLogOption.loProgress, Format(RSTR_LOGGER_CREATED_s, [MLogger.LogFileName])); MProxy.FIcsLog := MLogger; MProxy.onProxyProg := MLogger.DoDebugLog; MProxy.SourceServer.RootCAList.Clear; MProxy.RootCA := 'xxx'; LIcsHost := MProxy.IcsHosts.Add() as TIcsHost; LIcsHost.HostNames.Add('*'); LIcsHost.HostEnabled := True; LIcsHost.BindIpAddr := '0.0.0.0'; LIcsHost.BindSslPort := 8080; LIcsHost.BindNonPort := 0; LIcsHost.HostTag := '<Your host tag>'; LIcsHost.ForwardProxy := False; LIcsHost.WebLogDir := ''; LIcsHost.WebLogIdx := 0; LIcsHost.SslCert := {$DEFINE SSL_CERT}{$INCLUDE 'SslSettings.inc'}; LIcsHost.SslKey := {$DEFINE SSL_PRIV_KEY}{$INCLUDE 'SslSettings.inc'}; LIcsHost.SslInter := {$DEFINE SSL_INTER_CERT}{$INCLUDE 'SslSettings.inc'}; LIcsHost.SslPassword := {$DEFINE SSL_PASSWORD}{$INCLUDE 'SslSettings.inc'}; LIcsHost.SslSrvSecurity := sslSrvSecHigh; LIcsHost.WebRedirectStat := 0; LIcsHost.CliCertMethod := sslCliCertRequire; LIcsHost.CertSupplierProto := SuppProtoNone; LIcsHost.CertChallenge := ChallNone; LIcsHost.CertPKeyType := PrivKeyECsecp512; LIcsHost.CertSignDigest := Digest_sha3_512; LIcsHost.AuthForceSsl := True; LIcsHost.AuthSslCmd:= True; LIcsTarget := MProxy.ProxyTargets.Add() as TProxyTarget; LIcsTarget.TarHost := 'localhost'; LIcsTarget.TarPort := 8081; LIcsTarget.TarSsl := False; LIcsTarget.HostTag := '<Your host tag>'; LIcsTarget.HostEnabled := True; Edited June 2, 2023 by uso Share this post Link to post
Angus Robertson 577 Posted June 2, 2023 Sorry, a quick scan of the TIcsProxy code suggests that client certificate checking is not yet supported. It should be happening in TIcsProxy.ServerHandshakeDone which needs a new event onServerHandshakeDone which passes PeerCert to the application where you can check it and cause the client to be disconnected for an invalid certificate (see the web server). I'll try and do it next week. Angus Share this post Link to post
Angus Robertson 577 Posted June 5, 2023 This is working now, the proxy log says: Http > 443/443 (3) Source 17 - Client SSL Connected OK with TLSv1.3, cipher TLS_AES_128_GCM_SHA256, encryption AESGCM(128), message auth AEAD Client certificate received, should we trust client? CN: angus@magsys.co.uk, Issuer: Self Signed, Expires: 09/04/2030 and the event can be adjusted to either check a common name or an issuer name for corporate certificates. The hardest part was testing, I had to correct PemTool to properly create client certificates before Firefox would send one, I'll include a new test client certificate with the samples since this keeps coming up. Will be in SVN in a day or so. Angus Share this post Link to post
uso 0 Posted June 5, 2023 1 hour ago, Angus Robertson said: This is working now, the proxy log says: Http > 443/443 (3) Source 17 - Client SSL Connected OK with TLSv1.3, cipher TLS_AES_128_GCM_SHA256, encryption AESGCM(128), message auth AEAD Client certificate received, should we trust client? CN: angus@magsys.co.uk, Issuer: Self Signed, Expires: 09/04/2030 and the event can be adjusted to either check a common name or an issuer name for corporate certificates. The hardest part was testing, I had to correct PemTool to properly create client certificates before Firefox would send one, I'll include a new test client certificate with the samples since this keeps coming up. Will be in SVN in a day or so. Angus Hi Angus, thanks for your effort! We are going to test internally - too. PemTool: Same here - had to fiddle arround with it to get it to work. But ultimately I switched to XCA for creating my certs. Share this post Link to post
Angus Robertson 577 Posted June 5, 2023 PemTool used to work for client certificates, but I broke it when adding international domain support, where spaces and @ are illegal. Angus Share this post Link to post
Angus Robertson 577 Posted June 7, 2023 There was a large SVN update yesterday, including SSL client certificate support in the proxy server, and improved logging in the REST client, so you know if a client certificates was requested by the server. Available from SVN and the overnight zip. Angus Share this post Link to post