Crypto/x509 certificate signed by unknown authority

Hi, I faced the following issue in regard of verifying certificates when connecting using SSL.

The following server ‘smtp.tim.it’ (well-known Italian smtp server) sending the following certificate data (attached ‘openssl’ result at the bottom of the page).

It appears, it has kinda broken certificate chain:

‘USERTrust RSA Certification Authority’ (well-known trusted CA) => verifies ‘TI Trust Technologies DV CA’
‘TI Trust Technologies OV CA’ => verifies ‘smtp.tim.it’

But no verification part for ‘TI Trust Technologies OV CA’ in this chain.

Running the following code fails with ‘certificate: x509: certificate signed by unknown authority’:

	tlsConfig := &tls.Config{
		InsecureSkipVerify: false, // If noCert is true, skip Go's verification entirely
		ServerName:   "smtp.tim.it",
	}

	tlsConn := tls.Client(socket.conn, tlsConfig)
	// Perform the TLS handshake
	err := tlsConn.Handshake()

But only on Linux and Android.
On MAC and iOS this code works and verifies the chain correctly. Did not check on Windows, but I suppose it would work as well, and after some debugging I found the differences come from this part:

verify.go:

// Use platform verifiers, where available, if Roots is from SystemCertPool.
	if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
		// Don't use the system verifier if the system pool was replaced with a non-system pool,
		// i.e. if SetFallbackRoots was called with x509usefallbackroots=1.
		systemPool := systemRootsPool()
		if opts.Roots == nil && (systemPool == nil || systemPool.systemPool) {
			return c.systemVerify(&opts)
		}
		if opts.Roots != nil && opts.Roots.systemPool {
			platformChains, err := c.systemVerify(&opts)
			// If the platform verifier succeeded, or there are no additional
			// roots, return the platform verifier result. Otherwise, continue
			// with the Go verifier.
			if err == nil || opts.Roots.len() == 0 {
				return platformChains, err
			}
		}
	}

My guess that this code causes the OS handle the verification chains. My question is, how can we handle it for rest of the platforms? (We have many users on Android who use this provider and have certificate verification forced, so is really important to us. Also it used to work on our previous Java implementation (not sure how, as it was developed long ago and code is deprecated)).

Thanks for any help provided, and sorry if that was answered somewhere(I personally could not find an answer), also I don’t understand much in how this stuff works.

openssl s_client -starttls smtp -connect smtp.tim.it:587 -showcerts result:

