...

Source file src/github.com/sassoftware/relic/signers/starman/signer.go

Documentation: github.com/sassoftware/relic/signers/starman

     1  //
     2  // Copyright (c) SAS Institute Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package starman
    18  
    19  // tarball format used by SAS
    20  
    21  import (
    22  	"archive/tar"
    23  	"bytes"
    24  	"fmt"
    25  	"io"
    26  	"time"
    27  
    28  	"golang.org/x/crypto/openpgp"
    29  	"golang.org/x/crypto/openpgp/armor"
    30  	"golang.org/x/crypto/openpgp/packet"
    31  
    32  	"github.com/sassoftware/relic/lib/binpatch"
    33  	"github.com/sassoftware/relic/lib/certloader"
    34  	"github.com/sassoftware/relic/lib/magic"
    35  	"github.com/sassoftware/relic/lib/pgptools"
    36  	"github.com/sassoftware/relic/signers"
    37  	"github.com/sassoftware/relic/signers/sigerrors"
    38  )
    39  
    40  var Signer = &signers.Signer{
    41  	Name:         "starman",
    42  	Magic:        magic.FileTypeStarman,
    43  	CertTypes:    signers.CertTypePgp,
    44  	Sign:         sign,
    45  	VerifyStream: verify,
    46  }
    47  
    48  func init() {
    49  	signers.Register(Signer)
    50  }
    51  
    52  func sign(r io.Reader, cert *certloader.Certificate, opts signers.SignOpts) ([]byte, error) {
    53  	info, err := verifyMeta(r)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	// sign metadata
    58  	var sigbuf bytes.Buffer
    59  	config := &packet.Config{
    60  		DefaultHash: opts.Hash,
    61  		Time:        func() time.Time { return opts.Time },
    62  	}
    63  	if err := openpgp.ArmoredDetachSign(&sigbuf, cert.PgpKey, bytes.NewReader(info.mdblob), config); err != nil {
    64  		return nil, err
    65  	}
    66  	// preserve the existing padding size so an in-place patch can be done
    67  	padding := len(info.sigblob) - sigbuf.Len()
    68  	if padding > 0 {
    69  		sigbuf.Write(make([]byte, padding))
    70  	}
    71  	// build a tar fragment to insert
    72  	var twbuf bytes.Buffer
    73  	tw := tar.NewWriter(&twbuf)
    74  	tw.WriteHeader(&tar.Header{
    75  		Name:     info.mdname + sigSuffix,
    76  		Mode:     0644,
    77  		Size:     int64(sigbuf.Len()),
    78  		Typeflag: tar.TypeReg,
    79  		Uname:    "root",
    80  		Gname:    "root",
    81  	})
    82  	tw.Write(sigbuf.Bytes())
    83  	tw.Flush()
    84  	// turn fragment into a binpatch
    85  	patch := binpatch.New()
    86  	patch.Add(info.sigStart, info.sigEnd-info.sigStart, twbuf.Bytes())
    87  	opts.Audit.Attributes["rpm.name"] = info.md.Name
    88  	opts.Audit.Attributes["rpm.epoch"] = info.md.Version.Epoch
    89  	opts.Audit.Attributes["rpm.version"] = info.md.Version.Version
    90  	opts.Audit.Attributes["rpm.release"] = info.md.Version.Release
    91  	opts.Audit.Attributes["rpm.arch"] = info.md.Arch
    92  	if epoch := info.md.Version.Epoch; epoch != "" && epoch != "0" {
    93  		opts.Audit.Attributes["rpm.nevra"] = fmt.Sprintf("%s-%s:%s-%s.%s", info.md.Name, epoch, info.md.Version.Version, info.md.Version.Release, info.md.Arch)
    94  	} else {
    95  		opts.Audit.Attributes["rpm.nevra"] = fmt.Sprintf("%s-%s-%s.%s", info.md.Name, info.md.Version.Version, info.md.Version.Release, info.md.Arch)
    96  	}
    97  	return opts.SetBinPatch(patch)
    98  }
    99  
   100  func verify(r io.Reader, opts signers.VerifyOpts) ([]*signers.Signature, error) {
   101  	info, err := verifyMeta(r)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	if !info.hasSig {
   106  		return nil, sigerrors.NotSignedError{Type: "TAR"}
   107  	}
   108  	block, err := armor.Decode(bytes.NewReader(info.sigblob))
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	sig, err := pgptools.VerifyDetached(block.Body, bytes.NewReader(info.mdblob), opts.TrustedPgp)
   113  	if err == nil {
   114  		return []*signers.Signature{&signers.Signature{
   115  			CreationTime: sig.CreationTime,
   116  			Hash:         sig.Hash,
   117  			SignerPgp:    sig.Key.Entity,
   118  		}}, nil
   119  	} else if sig != nil {
   120  		return nil, fmt.Errorf("bad signature from %s(%x) [%s]: %s", pgptools.EntityName(sig.Key.Entity), sig.Key.PublicKey.KeyId, sig.CreationTime, err)
   121  	}
   122  	return nil, err
   123  }
   124  

View as plain text