github.com/coreos/mantle@v0.13.0/update/signature/signature.go (about)

     1  // Copyright 2016 CoreOS, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package signature
    16  
    17  import (
    18  	"crypto"
    19  	"crypto/rand"
    20  	"crypto/rsa"
    21  	_ "crypto/sha256"
    22  	"crypto/x509"
    23  	"encoding/pem"
    24  	"fmt"
    25  	"hash"
    26  
    27  	"github.com/coreos/pkg/capnslog"
    28  	"github.com/golang/protobuf/proto"
    29  
    30  	"github.com/coreos/mantle/update/metadata"
    31  )
    32  
    33  const (
    34  	signatureVersion = 2
    35  	signatureHash    = crypto.SHA256
    36  	developerPubKey  = `
    37  -----BEGIN PUBLIC KEY-----
    38  MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzFS5uVJ+pgibcFLD3kbY
    39  k02Edj0HXq31ZT/Bva1sLp3Ysv+QTv/ezjf0gGFfASdgpz6G+zTipS9AIrQr0yFR
    40  +tdp1ZsHLGxVwvUoXFftdapqlyj8uQcWjjbN7qJsZu0Ett/qo93hQ5nHW7Sv5dRm
    41  /ZsDFqk2Uvyaoef4bF9r03wYpZq7K3oALZ2smETv+A5600mj1Xg5M52QFU67UHls
    42  EFkZphrGjiqiCdp9AAbAvE7a5rFcJf86YR73QX08K8BX7OMzkn3DsqdnWvLB3l3W
    43  6kvIuP+75SrMNeYAcU8PI1+bzLcAG3VN3jA78zeKALgynUNH50mxuiiU3DO4DZ+p
    44  5QIDAQAB
    45  -----END PUBLIC KEY-----`
    46  	developerSecKey = `
    47  -----BEGIN RSA PRIVATE KEY-----
    48  MIIEowIBAAKCAQEAzFS5uVJ+pgibcFLD3kbYk02Edj0HXq31ZT/Bva1sLp3Ysv+Q
    49  Tv/ezjf0gGFfASdgpz6G+zTipS9AIrQr0yFR+tdp1ZsHLGxVwvUoXFftdapqlyj8
    50  uQcWjjbN7qJsZu0Ett/qo93hQ5nHW7Sv5dRm/ZsDFqk2Uvyaoef4bF9r03wYpZq7
    51  K3oALZ2smETv+A5600mj1Xg5M52QFU67UHlsEFkZphrGjiqiCdp9AAbAvE7a5rFc
    52  Jf86YR73QX08K8BX7OMzkn3DsqdnWvLB3l3W6kvIuP+75SrMNeYAcU8PI1+bzLcA
    53  G3VN3jA78zeKALgynUNH50mxuiiU3DO4DZ+p5QIDAQABAoIBAH7ENbE+9+nkPyMx
    54  hekaBPVmSz7b3/2iaTNWmckmlY5aSX3LxejtH3rLBjq7rihWGMXJqg6hodcfeGfP
    55  Zb0H2AeKq1Nlac7qq05XsKGRv3WXs6dyO1BDkH/Minh5dk1o0NrwEm91kXLSLfe8
    56  IsCwxPCjwgfGFTjpFLpL4zjA/nFmWRyk2eyvs5VYRGKbbC83alUy7LutyRdZfw1b
    57  nwXldw2m8k/HPbGhaAqPpXTOjckIXZS5Dcp3smrOzwObZ6c3gQzg8upaRmxJVOmk
    58  cgCFTe0yUB2GMTEE3SUmuWJyZqECoyQtuiu0yT3igH8MZQpjg9NXm0eho/bXjN36
    59  frH+ikUCgYEA7VdCRcisnYWct29j+Bnaio9yXwwxhfoee53a4LQgjw5RLGUe1mXe
    60  j56oZ1Mak3Hh55sVQLNXZBuXHQqPsr7KkWXJXedDNFfq1u6by4LeJV0YYiDjjaCM
    61  T5G4Tcs7xhBWszLMCjhpJCrwHdGk3aa65UQ+angZlxhyziULCjpb5rMCgYEA3GUb
    62  VkqlVuNkHoogOMwg+h1jUSkwtWvP/z/FOXrKjivuwSgQ+i6PsildI3FL/WQtJxgd
    63  arB+l0L8TZJ6spFdNXwGmdCLqEcgEBYl11EojOXYLa7oLONI41iRQ3/nBBIqC38P
    64  Cs6CZQG/ZpKSoOzXE34BwcrOL99MA2oaVpGHuQcCgYA1IIk3Mbph8FyqOwb3rGHd
    65  Dksdt48GXHyiUy2BixCWtS+6blA+0cLGB0/PAS07wAw/WdmiCAMR55Ml7w1Hh6m0
    66  bkJrAK9schmhTvwUzBCJ8JLatF37f+qojQfichHJPjMKHd7KkuIGNI5XPmxXKVFA
    67  rMwD7SpdRh28w1H7UiDsPQKBgGebnFtXohyTr2hv9K/evo32LM9ltsFC2rga6YOZ
    68  BwoI+yeQx1JleyX9LgzQYTHQ2y0quAGE0S4YznVFLCswDQpssMm0cUL9lMQbNVTg
    69  kViTYKoxNHKNsqE17Kw3v4l5ZIydAZxJ8qC7TphQxV+jl4RRU1AgIAf/SEO+qH0T
    70  0yMXAoGBAN+y9QpGnGX6cgwLQQ7IC6MC+3NRed21s+KxHzpyF+Zh/q6NTLUSgp8H
    71  dBmeF4wAZTY+g/fdB9drYeaSdRs3SZsM7gMEvjspjYgE2rV/5gkncFyGKRAiNOR4
    72  bsy1Gm/UYLTc8+S3fq/xjg9RCjW9JMwavAwL6oVNNt7nyAXPfvSu
    73  -----END RSA PRIVATE KEY-----
    74  `
    75  )
    76  
    77  var (
    78  	plog = capnslog.NewPackageLogger("github.com/coreos/mantle", "update/signature")
    79  )
    80  
    81  func NewSignatureHash() hash.Hash {
    82  	return signatureHash.New()
    83  }
    84  
    85  func keySize() (int, error) {
    86  	pemBlock, _ := pem.Decode([]byte(developerPubKey))
    87  	if pemBlock == nil {
    88  		return 0, fmt.Errorf("unable to parse key")
    89  	}
    90  
    91  	somePub, err := x509.ParsePKIXPublicKey(pemBlock.Bytes)
    92  	if err != nil {
    93  		return 0, err
    94  	}
    95  
    96  	rsaPub, ok := somePub.(*rsa.PublicKey)
    97  	if !ok {
    98  		return 0, fmt.Errorf("unexpected key type %T", somePub)
    99  	}
   100  
   101  	// This is how the rsa package computes key length.
   102  	return (rsaPub.N.BitLen() + 7) / 8, nil
   103  }
   104  
   105  func SignaturesSize() (int, error) {
   106  	dataLen, err := keySize()
   107  	if err != nil {
   108  		return 0, err
   109  	}
   110  	data := make([]byte, dataLen)
   111  	sigs := &metadata.Signatures{
   112  		Signatures: []*metadata.Signatures_Signature{
   113  			&metadata.Signatures_Signature{
   114  				Version: proto.Uint32(signatureVersion),
   115  				Data:    data,
   116  			},
   117  		},
   118  	}
   119  	return proto.Size(sigs), nil
   120  }
   121  
   122  func Sign(sum []byte) (*metadata.Signatures, error) {
   123  	pemBlock, _ := pem.Decode([]byte(developerSecKey))
   124  	if pemBlock == nil {
   125  		return nil, fmt.Errorf("unable to parse key")
   126  	}
   127  
   128  	rsaKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	sig, err := rsa.SignPKCS1v15(rand.Reader, rsaKey, signatureHash, sum)
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  
   138  	return &metadata.Signatures{
   139  		Signatures: []*metadata.Signatures_Signature{
   140  			&metadata.Signatures_Signature{
   141  				Version: proto.Uint32(signatureVersion),
   142  				Data:    sig,
   143  			},
   144  		},
   145  	}, nil
   146  }
   147  
   148  func VerifySignature(sum []byte, sigs *metadata.Signatures) error {
   149  	pemBlock, _ := pem.Decode([]byte(developerPubKey))
   150  	if pemBlock == nil {
   151  		return fmt.Errorf("unable to parse key")
   152  	}
   153  
   154  	somePub, err := x509.ParsePKIXPublicKey(pemBlock.Bytes)
   155  	if err != nil {
   156  		return err
   157  	}
   158  
   159  	rsaPub, ok := somePub.(*rsa.PublicKey)
   160  	if !ok {
   161  		return fmt.Errorf("unexpected key type %T", somePub)
   162  	}
   163  
   164  	for _, sig := range sigs.Signatures {
   165  		v := sig.GetVersion()
   166  		if v != signatureVersion {
   167  			plog.Debugf("Skipping v%d signature", v)
   168  			continue
   169  		}
   170  
   171  		if err := rsa.VerifyPKCS1v15(rsaPub, signatureHash, sum, sig.Data); err != nil {
   172  			plog.Debugf("Cannot verify v%d signature with dev key", v)
   173  		} else {
   174  			plog.Infof("Good v%d signature by dev key", v)
   175  			return nil
   176  		}
   177  
   178  	}
   179  
   180  	return fmt.Errorf("no valid signatures found")
   181  }