i've a local imap server (dovecot) i run php -v PHP 7.4.8 (cli) (built: Jul 9 2020 08:57:23) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Zend OPcache v7.4.8, Copyright (c), by Zend Technologies php -m | grep imap imap TL;DR i'm setting up to use ssl certificate verification. with `openssl s_client` verification works; with php `imap_open` verification fails. what's wrong/missing in my php config? connecting via php 'imap_open' to the imap server, on exec of the following test script imap_connect_test.php <?php $config = array(); $host = 'mx.example.com'; $port = '993'; $spec = '/debug/imap/ssl/norsh/novalidate-cert'; $mailbox = "{{$host}:{$port}{$spec}}INBOX"; $username = 'me@xxxxxxxxxxxx'; $password = 'changeme'; $options = 0; $params = array( 'ssl' => array( 'verify_peer' => true, 'verify_peer_name' => false, 'peer_name' => 'internal.mx.example.com', 'verify_depth' => 9, 'allow_self_signed' => true, 'SNI_enabled' => true, 'ciphers' => 'TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-CHACHA20-POLY1305', 'local_cert' => '/srv/ssl/mail.client.EC.crt', 'local_pk' => '/srv/ssl/mail.client.EC.key', 'cafile' => '/srv/ssl/myCA.CHAIN.crt' ), ); $imap = imap_open($mailbox, $username, $password, $options, 0, $params); $folders = imap_listmailbox($imap, "{mx.example.com:993}", "*"); if ($folders == false) { echo "Call failed<br />\n"; } else { foreach ($folders as $val) { echo $val . "<br />\n"; } } function printArray($array, $prefix) { if (is_array($array)) { foreach ($array as $entry) { print "$prefix: $entry\n"; } } else { print "$prefix: None\n"; } } printArray(imap_errors(), "ERR"); printArray(imap_alerts(), "Alert"); if ($imap !== FALSE) { imap_close($imap); } ?> returns, as expected, php imap_connect_test.php -e {mx.example.com:993}Drafts<br /> {mx.example.com:993}Trash<br /> {mx.example.com:993}Junk<br /> {mx.example.com:993}Sent<br /> {mx.example.com:993}INBOX<br /> ERR: None Alert: None and in imap logs ==> /var/log/dovecot/dovecot-debug.log <== 2020-08-14 11:13:25 auth: Debug: auth client connected (pid=11483) ==> /var/log/dovecot/dovecot-info.log <== 2020-08-14 11:13:25 imap-login: Info: Disconnected (no auth attempts in 0 secs): user=<>, rip=127.0.0.1, lip=127.0.0.1, TLS handshaking: SSL_accept() failed: error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca: SSL alert number 48 ==> /var/log/dovecot/dovecot-debug.log <== 2020-08-14 11:14:14 auth: Debug: auth client connected (pid=11499) 2020-08-14 11:14:14 auth: Debug: client in: AUTH 1 PLAIN service=imap secured=tls session=9X5tY9qshuR/AAAB lip=127.0.0.1 rip=127.0.0.1 lport=993 rport=58502 ssl_cipher=TLS_AES_256_GCM_SHA384 ssl_cipher_bits=256 ssl_pfs=KxANY ssl_protocol=TLSv1.3 2020-08-14 11:14:14 auth: Debug: client passdb out: CONT 1 2020-08-14 11:14:14 auth: Debug: client in: CONT 1 AGJsYWtlcnNAY3hvbG9naWMuY29tAHRlc3RwYXNzdGVzdHBhc3M= (previous base64 data may contain sensitive data) 2020-08-14 11:14:14 auth: Debug: passwd-file(me@xxxxxxxxxxxx,127.0.0.1,<9X5tY9qshuR/AAAB>): Performing passdb lookup 2020-08-14 11:14:14 auth: Debug: passwd-file(me@xxxxxxxxxxxx,127.0.0.1,<9X5tY9qshuR/AAAB>): lookup: user=me@xxxxxxxxxxxx file=/etc/dovecot/sec/users.conf 2020-08-14 11:14:14 auth: Debug: passwd-file(me@xxxxxxxxxxxx,127.0.0.1,<9X5tY9qshuR/AAAB>): Finished passdb lookup 2020-08-14 11:14:14 auth: Debug: auth(me@xxxxxxxxxxxx,127.0.0.1,<9X5tY9qshuR/AAAB>): Auth request finished 2020-08-14 11:14:14 auth: Debug: client passdb out: OK 1 user=me@xxxxxxxxxxxx 2020-08-14 11:14:14 auth: Debug: master in: REQUEST 3214278657 11499 1 1d2580e127909e48d03637a8e369054d session_pid=11500 request_auth_token 2020-08-14 11:14:14 auth: Debug: static(me@xxxxxxxxxxxx,127.0.0.1,<9X5tY9qshuR/AAAB>): Performing userdb lookup 2020-08-14 11:14:14 auth: Debug: static(me@xxxxxxxxxxxx,127.0.0.1,<9X5tY9qshuR/AAAB>): Finished userdb lookup 2020-08-14 11:14:14 auth: Debug: master userdb out: USER 3214278657 me@xxxxxxxxxxxx uid=5000 gid=5000 home=/data/vmail/example2.com/me/Maildir auth_mech=PLAIN auth_token=898caadcaf538866cd07a36dda4a46c28556434c ==> /var/log/dovecot/dovecot-info.log <== 2020-08-14 11:14:14 imap-login: Info: Login: user=<me@xxxxxxxxxxxx>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=11500, TLS 2020-08-14 11:14:14 imap(me@xxxxxxxxxxxx)<9X5tY9qshuR/AAAB>: Info: Logged out in=58 out=1187 deleted=0 expunged=0 trashed=0 hdr_count=0 hdr_bytes=0 body_count=0 body_bytes=0 if I toggle certificate validation -> ON - $spec = '/debug/imap/ssl/norsh/novalidate-cert'; + $spec = '/debug/imap/ssl/norsh/validate-cert'; and re-exec, it fails php imap_connect_test.php -e PHP Warning: imap_open(): Couldn't open stream {mx.example.com:993/debug/imap/ssl/norsh/validate-cert}INBOX in /home/test/imap_connect_test.php on line 42 Warning: imap_open(): Couldn't open stream {mx.example.com:993/debug/imap/ssl/norsh/validate-cert}INBOX in /home/test/imap_connect_test.php on line 42 ERR: Certificate failure for mx.example.com: unable to get local issuer certificate: /C=US/ST=NY/L=NY/O=example.com/OU=example.com_CA/CN=internal.mx.example.com/emailAddress=ssl@xxxxxxxxxxx Alert: None and in imap logs 2020-08-14 11:19:02 imap-login: Info: Disconnected (disconnected before auth was ready, waited 0 secs): user=<>, rip=127.0.0.1, lip=127.0.0.1, TLS handshaking: SSL_accept() failed: error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca: SSL alert number 48 if I check certificate verification with `openssl s_client`, it WORKS openssl s_client \ -verify +9 \ -verify_return_error \ -verifyCAfile /srv/ssl/myCA.CHAIN.crt \ -verify_hostname internal.mx1-dev.example.com \ -crlf \ -4 \ -showcerts \ -bind 172.30.11.49 \ -connect mx1-dev.example.com:41993 \ -cert /srv/ssl/roundcube.example.com.client.EC.crt \ -key /srv/ssl/roundcube.example.com.client.EC.key \ -CAfile /srv/ssl/myCA.CHAIN.crt \ -cipher ECDHE \ -ciphersuites "TLS_CHACHA20_POLY1305_SHA256" \ -min_protocol TLSv1.2 ... verify depth is 9 CONNECTED(00000003) depth=2 O = example.com, OU = myCA, L = NY, ST = NY, C = US, emailAddress = ssl@xxxxxxxxxxx, CN = myCA_ROOT verify return:1 depth=1 C = US, ST = NY, O = example.com, OU = myCA, CN = myCA_INTERMEDIATE, emailAddress = ssl@xxxxxxxxxxx verify return:1 depth=0 C = US, ST = NY, L = NY, O = example.com, OU = myCA, CN = internal.mx1-dev.example.com, emailAddress = ssl@xxxxxxxxxxx verify return:1 --- Certificate chain 0 s:C = US, ST = NY, L = NY, O = example.com, OU = myCA, CN = internal.mx1-dev.example.com, emailAddress = ssl@xxxxxxxxxxx i:C = US, ST = NY, O = example.com, OU = myCA, CN = myCA_INTERMEDIATE, emailAddress = ssl@xxxxxxxxxxx -----BEGIN CERTIFICATE----- MII...YVe -----END CERTIFICATE----- --- Server certificate subject=C = US, ST = NY, L = NY, O = example.com, OU = myCA, CN = internal.mx1-dev.example.com, emailAddress = ssl@xxxxxxxxxxx issuer=C = US, ST = NY, O = example.com, OU = myCA, CN = myCA_INTERMEDIATE, emailAddress = ssl@xxxxxxxxxxx --- No client certificate CA names sent Peer signing digest: SHA384 Peer signature type: ECDSA Server Temp Key: X25519, 253 bits --- SSL handshake has read 1573 bytes and written 380 bytes Verification: OK Verified peername: internal.mx1-dev.example.com --- New, TLSv1.3, Cipher is TLS_CHACHA20_POLY1305_SHA256 Server public key is 384 bit Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated Early data was not sent Verify return code: 0 (ok) --- --- Post-Handshake New Session Ticket arrived: SSL-Session: Protocol : TLSv1.3 Cipher : TLS_CHACHA20_POLY1305_SHA256 Session-ID: 978233572BFFB63870CC2FE3E24DCEF6664B79EC723579252032B8CA34D7D953 Session-ID-ctx: Resumption PSK: 64903664B2D25A5D72DADECEFD08402C27C69B242AF2A044F1EFF41CAF0FCB57 PSK identity: None PSK identity hint: None SRP username: None TLS session ticket lifetime hint: 7200 (seconds) TLS session ticket: 0000 - 74 67 31 81 3a 28 12 40-06 50 52 54 55 cf d2 95 tg1.:(.@.PRTU... 0010 - fc b9 09 ec eb 22 79 87-1d 29 46 8a be 38 51 fd ....."y..)F..8Q. Start Time: 1597430604 Timeout : 7200 (sec) Verify return code: 0 (ok) Extended master secret: no Max Early Data: 0 --- read R BLOCK --- Post-Handshake New Session Ticket arrived: SSL-Session: Protocol : TLSv1.3 Cipher : TLS_CHACHA20_POLY1305_SHA256 Session-ID: 9E120BCCC0389D6E21749E66764B369E1507C3FE8D379F82F791DC367C5E80CE Session-ID-ctx: Resumption PSK: 44C0E08FDEF2E6037EB03FC67306340E0B8AA037FA571F59821473129EA374BB PSK identity: None PSK identity hint: None SRP username: None TLS session ticket lifetime hint: 7200 (seconds) TLS session ticket: 0000 - 62 10 d1 6c 0d 77 fa 40-5c d3 47 76 dc ce 6e 52 b..l.w.@\.Gv..nR 0010 - 90 1f 19 37 02 41 a9 2e-06 6b 28 42 c8 52 e1 d1 ...7.A...k(B.R.. Start Time: 1597430604 Timeout : 7200 (sec) Verify return code: 0 (ok) Extended master secret: no Max Early Data: 0 --- read R BLOCK * OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SPECIAL-USE LITERAL+ AUTH=PLAIN] Dovecot ready. >> a1 login "me@xxxxxxxxxxxx" "changeme" a1 OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY STATUS=SIZE SPECIAL-USE LITERAL+ NOTIFY SPECIAL-USE QUOTA ACL RIGHTS=texk] Logged in >> x select inbox * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) * OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft \*)] Flags permitted. * 2 EXISTS * 0 RECENT * OK [UIDVALIDITY 1595625368] UIDs valid * OK [UIDNEXT 3] Predicted next UID * OK [HIGHESTMODSEQ 5] Highest x OK [READ-WRITE] Select completed (0.001 + 0.000 secs). etc etc etc i've found many posts re: "couldn't open stream" in similar cases, and have only, so far, found 'resolution' by NOT validating certs; i.e., $spec += "/novalidate-cert" :-/ as `openssl s_client` connect & verifies, clearly, something in my php config/usage is wrong ... what/where ?