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