Skip to content

Commit 67412b9

Browse files
committed
Add logic to flash certificates
1 parent 4c0c682 commit 67412b9

File tree

5 files changed

+280
-10
lines changed

5 files changed

+280
-10
lines changed

flasher/certificate.go

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
FirmwareUploader
3+
Copyright (c) 2021 Arduino LLC. All right reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package flasher
21+
22+
import (
23+
"bytes"
24+
"crypto/rsa"
25+
"crypto/sha1"
26+
"crypto/x509"
27+
"crypto/x509/pkix"
28+
"encoding/asn1"
29+
"encoding/binary"
30+
"time"
31+
32+
"github.com/sirupsen/logrus"
33+
)
34+
35+
func calculateNameSha1(cert *x509.Certificate) (b []byte, err error) {
36+
nameSha1 := sha1.New()
37+
38+
var subjectDistinguishedNameSequence pkix.RDNSequence
39+
40+
if _, err = asn1.Unmarshal(cert.RawSubject, &subjectDistinguishedNameSequence); err != nil {
41+
logrus.Error(err)
42+
return nil, err
43+
}
44+
45+
for _, dn := range subjectDistinguishedNameSequence {
46+
nameSha1.Write([]byte(dn[0].Value.(string)))
47+
}
48+
49+
b = nameSha1.Sum(nil)
50+
51+
return
52+
}
53+
54+
func convertTime(time time.Time) (b []byte, err error) {
55+
asn1Bytes, err := asn1.Marshal(time)
56+
if err != nil {
57+
logrus.Error(err)
58+
return nil, err
59+
}
60+
61+
b = bytes.Repeat([]byte{0x00}, 20) // value must be zero bytes
62+
copy(b, asn1Bytes[2:]) // copy but drop the first two bytes
63+
64+
return
65+
}
66+
67+
func modulusN(publicKey rsa.PublicKey) []byte {
68+
return publicKey.N.Bytes()
69+
}
70+
71+
func publicExponent(publicKey rsa.PublicKey) (b []byte) {
72+
b = make([]byte, 4)
73+
binary.BigEndian.PutUint32(b, uint32(publicKey.E))
74+
// strip leading zeros
75+
for b[0] == 0 {
76+
b = b[1:]
77+
}
78+
return
79+
}
80+
81+
func uint16ToBytes(i int) (b []byte) {
82+
b = make([]byte, 2)
83+
binary.LittleEndian.PutUint16(b, uint16(i))
84+
return
85+
}

flasher/flasher.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (e FlasherError) Error() string {
4545

4646
type Flasher interface {
4747
FlashFirmware(firmwareFile *paths.Path) error
48-
FlashCertificates(certificatePaths *paths.PathList) error
48+
FlashCertificates(certificatePaths *paths.PathList, URLs []string) error
4949
Close() error
5050

5151
hello() error

flasher/nina.go

+82-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ package flasher
2222
import (
2323
"bytes"
2424
"crypto/md5"
25+
"crypto/tls"
26+
"crypto/x509"
2527
"encoding/binary"
28+
"encoding/pem"
2629
"fmt"
2730
"strconv"
2831
"time"
@@ -82,9 +85,85 @@ func (f *NinaFlasher) FlashFirmware(firmwareFile *paths.Path) error {
8285
return f.md5sum(data)
8386
}
8487

85-
func (f *NinaFlasher) FlashCertificates(certificatePaths *paths.PathList) error {
86-
// TODO
87-
return nil
88+
func (f *NinaFlasher) FlashCertificates(certificatePaths *paths.PathList, URLs []string) error {
89+
var certificatesData []byte
90+
for _, certPath := range *certificatePaths {
91+
logrus.Infof("Converting and flashing certificate %s", certPath)
92+
93+
data, err := f.certificateFromFile(certPath)
94+
if err != nil {
95+
return err
96+
}
97+
certificatesData = append(certificatesData, data...)
98+
}
99+
100+
for _, URL := range URLs {
101+
logrus.Infof("Converting and flashing certificate from %s", URL)
102+
data, err := f.certificateFromURL(URL)
103+
if err != nil {
104+
return err
105+
}
106+
certificatesData = append(certificatesData, data...)
107+
}
108+
109+
certificatesDataLimit := 0x20000
110+
if len(certificatesData) > certificatesDataLimit {
111+
err := fmt.Errorf("certificates data %d exceeds limit of %d bytes", len(certificatesData), certificatesDataLimit)
112+
logrus.Error(err)
113+
return err
114+
}
115+
116+
// Pad certificatesData to flash page
117+
for len(certificatesData)%int(f.payloadSize) != 0 {
118+
certificatesData = append(certificatesData, 0)
119+
}
120+
121+
certificatesOffset := 0x10000
122+
return f.flashChunk(certificatesOffset, certificatesData)
123+
}
124+
125+
func (f *NinaFlasher) certificateFromFile(certificateFile *paths.Path) ([]byte, error) {
126+
data, err := certificateFile.ReadFile()
127+
if err != nil {
128+
logrus.Error(err)
129+
return nil, err
130+
}
131+
132+
cert, err := x509.ParseCertificate(data)
133+
if err != nil {
134+
logrus.Error(err)
135+
return nil, err
136+
}
137+
138+
return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}), nil
139+
}
140+
141+
func (f *NinaFlasher) certificateFromURL(URL string) ([]byte, error) {
142+
config := &tls.Config{
143+
InsecureSkipVerify: true,
144+
}
145+
146+
conn, err := tls.Dial("tcp", URL, config)
147+
if err != nil {
148+
logrus.Error(err)
149+
return nil, err
150+
}
151+
defer conn.Close()
152+
153+
if err := conn.Handshake(); err != nil {
154+
logrus.Error(err)
155+
return nil, err
156+
}
157+
158+
peerCertificates := conn.ConnectionState().PeerCertificates
159+
if len(peerCertificates) == 0 {
160+
err = fmt.Errorf("no peer certificates found at %s", URL)
161+
logrus.Error(err)
162+
return nil, err
163+
}
164+
165+
rootCertificate := peerCertificates[len(peerCertificates)-1]
166+
return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCertificate.Raw}), nil
88167
}
89168

