gopkg.in/ubuntu-core/snappy.v0@v0.0.0-20210902073436-25a8614f10a6/asserts/signtool/sign_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program 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 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package signtool_test 21 22 import ( 23 "encoding/json" 24 "testing" 25 26 . "gopkg.in/check.v1" 27 28 "github.com/snapcore/snapd/asserts" 29 "github.com/snapcore/snapd/asserts/assertstest" 30 "github.com/snapcore/snapd/asserts/signtool" 31 ) 32 33 func TestSigntool(t *testing.T) { TestingT(t) } 34 35 type signSuite struct { 36 keypairMgr asserts.KeypairManager 37 testKeyID string 38 } 39 40 var _ = Suite(&signSuite{}) 41 42 func (s *signSuite) SetUpSuite(c *C) { 43 testKey, _ := assertstest.GenerateKey(752) 44 45 s.keypairMgr = asserts.NewMemoryKeypairManager() 46 s.keypairMgr.Put(testKey) 47 s.testKeyID = testKey.PublicKey().ID() 48 } 49 50 func expectedModelHeaders(a asserts.Assertion) map[string]interface{} { 51 m := map[string]interface{}{ 52 "type": "model", 53 "authority-id": "user-id1", 54 "series": "16", 55 "brand-id": "user-id1", 56 "model": "baz-3000", 57 "architecture": "amd64", 58 "gadget": "brand-gadget", 59 "kernel": "baz-linux", 60 "store": "brand-store", 61 "required-snaps": []interface{}{"foo", "bar"}, 62 "timestamp": "2015-11-25T20:00:00Z", 63 } 64 if a != nil { 65 m["sign-key-sha3-384"] = a.SignKeyID() 66 } 67 return m 68 } 69 70 func exampleJSON(overrides map[string]interface{}) []byte { 71 m := expectedModelHeaders(nil) 72 for k, v := range overrides { 73 if v == nil { 74 delete(m, k) 75 } else { 76 m[k] = v 77 } 78 } 79 b, err := json.Marshal(m) 80 if err != nil { 81 panic(err) 82 } 83 return b 84 } 85 86 func (s *signSuite) TestSignJSON(c *C) { 87 opts := signtool.Options{ 88 KeyID: s.testKeyID, 89 90 Statement: exampleJSON(nil), 91 } 92 93 assertText, err := signtool.Sign(&opts, s.keypairMgr) 94 c.Assert(err, IsNil) 95 96 a, err := asserts.Decode(assertText) 97 c.Assert(err, IsNil) 98 99 c.Check(a.Type(), Equals, asserts.ModelType) 100 c.Check(a.Revision(), Equals, 0) 101 expectedHeaders := expectedModelHeaders(a) 102 c.Check(a.Headers(), DeepEquals, expectedHeaders) 103 104 for n, v := range a.Headers() { 105 c.Check(v, DeepEquals, expectedHeaders[n], Commentf(n)) 106 } 107 108 c.Check(a.Body(), IsNil) 109 } 110 111 func (s *signSuite) TestSignJSONWithBodyAndRevision(c *C) { 112 statement := exampleJSON(map[string]interface{}{ 113 "body": "BODY", 114 "revision": "11", 115 }) 116 opts := signtool.Options{ 117 KeyID: s.testKeyID, 118 119 Statement: statement, 120 } 121 122 assertText, err := signtool.Sign(&opts, s.keypairMgr) 123 c.Assert(err, IsNil) 124 125 a, err := asserts.Decode(assertText) 126 c.Assert(err, IsNil) 127 128 c.Check(a.Type(), Equals, asserts.ModelType) 129 c.Check(a.Revision(), Equals, 11) 130 131 expectedHeaders := expectedModelHeaders(a) 132 expectedHeaders["revision"] = "11" 133 expectedHeaders["body-length"] = "4" 134 135 c.Check(a.Headers(), DeepEquals, expectedHeaders) 136 137 c.Check(a.Body(), DeepEquals, []byte("BODY")) 138 } 139 140 func (s *signSuite) TestSignJSONWithBodyAndComplementRevision(c *C) { 141 statement := exampleJSON(map[string]interface{}{ 142 "body": "BODY", 143 }) 144 opts := signtool.Options{ 145 KeyID: s.testKeyID, 146 147 Statement: statement, 148 Complement: map[string]interface{}{ 149 "revision": "11", 150 }, 151 } 152 153 assertText, err := signtool.Sign(&opts, s.keypairMgr) 154 c.Assert(err, IsNil) 155 156 a, err := asserts.Decode(assertText) 157 c.Assert(err, IsNil) 158 159 c.Check(a.Type(), Equals, asserts.ModelType) 160 c.Check(a.Revision(), Equals, 11) 161 162 expectedHeaders := expectedModelHeaders(a) 163 expectedHeaders["revision"] = "11" 164 expectedHeaders["body-length"] = "4" 165 166 c.Check(a.Headers(), DeepEquals, expectedHeaders) 167 168 c.Check(a.Body(), DeepEquals, []byte("BODY")) 169 } 170 171 func (s *signSuite) TestSignJSONWithRevisionAndComplementBodyAndRepeatedType(c *C) { 172 statement := exampleJSON(map[string]interface{}{ 173 "revision": "11", 174 }) 175 opts := signtool.Options{ 176 KeyID: s.testKeyID, 177 178 Statement: statement, 179 Complement: map[string]interface{}{ 180 "type": "model", 181 "body": "BODY", 182 }, 183 } 184 185 assertText, err := signtool.Sign(&opts, s.keypairMgr) 186 c.Assert(err, IsNil) 187 188 a, err := asserts.Decode(assertText) 189 c.Assert(err, IsNil) 190 191 c.Check(a.Type(), Equals, asserts.ModelType) 192 c.Check(a.Revision(), Equals, 11) 193 194 expectedHeaders := expectedModelHeaders(a) 195 expectedHeaders["revision"] = "11" 196 expectedHeaders["body-length"] = "4" 197 198 c.Check(a.Headers(), DeepEquals, expectedHeaders) 199 200 c.Check(a.Body(), DeepEquals, []byte("BODY")) 201 } 202 203 func (s *signSuite) TestSignErrors(c *C) { 204 opts := signtool.Options{ 205 KeyID: s.testKeyID, 206 } 207 208 emptyList := []interface{}{} 209 210 tests := []struct { 211 expError string 212 brokenStatement []byte 213 complement map[string]interface{} 214 }{ 215 {`cannot parse the assertion input as JSON:.*`, 216 []byte("\x00"), 217 nil, 218 }, 219 {`invalid assertion type: what`, 220 exampleJSON(map[string]interface{}{"type": "what"}), 221 nil, 222 }, 223 {`assertion type must be a string, not: \[\]`, 224 exampleJSON(map[string]interface{}{"type": emptyList}), 225 nil, 226 }, 227 {`missing assertion type header`, 228 exampleJSON(map[string]interface{}{"type": nil}), 229 nil, 230 }, 231 {"revision should be positive: -10", 232 exampleJSON(map[string]interface{}{"revision": "-10"}), 233 nil, 234 }, 235 {`"authority-id" header is mandatory`, 236 exampleJSON(map[string]interface{}{"authority-id": nil}), 237 nil, 238 }, 239 {`body if specified must be a string`, 240 exampleJSON(map[string]interface{}{"body": emptyList}), 241 nil, 242 }, 243 {`repeated assertion type does not match`, 244 exampleJSON(nil), 245 map[string]interface{}{"type": "foo"}, 246 }, 247 {`complementary header "kernel" clashes with assertion input`, 248 exampleJSON(nil), 249 map[string]interface{}{"kernel": "foo"}, 250 }, 251 } 252 253 for _, t := range tests { 254 fresh := opts 255 256 fresh.Statement = t.brokenStatement 257 fresh.Complement = t.complement 258 259 _, err := signtool.Sign(&fresh, s.keypairMgr) 260 c.Check(err, ErrorMatches, t.expError) 261 } 262 }