github.com/bugraaydogar/snapd@v0.0.0-20210315170335-8c70bb858939/asserts/serial_asserts.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 asserts
    21  
    22  import (
    23  	"fmt"
    24  	"time"
    25  
    26  	"github.com/snapcore/snapd/release"
    27  	"github.com/snapcore/snapd/strutil"
    28  )
    29  
    30  // Serial holds a serial assertion, which is a statement binding a
    31  // device identity with the device public key.
    32  type Serial struct {
    33  	assertionBase
    34  	timestamp time.Time
    35  	pubKey    PublicKey
    36  }
    37  
    38  // BrandID returns the brand identifier of the device.
    39  func (ser *Serial) BrandID() string {
    40  	return ser.HeaderString("brand-id")
    41  }
    42  
    43  // Model returns the model name identifier of the device.
    44  func (ser *Serial) Model() string {
    45  	return ser.HeaderString("model")
    46  }
    47  
    48  // Serial returns the serial identifier of the device, together with
    49  // brand id and model they form the unique identifier of the device.
    50  func (ser *Serial) Serial() string {
    51  	return ser.HeaderString("serial")
    52  }
    53  
    54  // DeviceKey returns the public key of the device.
    55  func (ser *Serial) DeviceKey() PublicKey {
    56  	return ser.pubKey
    57  }
    58  
    59  // Timestamp returns the time when the serial assertion was issued.
    60  func (ser *Serial) Timestamp() time.Time {
    61  	return ser.timestamp
    62  }
    63  
    64  func (ser *Serial) checkConsistency(db RODatabase, acck *AccountKey) error {
    65  	if ser.AuthorityID() != ser.BrandID() {
    66  		// serial authority and brand do not match, check the model
    67  		a, err := db.Find(ModelType, map[string]string{
    68  			"series":   release.Series,
    69  			"brand-id": ser.BrandID(),
    70  			"model":    ser.Model(),
    71  		})
    72  		if err != nil && !IsNotFound(err) {
    73  			return err
    74  		}
    75  		if IsNotFound(err) || !strutil.ListContains(a.(*Model).SerialAuthority(), ser.AuthorityID()) {
    76  			return fmt.Errorf("serial with authority %q different from brand %q without model assertion with serial-authority set to to allow for them", ser.AuthorityID(), ser.BrandID())
    77  		}
    78  	}
    79  	return nil
    80  }
    81  
    82  func assembleSerial(assert assertionBase) (Assertion, error) {
    83  	// brand-id and authority-id can diverge if the model allows
    84  	// for it via serial-authority, check for brand-id well-formedness
    85  	_, err := checkStringMatches(assert.headers, "brand-id", validAccountID)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	_, err = checkModel(assert.headers)
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  
    95  	encodedKey, err := checkNotEmptyString(assert.headers, "device-key")
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	pubKey, err := DecodePublicKey([]byte(encodedKey))
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	keyID, err := checkNotEmptyString(assert.headers, "device-key-sha3-384")
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	if keyID != pubKey.ID() {
   108  		return nil, fmt.Errorf("device key does not match provided key id")
   109  	}
   110  
   111  	timestamp, err := checkRFC3339Date(assert.headers, "timestamp")
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	// ignore extra headers and non-empty body for future compatibility
   117  	return &Serial{
   118  		assertionBase: assert,
   119  		timestamp:     timestamp,
   120  		pubKey:        pubKey,
   121  	}, nil
   122  }
   123  
   124  // SerialRequest holds a serial-request assertion, which is a self-signed request to obtain a full device identity bound to the device public key.
   125  type SerialRequest struct {
   126  	assertionBase
   127  	pubKey PublicKey
   128  }
   129  
   130  // BrandID returns the brand identifier of the device making the request.
   131  func (sreq *SerialRequest) BrandID() string {
   132  	return sreq.HeaderString("brand-id")
   133  }
   134  
   135  // Model returns the model name identifier of the device making the request.
   136  func (sreq *SerialRequest) Model() string {
   137  	return sreq.HeaderString("model")
   138  }
   139  
   140  // Serial returns the optional proposed serial identifier for the device, the service taking the request might use it or ignore it.
   141  func (sreq *SerialRequest) Serial() string {
   142  	return sreq.HeaderString("serial")
   143  }
   144  
   145  // RequestID returns the id for the request, obtained from and to be presented to the serial signing service.
   146  func (sreq *SerialRequest) RequestID() string {
   147  	return sreq.HeaderString("request-id")
   148  }
   149  
   150  // DeviceKey returns the public key of the device making the request.
   151  func (sreq *SerialRequest) DeviceKey() PublicKey {
   152  	return sreq.pubKey
   153  }
   154  
   155  func assembleSerialRequest(assert assertionBase) (Assertion, error) {
   156  	_, err := checkNotEmptyString(assert.headers, "brand-id")
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	_, err = checkModel(assert.headers)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  
   166  	_, err = checkNotEmptyString(assert.headers, "request-id")
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  
   171  	_, err = checkOptionalString(assert.headers, "serial")
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	encodedKey, err := checkNotEmptyString(assert.headers, "device-key")
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  	pubKey, err := DecodePublicKey([]byte(encodedKey))
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  
   185  	if pubKey.ID() != assert.SignKeyID() {
   186  		return nil, fmt.Errorf("device key does not match included signing key id")
   187  	}
   188  
   189  	// ignore extra headers and non-empty body for future compatibility
   190  	return &SerialRequest{
   191  		assertionBase: assert,
   192  		pubKey:        pubKey,
   193  	}, nil
   194  }
   195  
   196  // DeviceSessionRequest holds a device-session-request assertion, which is a request wrapping a store-provided nonce to start a session by a device signed with its key.
   197  type DeviceSessionRequest struct {
   198  	assertionBase
   199  	timestamp time.Time
   200  }
   201  
   202  // BrandID returns the brand identifier of the device making the request.
   203  func (req *DeviceSessionRequest) BrandID() string {
   204  	return req.HeaderString("brand-id")
   205  }
   206  
   207  // Model returns the model name identifier of the device making the request.
   208  func (req *DeviceSessionRequest) Model() string {
   209  	return req.HeaderString("model")
   210  }
   211  
   212  // Serial returns the serial identifier of the device making the request,
   213  // together with brand id and model it forms the unique identifier of
   214  // the device.
   215  func (req *DeviceSessionRequest) Serial() string {
   216  	return req.HeaderString("serial")
   217  }
   218  
   219  // Nonce returns the nonce obtained from store and to be presented when requesting a device session.
   220  func (req *DeviceSessionRequest) Nonce() string {
   221  	return req.HeaderString("nonce")
   222  }
   223  
   224  // Timestamp returns the time when the device-session-request was created.
   225  func (req *DeviceSessionRequest) Timestamp() time.Time {
   226  	return req.timestamp
   227  }
   228  
   229  func assembleDeviceSessionRequest(assert assertionBase) (Assertion, error) {
   230  	_, err := checkModel(assert.headers)
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  
   235  	_, err = checkNotEmptyString(assert.headers, "nonce")
   236  	if err != nil {
   237  		return nil, err
   238  	}
   239  
   240  	timestamp, err := checkRFC3339Date(assert.headers, "timestamp")
   241  	if err != nil {
   242  		return nil, err
   243  	}
   244  
   245  	// ignore extra headers and non-empty body for future compatibility
   246  	return &DeviceSessionRequest{
   247  		assertionBase: assert,
   248  		timestamp:     timestamp,
   249  	}, nil
   250  }