90169
// Close the port used by this flasher

flasher/sara.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,8 @@ func (f *SaraFlasher) FlashFirmware(firmwareFile *paths.Path) error {
104104
return err
105105
}
106106

107-
func (f *SaraFlasher) FlashCertificates(certificatePaths *paths.PathList) error {
108-
// TODO
109-
return nil
107+
func (f *SaraFlasher) FlashCertificates(certificatePaths *paths.PathList, URLs []string) error {
108+
return fmt.Errorf("not supported by SaraFlasher")
110109
}
111110

112111
func (f *SaraFlasher) Close() error {

flasher/winc.go

+110-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ package flasher
2121

2222
import (
2323
"bytes"
24+
"crypto/rsa"
25+
"crypto/tls"
26+
"crypto/x509"
2427
"encoding/binary"
2528
"errors"
2629
"fmt"
@@ -68,9 +71,113 @@ func (f *WincFlasher) FlashFirmware(firmwareFile *paths.Path) error {
6871
return f.flashChunk(firmwareOffset, data)
6972
}
7073

71-
func (f *WincFlasher) FlashCertificates(certificatePaths *paths.PathList) error {
72-
// TODO
73-
return nil
74+
func (f *WincFlasher) FlashCertificates(certificatePaths *paths.PathList, URLs []string) error {
75+
var certificatesData []byte
76+
certificatesNumber := 0
77+
for _, certPath := range *certificatePaths {
78+
logrus.Infof("Converting and flashing certificate %s", certPath)
79+
80+
data, err := f.certificateFromFile(certPath)
81+
if err != nil {
82+
return err
83+
}
84+
certificatesData = append(certificatesData, data...)
85+
certificatesNumber++
86+
}
87+
88+
for _, URL := range URLs {
89+
logrus.Infof("Converting and flashing certificate from %s", URL)
90+
data, err := f.certificateFromURL(URL)
91+
if err != nil {
92+
return err
93+
}
94+
certificatesData = append(certificatesData, data...)
95+
certificatesNumber++
96+
}
97+
98+
certificatesOffset := 0x4000
99+
return f.flashChunk(certificatesOffset, certificatesData)
100+
}
101+
102+
func (f *WincFlasher) certificateFromFile(certificateFile *paths.Path) ([]byte, error) {
103+
data, err := certificateFile.ReadFile()
104+
if err != nil {
105+
logrus.Error(err)
106+
return nil, err
107+
}
108+
109+
cert, err := x509.ParseCertificate(data)
110+
if err != nil {
111+
logrus.Error(err)
112+
return nil, err
113+
}
114+
115+
return f.getCertificateData(cert)
116+
}
117+
118+
func (f *WincFlasher) certificateFromURL(URL string) ([]byte, error) {
119+
config := &tls.Config{
120+
InsecureSkipVerify: true,
121+
}
122+
123+
conn, err := tls.Dial("tcp", URL, config)
124+
if err != nil {
125+
logrus.Error(err)
126+
return nil, err
127+
}
128+
defer conn.Close()
129+
130+
if err := conn.Handshake(); err != nil {
131+
logrus.Error(err)
132+
return nil, err
133+
}
134+
135+
peerCertificates := conn.ConnectionState().PeerCertificates
136+
if len(peerCertificates) == 0 {
137+
err = fmt.Errorf("no peer certificates found at %s", URL)
138+
logrus.Error(err)
139+
return nil, err
140+
}
141+
rootCertificate := peerCertificates[len(peerCertificates)-1]
142+
return f.getCertificateData(rootCertificate)
143+
}
144+
145+
func (f *WincFlasher) getCertificateData(cert *x509.Certificate) ([]byte, error) {
146+
b := []byte{}
147+
nameSHA1Bytes, err := calculateNameSha1(cert)
148+
if err != nil {
149+
return nil, err
150+
}
151+
152+
notBeforeBytes, err := convertTime(cert.NotBefore)
153+
if err != nil {
154+
return nil, err
155+
}
156+
157+
notAfterBytes, err := convertTime(cert.NotAfter)
158+
if err != nil {
159+
return nil, err
160+
}
161+
162+
rsaPublicKey := *cert.PublicKey.(*rsa.PublicKey)
163+
164+
rsaModulusNBytes := modulusN(rsaPublicKey)
165+
rsaPublicExponentBytes := publicExponent(rsaPublicKey)
166+
167+
rsaModulusNLenBytes := uint16ToBytes(len(rsaModulusNBytes))
168+
rsaPublicExponentLenBytes := uint16ToBytes(len(rsaPublicExponentBytes))
169+
170+
b = append(b, nameSHA1Bytes...)
171+
b = append(b, rsaModulusNLenBytes...)
172+
b = append(b, rsaPublicExponentLenBytes...)
173+
b = append(b, notBeforeBytes...)
174+
b = append(b, notAfterBytes...)
175+
b = append(b, rsaModulusNBytes...)
176+
b = append(b, rsaPublicExponentBytes...)
177+
for (len(b) & 3) != 0 {
178+
b = append(b, 0xff) // padding
179+
}
180+
return b, nil
74181
}
75182

76183
func (f *WincFlasher) Close() error {

0 commit comments

Comments
 (0)