github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/asserts/crypto.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2015-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  	"bytes"
    24  	"crypto"
    25  	"crypto/rand"
    26  	"crypto/rsa"
    27  
    28  	// be explicit about supporting SHA256
    29  	_ "crypto/sha256"
    30  
    31  	// be explicit about needing SHA512
    32  	_ "crypto/sha512"
    33  	"encoding/base64"
    34  	"fmt"
    35  	"io"
    36  	"time"
    37  
    38  	"golang.org/x/crypto/openpgp/packet"
    39  	"golang.org/x/crypto/sha3"
    40  )
    41  
    42  const (
    43  	maxEncodeLineLength = 76
    44  	v1                  = 0x1
    45  )
    46  
    47  var (
    48  	v1Header         = []byte{v1}
    49  	v1FixedTimestamp = time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC)
    50  )
    51  
    52  func encodeV1(data []byte) []byte {
    53  	buf := new(bytes.Buffer)
    54  	buf.Grow(base64.StdEncoding.EncodedLen(len(data) + 1))
    55  	enc := base64.NewEncoder(base64.StdEncoding, buf)
    56  	enc.Write(v1Header)
    57  	enc.Write(data)
    58  	enc.Close()
    59  	flat := buf.Bytes()
    60  	flatSize := len(flat)
    61  
    62  	buf = new(bytes.Buffer)
    63  	buf.Grow(flatSize + flatSize/maxEncodeLineLength + 1)
    64  	off := 0
    65  	for {
    66  		endOff := off + maxEncodeLineLength
    67  		if endOff > flatSize {
    68  			endOff = flatSize
    69  		}
    70  		buf.Write(flat[off:endOff])
    71  		off = endOff
    72  		if off >= flatSize {
    73  			break
    74  		}
    75  		buf.WriteByte('\n')
    76  	}
    77  
    78  	return buf.Bytes()
    79  }
    80  
    81  type keyEncoder interface {
    82  	keyEncode(w io.Writer) error
    83  }
    84  
    85  func encodeKey(key keyEncoder, kind string) ([]byte, error) {
    86  	buf := new(bytes.Buffer)
    87  	err := key.keyEncode(buf)
    88  	if err != nil {
    89  		return nil, fmt.Errorf("cannot encode %s: %v", kind, err)
    90  	}
    91  	return encodeV1(buf.Bytes()), nil
    92  }
    93  
    94  type openpgpSigner interface {
    95  	sign(content []byte) (*packet.Signature, error)
    96  }
    97  
    98  func signContent(content []byte, privateKey PrivateKey) ([]byte, error) {
    99  	signer, ok := privateKey.(openpgpSigner)
   100  	if !ok {
   101  		panic(fmt.Errorf("not an internally supported PrivateKey: %T", privateKey))
   102  	}
   103  
   104  	sig, err := signer.sign(content)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	buf := new(bytes.Buffer)
   110  	err = sig.Serialize(buf)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	return encodeV1(buf.Bytes()), nil
   116  }
   117  
   118  func decodeV1(b []byte, kind string) (packet.Packet, error) {
   119  	if len(b) == 0 {
   120  		return nil, fmt.Errorf("cannot decode %s: no data", kind)
   121  	}
   122  	buf := make([]byte, base64.StdEncoding.DecodedLen(len(b)))
   123  	n, err := base64.StdEncoding.Decode(buf, b)
   124  	if err != nil {
   125  		return nil, fmt.Errorf("cannot decode %s: %v", kind, err)
   126  	}
   127  	if n == 0 {
   128  		return nil, fmt.Errorf("cannot decode %s: base64 without data", kind)
   129  	}
   130  	buf = buf[:n]
   131  	if buf[0] != v1 {
   132  		return nil, fmt.Errorf("unsupported %s format version: %d", kind, buf[0])
   133  	}
   134  	rd := bytes.NewReader(buf[1:])
   135  	pkt, err := packet.Read(rd)
   136  	if err != nil {
   137  		return nil, fmt.Errorf("cannot decode %s: %v", kind, err)
   138  	}
   139  	if rd.Len() != 0 {
   140  		return nil, fmt.Errorf("%s has spurious trailing data", kind)
   141  	}
   142  	return pkt, nil
   143  }
   144  
   145  func decodeSignature(signature []byte) (*packet.Signature, error) {
   146  	pkt, err := decodeV1(signature, "signature")
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	sig, ok := pkt.(*packet.Signature)
   151  	if !ok {
   152  		return nil, fmt.Errorf("expected signature, got instead: %T", pkt)
   153  	}
   154  	return sig, nil
   155  }
   156  
   157  // PublicKey is the public part of a cryptographic private/public key pair.
   158  type PublicKey interface {
   159  	// ID returns the id of the key used for lookup.
   160  	ID() string
   161  
   162  	// verify verifies signature is valid for content using the key.
   163  	verify(content []byte, sig *packet.Signature) error
   164  
   165  	keyEncoder
   166  }
   167  
   168  type openpgpPubKey struct {
   169  	pubKey   *packet.PublicKey
   170  	sha3_384 string
   171  }
   172  
   173  func (opgPubKey *openpgpPubKey) ID() string {
   174  	return opgPubKey.sha3_384
   175  }
   176  
   177  func (opgPubKey *openpgpPubKey) verify(content []byte, sig *packet.Signature) error {
   178  	h := sig.Hash.New()
   179  	h.Write(content)
   180  	return opgPubKey.pubKey.VerifySignature(h, sig)
   181  }
   182  
   183  func (opgPubKey openpgpPubKey) keyEncode(w io.Writer) error {
   184  	return opgPubKey.pubKey.Serialize(w)
   185  }
   186  
   187  func newOpenPGPPubKey(intPubKey *packet.PublicKey) *openpgpPubKey {
   188  	h := sha3.New384()
   189  	h.Write(v1Header)
   190  	err := intPubKey.Serialize(h)
   191  	if err != nil {
   192  		panic("internal error: cannot compute public key sha3-384")
   193  	}
   194  	sha3_384, err := EncodeDigest(crypto.SHA3_384, h.Sum(nil))
   195  	if err != nil {
   196  		panic("internal error: cannot compute public key sha3-384")
   197  	}
   198  	return &openpgpPubKey{pubKey: intPubKey, sha3_384: sha3_384}
   199  }
   200  
   201  // RSAPublicKey returns a database useable public key out of rsa.PublicKey.
   202  func RSAPublicKey(pubKey *rsa.PublicKey) PublicKey {
   203  	intPubKey := packet.NewRSAPublicKey(v1FixedTimestamp, pubKey)
   204  	return newOpenPGPPubKey(intPubKey)
   205  }
   206  
   207  // DecodePublicKey deserializes a public key.
   208  func DecodePublicKey(pubKey []byte) (PublicKey, error) {
   209  	pkt, err := decodeV1(pubKey, "public key")
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  	pubk, ok := pkt.(*packet.PublicKey)
   214  	if !ok {
   215  		return nil, fmt.Errorf("expected public key, got instead: %T", pkt)
   216  	}
   217  	rsaPubKey, ok := pubk.PublicKey.(*rsa.PublicKey)
   218  	if !ok {
   219  		return nil, fmt.Errorf("expected RSA public key, got instead: %T", pubk.PublicKey)
   220  	}
   221  	return RSAPublicKey(rsaPubKey), nil
   222  }
   223  
   224  // EncodePublicKey serializes a public key, typically for embedding in an assertion.
   225  func EncodePublicKey(pubKey PublicKey) ([]byte, error) {
   226  	return encodeKey(pubKey, "public key")
   227  }
   228  
   229  // PrivateKey is a cryptographic private/public key pair.
   230  type PrivateKey interface {
   231  	// PublicKey returns the public part of the pair.
   232  	PublicKey() PublicKey
   233  
   234  	keyEncoder
   235  }
   236  
   237  type openpgpPrivateKey struct {
   238  	privk *packet.PrivateKey
   239  }
   240  
   241  func (opgPrivK openpgpPrivateKey) PublicKey() PublicKey {
   242  	return newOpenPGPPubKey(&opgPrivK.privk.PublicKey)
   243  }
   244  
   245  func (opgPrivK openpgpPrivateKey) keyEncode(w io.Writer) error {
   246  	return opgPrivK.privk.Serialize(w)
   247  }
   248  
   249  var openpgpConfig = &packet.Config{
   250  	DefaultHash: crypto.SHA512,
   251  }
   252  
   253  func (opgPrivK openpgpPrivateKey) sign(content []byte) (*packet.Signature, error) {
   254  	privk := opgPrivK.privk
   255  	sig := new(packet.Signature)
   256  	sig.PubKeyAlgo = privk.PubKeyAlgo
   257  	sig.Hash = openpgpConfig.Hash()
   258  	sig.CreationTime = time.Now()
   259  
   260  	h := openpgpConfig.Hash().New()
   261  	h.Write(content)
   262  
   263  	err := sig.Sign(h, privk, openpgpConfig)
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  
   268  	return sig, nil
   269  }
   270  
   271  func decodePrivateKey(privKey []byte) (PrivateKey, error) {
   272  	pkt, err := decodeV1(privKey, "private key")
   273  	if err != nil {
   274  		return nil, err
   275  	}
   276  	privk, ok := pkt.(*packet.PrivateKey)
   277  	if !ok {
   278  		return nil, fmt.Errorf("expected private key, got instead: %T", pkt)
   279  	}
   280  	if _, ok := privk.PrivateKey.(*rsa.PrivateKey); !ok {
   281  		return nil, fmt.Errorf("expected RSA private key, got instead: %T", privk.PrivateKey)
   282  	}
   283  	return openpgpPrivateKey{privk}, nil
   284  }
   285  
   286  // RSAPrivateKey returns a PrivateKey for database use out of a rsa.PrivateKey.
   287  func RSAPrivateKey(privk *rsa.PrivateKey) PrivateKey {
   288  	intPrivk := packet.NewRSAPrivateKey(v1FixedTimestamp, privk)
   289  	return openpgpPrivateKey{intPrivk}
   290  }
   291  
   292  // GenerateKey generates a private/public key pair.
   293  func GenerateKey() (PrivateKey, error) {
   294  	priv, err := rsa.GenerateKey(rand.Reader, 4096)
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  	return RSAPrivateKey(priv), nil
   299  }
   300  
   301  func encodePrivateKey(privKey PrivateKey) ([]byte, error) {
   302  	return encodeKey(privKey, "private key")
   303  }
   304  
   305  // externally held key pairs
   306  
   307  type extPGPPrivateKey struct {
   308  	pubKey     PublicKey
   309  	from       string
   310  	externalID string
   311  	bitLen     int
   312  	doSign     func(content []byte) (*packet.Signature, error)
   313  }
   314  
   315  func newExtPGPPrivateKey(exportedPubKeyStream io.Reader, from string, sign func(content []byte) (*packet.Signature, error)) (*extPGPPrivateKey, error) {
   316  	var pubKey *packet.PublicKey
   317  
   318  	rd := packet.NewReader(exportedPubKeyStream)
   319  	for {
   320  		pkt, err := rd.Next()
   321  		if err == io.EOF {
   322  			break
   323  		}
   324  		if err != nil {
   325  			return nil, fmt.Errorf("cannot read exported public key: %v", err)
   326  		}
   327  		cand, ok := pkt.(*packet.PublicKey)
   328  		if ok {
   329  			if cand.IsSubkey {
   330  				continue
   331  			}
   332  			if pubKey != nil {
   333  				return nil, fmt.Errorf("cannot select exported public key, found many")
   334  			}
   335  			pubKey = cand
   336  		}
   337  	}
   338  
   339  	if pubKey == nil {
   340  		return nil, fmt.Errorf("cannot read exported public key, found none (broken export)")
   341  
   342  	}
   343  
   344  	rsaPubKey, ok := pubKey.PublicKey.(*rsa.PublicKey)
   345  	if !ok {
   346  		return nil, fmt.Errorf("not a RSA key")
   347  	}
   348  
   349  	return &extPGPPrivateKey{
   350  		pubKey:     RSAPublicKey(rsaPubKey),
   351  		from:       from,
   352  		externalID: fmt.Sprintf("%X", pubKey.Fingerprint),
   353  		bitLen:     rsaPubKey.N.BitLen(),
   354  		doSign:     sign,
   355  	}, nil
   356  }
   357  
   358  func (expk *extPGPPrivateKey) PublicKey() PublicKey {
   359  	return expk.pubKey
   360  }
   361  
   362  func (expk *extPGPPrivateKey) keyEncode(w io.Writer) error {
   363  	return fmt.Errorf("cannot access external private key to encode it")
   364  }
   365  
   366  func (expk *extPGPPrivateKey) sign(content []byte) (*packet.Signature, error) {
   367  	if expk.bitLen < 4096 {
   368  		return nil, fmt.Errorf("signing needs at least a 4096 bits key, got %d", expk.bitLen)
   369  	}
   370  
   371  	sig, err := expk.doSign(content)
   372  	if err != nil {
   373  		return nil, err
   374  	}
   375  
   376  	badSig := fmt.Sprintf("bad %s produced signature: ", expk.from)
   377  
   378  	if sig.Hash != crypto.SHA512 {
   379  		return nil, fmt.Errorf(badSig + "expected SHA512 digest")
   380  	}
   381  
   382  	err = expk.pubKey.verify(content, sig)
   383  	if err != nil {
   384  		return nil, fmt.Errorf(badSig+"it does not verify: %v", err)
   385  	}
   386  
   387  	return sig, nil
   388  }