Merge ~codersquid/snappy-hwe-snaps/+git/wifi-connect:cert-generation into ~snappy-hwe-team/snappy-hwe-snaps/+git/wifi-connect:master

Proposed by Sheila Miguez
Status: Rejected
Rejected by: Sheila Miguez
Proposed branch: ~codersquid/snappy-hwe-snaps/+git/wifi-connect:cert-generation
Merge into: ~snappy-hwe-team/snappy-hwe-snaps/+git/wifi-connect:master
Diff against target: 221 lines (+209/-0)
2 files modified
cert/cert.go (+131/-0)
cert/cert_test.go (+78/-0)
Reviewer Review Type Date Requested Status
System Enablement Bot continuous-integration Approve
Review via email: mp+326967@code.launchpad.net

Description of the change

This change adds a cert package responsible for generating self signed certificates. The code is reused from snapweb, with a few minor differences:

* instead of fatal errors, we return errors and allow callers to decide how to handle failures
* files are stored in SNAP_COMMON rather than SNAP_DATA

To post a comment you must log in.
Revision history for this message
System Enablement Bot (system-enablement-ci-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kyle Nitzsche (knitzsche) wrote :

Can this PR also include the code that uses this cert package? that is, I don't see why we add it if we don't use it (unless I misunderstand something...)

Revision history for this message
Roberto Mier Escandon (rmescandon) wrote :

Looks good (I've not tested it at all). An inline comment

Revision history for this message
Sheila Miguez (codersquid) wrote :

> Can this PR also include the code that uses this cert package? that is, I
> don't see why we add it if we don't use it (unless I misunderstand
> something...)

I'll go ahead and cancel this MR and stick it with the rest of hte https work. I wanted to break things up to make things easier to review but in hindsight splitting this one out wasn't the best idea.

Unmerged commits

1289197... by Sheila Miguez

reuse self-signing cert package from snapweb

This reuses snapweb code with some minor changes

* instead of fatal errors, we return errors and allow callers to decide
  how to handle failures
* files are stored in SNAP_COMMON rather than SNAP_DATA

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/cert/cert.go b/cert/cert.go
2new file mode 100644
3index 0000000..60242c6
4--- /dev/null
5+++ b/cert/cert.go
6@@ -0,0 +1,131 @@
7+/*
8+ * Copyright (C) 2017 Canonical Ltd
9+ *
10+ * This program is free software: you can redistribute it and/or modify
11+ * it under the terms of the GNU General Public License version 3 as
12+ * published by the Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful,
15+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+ * GNU General Public License for more details.
18+ *
19+ * You should have received a copy of the GNU General Public License
20+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
21+ *
22+ */
23+
24+package cert
25+
26+/*
27+ * help and re-use from https://github.com/snapcore/snapweb/blob/0.25/cmd/snapweb/cert.go
28+ */
29+
30+import (
31+ "crypto/rand"
32+ "crypto/rsa"
33+ "crypto/x509"
34+ "crypto/x509/pkix"
35+ "encoding/pem"
36+ "errors"
37+ "fmt"
38+ "math/big"
39+ "net"
40+ "os"
41+ "path/filepath"
42+ "time"
43+)
44+
45+// CertFile path to certificate file
46+var CertFile = filepath.Join(os.Getenv("SNAP_COMMON"), "cert.pem")
47+
48+// KeyFile path to key file
49+var KeyFile = filepath.Join(os.Getenv("SNAP_COMMON"), "key.pem")
50+
51+// FindOrGenerateCertificate finds or creates the certificate & key files if they do not exist
52+func FindOrGenerateCertificate() error {
53+
54+ _, err1 := os.Stat(CertFile)
55+ _, err2 := os.Stat(KeyFile)
56+
57+ // skip if both cert and key exist
58+ if err1 == nil && err2 == nil {
59+ return nil
60+ }
61+
62+ return GenerateCertificate(CertFile, KeyFile)
63+}
64+
65+// GenerateCertificate will generate a new self-signed certifiate at startup
66+func GenerateCertificate(certFilename string, keyFilename string) error {
67+ /* With help from https://golang.org/src/crypto/tls/generate_cert.go */
68+
69+ priv, err := rsa.GenerateKey(rand.Reader, 2048)
70+ if err != nil {
71+ return fmt.Errorf("Failed to generate private key: %v", err)
72+ }
73+
74+ notBefore := time.Now()
75+ validFor := 365 * 24 * time.Hour
76+ notAfter := notBefore.Add(validFor)
77+
78+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
79+ serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
80+ if err != nil {
81+ return fmt.Errorf("Failed to generate serial number: %v", err)
82+ }
83+
84+ template := x509.Certificate{
85+ SerialNumber: serialNumber,
86+ Subject: pkix.Name{
87+ Organization: []string{"wifi-connect"},
88+ },
89+ NotBefore: notBefore,
90+ NotAfter: notAfter,
91+ KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
92+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
93+ BasicConstraintsValid: true,
94+ }
95+
96+ // TODO: add other IP addresses and hostnames (check Avahi)
97+ template.IPAddresses = append(template.IPAddresses, net.ParseIP("127.0.0.1"))
98+ template.IsCA = false
99+
100+ derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
101+ if err != nil {
102+ return fmt.Errorf("Failed to create certificate: %v", err)
103+ }
104+
105+ err = createPublicKeycertFile(certFilename, derBytes)
106+ if err != nil {
107+ return err
108+ }
109+ err = createPrivateKeyFile(keyFilename, priv)
110+ if err != nil {
111+ return err
112+ }
113+ return nil
114+}
115+
116+func createPublicKeycertFile(filename string, b []byte) error {
117+ certOut, err := os.Create(filename)
118+ if err != nil {
119+ return fmt.Errorf("failed to open cert.pem for writing: %v", err)
120+ }
121+ pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: b})
122+ certOut.Close()
123+ return nil
124+}
125+
126+func createPrivateKeyFile(filename string, k *rsa.PrivateKey) error {
127+ keyOut, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
128+ if err != nil {
129+ return fmt.Errorf("failed to open key.pem for writing: %v", err)
130+ }
131+ if k == nil {
132+ return errors.New("Invalid private key context")
133+ }
134+ pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)})
135+ keyOut.Close()
136+ return nil
137+}
138diff --git a/cert/cert_test.go b/cert/cert_test.go
139new file mode 100644
140index 0000000..8966043
141--- /dev/null
142+++ b/cert/cert_test.go
143@@ -0,0 +1,78 @@
144+/*
145+ * Copyright (C) 2017 Canonical Ltd
146+ *
147+ * This program is free software: you can redistribute it and/or modify
148+ * it under the terms of the GNU General Public License version 3 as
149+ * published by the Free Software Foundation.
150+ *
151+ * This program is distributed in the hope that it will be useful,
152+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
153+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
154+ * GNU General Public License for more details.
155+ *
156+ * You should have received a copy of the GNU General Public License
157+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
158+ *
159+ */
160+
161+package cert
162+
163+/*
164+ * help and re-use from https://github.com/snapcore/snapweb/blob/0.25/cmd/snapweb/cert_test.go
165+ */
166+
167+import (
168+ "io/ioutil"
169+ "os"
170+
171+ . "gopkg.in/check.v1"
172+)
173+
174+type CertSuite struct {
175+ snapdata string
176+ certFilename string
177+ keyFilename string
178+}
179+
180+var _ = Suite(&CertSuite{})
181+
182+func (s *CertSuite) SetUpTest(c *C) {
183+ s.snapdata = c.MkDir()
184+ os.Setenv("SNAP_COMMON", s.snapdata)
185+}
186+
187+func (s *CertSuite) TearDownTest(c *C) {
188+ os.RemoveAll(s.snapdata)
189+}
190+
191+func (s *CertSuite) TestDumpCertificate(c *C) {
192+ c.Assert(ioutil.WriteFile(CertFile, nil, 0600), IsNil)
193+ c.Assert(ioutil.WriteFile(KeyFile, nil, 0600), IsNil)
194+
195+ FindOrGenerateCertificate()
196+ certData, err := ioutil.ReadFile(CertFile)
197+ c.Assert(err, IsNil)
198+ keyData, err := ioutil.ReadFile(KeyFile)
199+ c.Assert(err, IsNil)
200+
201+ FindOrGenerateCertificate()
202+ certData2, err := ioutil.ReadFile(CertFile)
203+ c.Assert(err, IsNil)
204+ keyData2, err := ioutil.ReadFile(KeyFile)
205+ c.Assert(err, IsNil)
206+
207+ // ensure the certificate is not re-generated if one already exists
208+ c.Assert(certData, DeepEquals, certData2)
209+ c.Assert(keyData, DeepEquals, keyData2)
210+}
211+
212+func (s *CertSuite) TestGenerateCertificate(c *C) {
213+ GenerateCertificate(CertFile, KeyFile)
214+ _, err := os.Stat(s.certFilename)
215+ c.Assert(err, IsNil)
216+ _, err = os.Stat(s.keyFilename)
217+ c.Assert(err, IsNil)
218+ // TODO check for content
219+ c.Assert(createPublicKeycertFile(CertFile, nil), IsNil)
220+ c.Assert(createPrivateKeyFile(KeyFile, nil), NotNil)
221+}

Subscribers

People subscribed via source and target branches