rlebeau on master
#346 Updating IdSSLOpenSSLHeade… (compare)
@klsyzzz OpenSSL certificate validation with Indy is a little bit tricky (or maybe its the OpenSSL part that makes it tricky^^), sslvrfPeer says "if the server sends a certificate, it wil be verified. If the verification fails, the handshake will be terminated immediately. The only time that a server would not send a certificate is when an anonymous cipher is in use" (which should never be used^^). sslvrfFailIfNoPeerCert and sslvrfClientOnce are only used for server. If no VerifyMode is set, OpenSSL (in client mode) will verify the server certificate, but failure will not terminate the handshake.
I even believe you have always to implement a OnVerifyPeer, otherwise Indy uses a default implementation which is
Result := True which overrides the verification result of OpenSSL.
If OpenSSL should verify the certificate, it needs to know which certificate are trustable. For this OpenSSL uses all public certs which are stored in the directory which you specified in SSLOptions.VerifyDir. If you want to use the windows certificate store, you could use this snippet, but you have to have a look into the msdn for
CertEnumCertificatesInStore and maybe is
CertEnumSystemStore interessting for you.
LCert := CertEnumCertificatesInStore(LStore, nil); while Assigned(LCert) do begin LX509 := d2i_X509(nil, @lCert.pbCertEncoded, LCert.cbCertEncoded); if Assigned(LX509) then begin X509_STORE_add_cert(ctx.cert_store, LX509); X509_free(LX509); end; LCert := CertEnumCertificatesInStore(LStore, LCert); end; // Calls of CertFreeCertificateContext are not needed, because // CertEnumCertificatesInStore frees the pPrevCertContext Argument
Another Point for certificate verification is the VerifyDepth: OpenSSL uses as default 9, but Indy overrides this with its own default, which is default(Integer) = 0. If the SMTP Server sends a certificate issued by a intermediate CA, OpenSSL terminate the connection with cert chain too long. VerifyDepth specifies the max length of a certificate chain.
@rlebeau I've changed the function to use a UID for the temp file name:
if(CreateGuid(Uid) = S_OK) then Result := Copy(stringreplace(GuidToString(Uid),'-','', [rfReplaceAll]), 2, 10) + LFQE; // Result := LFName + IntToHex(LNamePart, 8) + LFQE; if not FileExists(Result) then begin Break; end;
The first test of this change is hopefull, my application is again able to parse the messages with attachments.
Can you think of any problems I might run into using this change (Apart from compatibilty issues when I try to upgrade the Indy components)
:!DH:within the existing cipher list, I've just changed mine to:
'ALL:!ADH:!DH:RC4+RSA:+SSLv2:@STRENGTH'and now the latest OpenSSL 1.1.0e connects". You can use the
TIdSSLIOHandlerSocketOpenSSL.SSLOptions.CipherListproperty for that.
OnVerifyPeerevents, and set
[sslvrfPeer], but it is currently allowing connections when there is no client certificate. What have I done wrong / missed ?
sslvrPeer: A Request from a client certificate will be sent to the client. The client may opt to ignore the request, but if a certificate is sent back, it will be verified.
sslvrfFailIfNoPeerCert: only used for server when
sslvrPeeris set. Use of this flag will cause the handshake to terminate immendiatly if no certificate is provided by the client.
sslvrfClientOnce: only used for server when
sslvrPeeris set. Use of this flag will prevent the server from requesting a certificate from the client in the case of renegotiation. A certificate will still be requested during the initial handshake
VerifyMode := ;