Connecting to 34.141.221.156                          CONNECTED(00000003)
depth=0 C=IT, ST=Milano, O=TELECOM ITALIA SPA, CN=[smtp.tim.it](http://smtp.tim.it/)
verify error:num=20:unable to get local issuer certificate
verify return:1                                       depth=0 C=IT, ST=Milano, O=TELECOM ITALIA SPA, CN=[smtp.tim.it](http://smtp.tim.it/)                                               verify error:num=21:unable to verify the first certificate                                                  verify return:1
depth=0 C=IT, ST=Milano, O=TELECOM ITALIA SPA, CN=[smtp.tim.it](http://smtp.tim.it/)
verify return:1
---
Certificate chain
 0 s:C=IT, ST=Milano, O=TELECOM ITALIA SPA, CN=[smtp.tim.it](http://smtp.tim.it/)
   i:C=IT, ST=Roma, L=Pomezia, O=TI Trust Technologies S.R.L., CN=TI Trust Technologies OV CA
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: May 28 00:00:00 2025 GMT; NotAfter: Jun 27 23:59:59 2026 GMT
-----BEGIN CERTIFICATE-----
MIIHXzCCBkegAwIBAgIQBaf7Bz3GKlRh4r37qfgd/TANBgkqhkiG9w0BAQsFADB7
MQswCQYDVQQGEwJJVDENMAsGA1UECBMEUm9tYTEQMA4GA1UEBxMHUG9tZXppYTEl
MCMGA1UEChMcVEkgVHJ1c3QgVGVjaG5vbG9naWVzIFMuUi5MLjEkMCIGA1UEAxMb
VEkgVHJ1c3QgVGVjaG5vbG9naWVzIE9WIENBMB4XDTI1MDUyODAwMDAwMFoXDTI2
MDYyNzIzNTk1OVowUTELMAkGA1UEBhMCSVQxDzANBgNVBAgTBk1pbGFubzEbMBkG
A1UEChMSVEVMRUNPTSBJVEFMSUEgU1BBMRQwEgYDVQQDEwtzbXRwLnRpbS5pdDCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALeUXDVdSR3vX69HqJcPTK/7
IkZKz5Hu3bVlxt5BVgfq8ikgAFYtGNVSChkm8cC1aqf39HK/lGbjBxmfoXqeqOXU
95yorSHKKS5M65434Gh/qxgZX0rNGOnkPSR9cGxhW5lOitPK755SXWFpXsWEo/A7
ChmuBkJvmWettaKRU4dFfxr9rxCIq/KMDW0pNOx6AVWYw9W22+Fcia7b2nMwI7lJ
NYDlPWEN7Y+v/xhsnR1WoDcjfpHGZFGijAcLKX9EFuzvE+AxNyiKk7JTPDJJvJIS
bN6PBBqLwkTRmZVPUZTZ+EUxIUlndpLeNd3GLUsTrSCxe7o5nsKr20hZeRBR/k8C
AwEAAaOCBAcwggQDMB8GA1UdIwQYMBaAFGPlP/jPJ7ExGSorXM3/LnH7KTjfMB0G
A1UdDgQWBBTt5pcOD+PaovEkJbMeaY3TZJYaNzAOBgNVHQ8BAf8EBAMCBaAwDAYD
VR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwSQYDVR0g
BEIwQDA0BgsrBgEEAbIxAQICSTAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3Rp
Z28uY29tL0NQUzAIBgZngQwBAgIwSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL3Rp
VHJ1c3QuY3JsLnNlY3RpZ28uY29tL1RJVHJ1c3RUZWNobm9sb2dpZXNPVkNBLmNy
bDCBgwYIKwYBBQUHAQEEdzB1MEYGCCsGAQUFBzAChjpodHRwOi8vdGlUcnVzdC5j
cnQuc2VjdGlnby5jb20vVElUcnVzdFRlY2hub2xvZ2llc09WQ0EuY3J0MCsGCCsG
AQUFBzABhh9odHRwOi8vdGlUcnVzdC5vY3NwLnNlY3RpZ28uY29tMIIBfwYKKwYB
BAHWeQIEAgSCAW8EggFrAWkAdQCWl2S/VViXrfdDh2g3CEJ36fA61fak8zZuRqQ/
D8qpxgAAAZcV1yCqAAAEAwBGMEQCIFFVWNEsc2UbBPBpkhqnTj0/KUtKHMAfALFM
DK9O9IF5AiBGa2EYjszuEg9BheOqodEayZZ9MHQBsif+hG+d8G+f0QB3ABmG1Mco
qm/+ugNveCpNAZGqzi1yMQ+uzl1wQS0lTMfUAAABlxXXIEsAAAQDAEgwRgIhAMhe
ncRRlLMTkW0OZr3N5JZqBcsjY83cBIQ+CTsJtx4QAiEAllswEQIQlonTy80tV3/A
bKzlbZLJiv3YD/V8TjHXK4MAdwAOV5S8866pPjMbLJkHs/eQ35vCPXEyJd0hqSWs
YcVOIQAAAZcV1yBNAAAEAwBIMEYCIQDj0Th5VH8vK1cToYt7hiHgSBjBa62e1FcX
KbaBkPb8JwIhAPiqdWtqVhyynkgJarD/WKDAvTLd69U7JPkiSeek1tt0MIHiBgNV
HREEgdowgdeCC3NtdHAudGltLml0gg4qLnBvc3RhLnRpbS5pdIIKYm94LnRpbi5p
dIILaW1hcC50aW0uaXSCC2ltYXAudGluLml0ggxpbWFwcy50aW4uaXSCC2luLmFs
aWNlLml0ggttYWlsLnRpbi5pdIIJbXgudGltLml0gglteC50aW4uaXSCDG91dC5h
bGljZS5pdIIKcG9wLnRpbS5pdIIKcG9wLnRpbi5pdIILcG9wcy50aW4uaXSCC3Nt
dHAudGluLml0ggxzbXRwcy50aW4uaXSCBnRpbi5pdDANBgkqhkiG9w0BAQsFAAOC
AQEAYXfyRlm5bU3Mm2fyXHi9OXl90cAZvd57sWb5geXDL1Ubwmmqqk/eCLxDsj8d
3bXmMjWQjTs/ciphG358H1PonrhF7Ct1ZW1njYEK0RZJsOM0uppBMFEhrCg3C77z
6iXNUoZ8Nx5bfUsST3dwR0ieA99OKXV8qRKolO23FGACoH4eIhrZc7X2J0euQeGY
gGNduEVael2IIS2eAoXVmA0t06UuF/FsVbvmrX6WC7W/SjZ04u6zCkNZkIi17I4W
+1TtZ9GR3TiEO1rAl7vsAaaMKLoAG8T5PuiG7iO96KTa/bj5lhXMm5UvyLY0RLxi
++bD6UvAIbf/+wtMFumZwctOXQ==
-----END CERTIFICATE-----
 1 s:C=IT, ST=Roma, L=Pomezia, O=TI Trust Technologies S.R.L., CN=TI Trust Technologies DV CA
   i:C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust RSA Certification Authority
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA384
   v:NotBefore: Jul 30 00:00:00 2019 GMT; NotAfter: Jul 29 23:59:59 2029 GMT
-----BEGIN CERTIFICATE-----
MIIGBjCCA+6gAwIBAgIRALMcXS7T8KrJaCn0VoiLO44wDQYJKoZIhvcNAQEMBQAw
gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK
ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD
VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE5
MDczMDAwMDAwMFoXDTI5MDcyOTIzNTk1OVowezELMAkGA1UEBhMCSVQxDTALBgNV
BAgTBFJvbWExEDAOBgNVBAcTB1BvbWV6aWExJTAjBgNVBAoTHFRJIFRydXN0IFRl
Y2hub2xvZ2llcyBTLlIuTC4xJDAiBgNVBAMTG1RJIFRydXN0IFRlY2hub2xvZ2ll
cyBEViBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKRYvlj4gqxr
SMQPfD5tXRBiK9tifjCoeFZ6BnPwT+G6XthhxODxX1ZVrqXjREjtef6uQc1K9ao/
gXJ5jA4soV72lRLvxyVZ9uHcw83WZft+6oqpQaSOdo8Bvag3HEegoSb3zElSmPhv
NArENCdK6uiHmXvOW6uzPPdXG4uMeqyTdZVlR1u27UVJ5xB2Um6ryNfHqAA4eN22
djopHRIeVAu5sQoeAurLTBOfq4QEpecDm0xa+ySe642X+HVNzQGye7diI0sD/ngf
Ir9x7h1HxyqxC24rXT4XZlK+ZA/d5bpuvoMQMDEV4CKo6T9J7oo+Oq3u+HFwBo94
BClLlXBc9aMCAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvA
nfKyA2bLMB0GA1UdDgQWBBTWUeJ5s8ZXr95WY+CywoVtRjQVpjAOBgNVHQ8BAf8E
BAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
KwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQICSTAIBgZngQwBAgEwUAYD
VR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVz
dFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/
BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJT
QUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1
c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQA0MXhgkf6J+NnG0SAwIkNrC0zv27vT
IwtAkVcp3TaIIdnIT11XJ1mVmt7MwidqMC7cYXqe81zlIlVB65+NwZWuhEiM+1ce
vu8MFA6xcaFHFTTFYFIsBGHw7Fgbo54rP5cIHKehyCcCxvFFdQ2tvbMVjGWMubZO
5sD0rAWb1gGkVQ8uNgwR2RJrrfllPDqbNz/PNyxAAJWtY7dpTd1duEvA8u+uJ2wk
0DHKtPX8MvmojNwL89KZMUbXE+Ecg4Dc120SWjk6tcExkkceRP91MQv9oSABGw03
mSO2F02LguHJbfrS3kP1Twx68B33SIzR7OUcP93aAU+eKjCiY+jMqfr/knaqmaY1
U5AEANMHIFLoM7SOYvQhBa0sqNAxiwIZPT2lGxN8/znPAf9wEk7zHOpsJ2Qd+Tb1
Or6F+Y0Q2SsVGCxEB+HiFG9Az/rBk0sZhMuCyvd81XYPO7aTJjf/ppwtiBxdlTJK
+/hjAlzEHGZzeVDbAJ2/K1XJgxsqYpfET8qfyOrDjbCfiz4zuIy49aJuU0M8NMcQ
+qBBcLfHP9K+wpAJ88ERGlFx0uPip8Trd4L2asW2K+We0S3epfCC9/zmMfi4uVQ+
HiODkiJQstTt0nS88Vuq0uYIynnu52G3ueKVtNkCb45AxT8MO2UIH8Dm5cvHV84G
BTbqpLm41FxfJQ==
-----END CERTIFICATE-----
---
Server certificate
subject=C=IT, ST=Milano, O=TELECOM ITALIA SPA, CN=[smtp.tim.it](http://smtp.tim.it/)
issuer=C=IT, ST=Roma, L=Pomezia, O=TI Trust Technologies S.R.L., CN=TI Trust Technologies OV CA
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 4230 bytes and written 442 bytes
Verification error: unable to verify the first certificate
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Protocol: TLSv1.3
Server public key is 2048 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)
---
250 SIZE 41943040
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: 9B6B75263EB4AD412A50E5C2505E3F7D25334F829F66270942D8482E5AFB88CD
    Session-ID-ctx:
    Resumption PSK: 0F05D0274C530335E545A9284F72F7F7E25F369D9145389C5E6CBE9106D2F3715521623C444A2716798F3C22C2707F64
    PSK identity: None
    PSK identity hint: None
    TLS session ticket lifetime hint: 7200 (seconds)
    TLS session ticket:
    0000 - 1d fb 8f d0 06 5e 01 bd-73 7d c8 19 a1 aa 57 ba   .....^..s}....W.
    0010 - 74 10 03 a4 a1 54 24 9c-72 eb ba bf ea 27 70 75   t....T$.r....'pu
    0020 - ee 18 a4 89 12 a2 b0 69-28 90 87 3a b2 47 aa 3d   .......i(..:.G.=
    0030 - bc 87 05 10 00 8e 13 85-e4 6a 2c ed ec 2a 3a d6   .........j,..*:.
    0040 - 6b c5 07 8e 47 25 f6 e0-ec 18 aa 71 a2 d7 18 84   k...G%.....q....
    0050 - 24 9a f7 d9 dc 9e 74 19-63 2b b7 bc 9f cc fe 31   $.....t.c+.....1
    0060 - 7b 5d d6 84 2a 11 0f 6c-d0 cc 41 46 73 15 21 9d   {]..*..l..AFs.!.
    0070 - 8c dd d4 7f bf 5d b4 bf-54 91 51 1e c3 4b 50 85   .....]..T.Q..KP.
    0080 - 15 ec 38 28 10 9e c9 04-d7 f6 89 e7 e1 2e 5b ef   ..8(..........[.
    0090 - a6 97 a3 7e c7 b1 cf d7-de 4e ea 80 f4 21 d8 56   ...~.....N...!.V
    00a0 - e7 47 b5 93 a6 58 22 85-0d ec 9f dc bf 89 32 0d   .G...X".......2.
    00b0 - da 14 72 e5 e9 b2 16 1e-73 fe 2a 17 18 08 69 e2   ..r.....s.*...i.
    00c0 - 66 d0 24 9f 8f fe 71 a2-69 47 cc c9 0a 3e 24 19   f.$...q.iG...>$.

    Start Time: 1749320149
    Timeout   : 7200 (sec)
    Verify return code: 21 (unable to verify the first certificate)
    Extended master secret: no
    Max Early Data: 0
---
read R BLOCK
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: E56031F7BA3FCE03B3AA672A023E569CC130916A64C254CB7F28A111DB1AF7AD
    Session-ID-ctx:
    Resumption PSK: 1804DA18160B2708DC404D540273359C304E1D0EA95681D06AFA0E5B947F8D4FA4100D3CC054E4B8692A672E01B9A8E7
    PSK identity: None
    PSK identity hint: None
    TLS session ticket lifetime hint: 7200 (seconds)
    TLS session ticket:
    0000 - 1d fb 8f d0 06 5e 01 bd-73 7d c8 19 a1 aa 57 ba   .....^..s}....W.
    0010 - 0d c3 09 c9 21 b7 fd 53-df b0 db c6 91 40 25 10   ....!..S.....@%.
    0020 - 46 da a5 7e cd 37 5c 74-2f 88 6c 51 c4 63 f9 01   F..~.7\t/.lQ.c..
    0030 - c7 04 56 5f 96 ee 85 ca-dd 74 93 bd 5b 3e 21 b5   ..V_.....t..[>!.
    0040 - f3 ee 12 14 6a bb 55 00-2b 5d c0 70 fc 8c ab 93   ....j.U.+].p....
    0050 - 32 c3 ba 31 18 43 59 bd-53 c9 ff c0 4e 76 3f cb   2..1.CY.S...Nv?.
    0060 - f0 53 34 15 2b b2 9b 69-3c f4 b7 a6 7f 1f c6 cf   .S4.+..i<.......
    0070 - 57 97 fe 7e 27 ad 5d 9a-3f e0 75 83 11 27 a9 0c   W..~'.].?.u..'..
    0080 - 5a c1 59 a1 28 50 ac ef-38 c6 23 a3 ef 4b d0 ef   Z.Y.(P..8.#..K..
    0090 - 8d cf 83 09 76 67 80 cf-54 bc c7 ab d3 92 c1 09   ....vg..T.......
    00a0 - 2d b5 af 2a 32 2a 2b 11-46 4a ee e8 f8 c1 dd b4   -..*2*+.FJ......
    00b0 - 21 c3 a0 c6 80 40 95 8e-0e 3e 0d 65 64 0e 75 45   !....@...>.ed.uE
    00c0 - 4c 00 0c 95 c7 5b 7b 74-54 44 16 45 1e a3 1f 53   L....[{tTD.E...S

    Start Time: 1749320149
    Timeout   : 7200 (sec)
    Verify return code: 21 (unable to verify the first certificate)
    Extended master secret: no
    Max Early Data: 0
---
read R BLOCK