From 7c13b50a202d92a9353399f69781ce3f8c6ca8ec Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Wed, 30 Aug 2023 16:14:30 +0200 Subject: [PATCH 1/3] Correctly lookup for RootCA --- certificates/certutils.go | 16 ++++++++-------- certificates/certutils_test.go | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 certificates/certutils_test.go diff --git a/certificates/certutils.go b/certificates/certutils.go index bd272d6..1bd635b 100644 --- a/certificates/certutils.go +++ b/certificates/certutils.go @@ -45,15 +45,15 @@ func ScrapeRootCertificatesFromURL(URL string) (*x509.Certificate, error) { return nil, err } - peerCertificates := conn.ConnectionState().PeerCertificates - if len(peerCertificates) == 0 { - err = fmt.Errorf("no peer certificates found at %s", URL) - logrus.Error(err) - return nil, err + chains := conn.ConnectionState().VerifiedChains + if len(chains) == 0 { + return nil, fmt.Errorf("no certificates found at %s", URL) } - - rootCertificate := peerCertificates[len(peerCertificates)-1] - return rootCertificate, nil + rootCertificate := chains[len(chains)-1] + if len(rootCertificate) == 0 { + return nil, fmt.Errorf("no certificates found at %s", URL) + } + return rootCertificate[len(rootCertificate)-1], nil } // LoadCertificatesFromFile read certificates from the given file. PEM and CER formats diff --git a/certificates/certutils_test.go b/certificates/certutils_test.go new file mode 100644 index 0000000..67f281a --- /dev/null +++ b/certificates/certutils_test.go @@ -0,0 +1,14 @@ +package certificates_test + +import ( + "testing" + + "github.com/arduino/arduino-fwuploader/certificates" + "github.com/stretchr/testify/require" +) + +func TestScrapeRootCertificatesFromURL(t *testing.T) { + cert, err := certificates.ScrapeRootCertificatesFromURL("www.arduino.cc:443") + require.NoError(t, err) + require.Equal(t, cert.Issuer, cert.Subject) +} From 246c80c352f992b7809babaa114f44cafaa0f62c Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Wed, 30 Aug 2023 16:34:15 +0200 Subject: [PATCH 2/3] update docs --- docs/plugins.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/plugins.md b/docs/plugins.md index de2fb8f..6379ad8 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -94,11 +94,8 @@ Error: reboot mode: upload commands sketch: setting DTR to OFF #### I flashed the certificates, but I am unable to reach the host -The **whole certificate chain** is needed to make it work. Using -[`-u` flags](commands/arduino-fwuploader_certificates_flash.md#options) (ex: `-u www.arduino.cc:443`) won’t work because -it only downloads the root certificates. The solution is to use only the -[`-f` flag](commands/arduino-fwuploader_certificates_flash.md#options) and provide a pem certificate containing the -whole chain. +There was a bug in the arduino-fwuploader prior `2.4.1` which didn't pick the actual root certificate. Upgrading to the +latest version solves the problem. #### My antivirus says that `espflash` is a threat From 7dc04044155381b386f722465e4bd3a61f4e823c Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Wed, 30 Aug 2023 17:35:54 +0200 Subject: [PATCH 3/3] Scrape all possible root certificate In the uno r4 we're using mbedtls which has a strange behaviour. And some root certificates won't work. Therfore the most simple solution is using all the possible ones, found during the handshake. --- certificates/certutils.go | 11 ++++++----- certificates/certutils_test.go | 6 ++++-- cli/certificates/flash.go | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/certificates/certutils.go b/certificates/certutils.go index 1bd635b..d48b9a3 100644 --- a/certificates/certutils.go +++ b/certificates/certutils.go @@ -30,7 +30,7 @@ import ( // ScrapeRootCertificatesFromURL downloads from a webserver the root certificate // required to connect to that server from the TLS handshake response. -func ScrapeRootCertificatesFromURL(URL string) (*x509.Certificate, error) { +func ScrapeRootCertificatesFromURL(URL string) ([]*x509.Certificate, error) { conn, err := tls.Dial("tcp", URL, &tls.Config{ InsecureSkipVerify: false, }) @@ -49,11 +49,12 @@ func ScrapeRootCertificatesFromURL(URL string) (*x509.Certificate, error) { if len(chains) == 0 { return nil, fmt.Errorf("no certificates found at %s", URL) } - rootCertificate := chains[len(chains)-1] - if len(rootCertificate) == 0 { - return nil, fmt.Errorf("no certificates found at %s", URL) + rootCertificates := make([]*x509.Certificate, len(chains)) + for i, chain := range chains { + // The last certificate of the chain is always the Root Certificate + rootCertificates[i] = chain[len(chain)-1] } - return rootCertificate[len(rootCertificate)-1], nil + return rootCertificates, nil } // LoadCertificatesFromFile read certificates from the given file. PEM and CER formats diff --git a/certificates/certutils_test.go b/certificates/certutils_test.go index 67f281a..86e2821 100644 --- a/certificates/certutils_test.go +++ b/certificates/certutils_test.go @@ -8,7 +8,9 @@ import ( ) func TestScrapeRootCertificatesFromURL(t *testing.T) { - cert, err := certificates.ScrapeRootCertificatesFromURL("www.arduino.cc:443") + rootCerts, err := certificates.ScrapeRootCertificatesFromURL("www.arduino.cc:443") require.NoError(t, err) - require.Equal(t, cert.Issuer, cert.Subject) + for _, cert := range rootCerts { + require.Equal(t, cert.Issuer, cert.Subject) + } } diff --git a/cli/certificates/flash.go b/cli/certificates/flash.go index 0ca00c0..85906c3 100644 --- a/cli/certificates/flash.go +++ b/cli/certificates/flash.go @@ -121,11 +121,11 @@ func flashCertificates(uploader *plugin.FwUploader, certificateURLs, certificate for _, URL := range certificateURLs { logrus.Infof("Converting and flashing certificate from %s", URL) stdout.Write([]byte(fmt.Sprintf("Converting and flashing certificate from %s\n", URL))) - rootCert, err := certificates.ScrapeRootCertificatesFromURL(URL) + rootCerts, err := certificates.ScrapeRootCertificatesFromURL(URL) if err != nil { return nil, err } - allCerts = append(allCerts, rootCert) + allCerts = append(allCerts, rootCerts...) } f, err := certsBundle.Create()