github.com/jlowellwofford/u-root@v1.0.0/cmds/gpgv/gpgv.go (about)

     1  // Copyright 2016-2017 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // gpgv validates a signature against a file.
     6  //
     7  // Synopsis:
     8  //     gpgv [-v] KEY SIG CONTENT
     9  //
    10  // Description:
    11  //     It prints "OK\n" to stdout if the check succeeds and exits with 0. It
    12  //     prints an error message and exits with non-0 otherwise.
    13  //
    14  //     The openpgp package ReadKeyRing function does not completely implement
    15  //     RFC4880 in that it can't use a PublicSigningKey with 0 signatures. We
    16  //     use one from Eric Grosse instead.
    17  //
    18  // Options:
    19  //     -v: verbose
    20  //
    21  // Author:
    22  //     grosse@gmail.com.
    23  package main
    24  
    25  import (
    26  	"crypto"
    27  	"flag"
    28  	"fmt"
    29  	"io"
    30  	"log"
    31  	"os"
    32  
    33  	"golang.org/x/crypto/openpgp/errors"
    34  	"golang.org/x/crypto/openpgp/packet"
    35  )
    36  
    37  var (
    38  	verbose bool
    39  	debug   = func(string, ...interface{}) {}
    40  )
    41  
    42  func main() {
    43  	flag.BoolVar(&verbose, "v", false, "verbose")
    44  	flag.Parse()
    45  	if verbose {
    46  		debug = log.Printf
    47  	}
    48  	if flag.NArg() != 3 {
    49  		log.Fatal("usage: boot-verify [-v] key sig content")
    50  	}
    51  
    52  	keyf, err := os.Open(flag.Args()[0])
    53  	if err != nil {
    54  		log.Fatal(err)
    55  	}
    56  	sigf, err := os.Open(flag.Args()[1])
    57  	if err != nil {
    58  		log.Fatal(err)
    59  	}
    60  	contentf, err := os.Open(flag.Args()[2])
    61  	if err != nil {
    62  		log.Fatal(err)
    63  	}
    64  
    65  	key, err := readPublicSigningKey(keyf)
    66  	if err != nil {
    67  		log.Fatal("key ", err)
    68  	}
    69  
    70  	if err = verifyDetachedSignature(key, contentf, sigf); err != nil {
    71  		log.Fatal("verify: ", err)
    72  	}
    73  	fmt.Printf("OK")
    74  }
    75  
    76  func readPublicSigningKey(keyf io.Reader) (*packet.PublicKey, error) {
    77  	keypackets := packet.NewReader(keyf)
    78  	p, err := keypackets.Next()
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	switch pkt := p.(type) {
    83  	case *packet.PublicKey:
    84  		debug("key: ", pkt)
    85  		return pkt, nil
    86  	default:
    87  		log.Printf("ReadPublicSigningKey: got %T, want *packet.PublicKey", pkt)
    88  	}
    89  	return nil, errors.StructuralError("expected first packet to be PublicKey")
    90  }
    91  
    92  func verifyDetachedSignature(key *packet.PublicKey, contentf, sigf io.Reader) error {
    93  	var hashFunc crypto.Hash
    94  
    95  	packets := packet.NewReader(sigf)
    96  	p, err := packets.Next()
    97  	if err != nil {
    98  		return err
    99  	}
   100  	switch sig := p.(type) {
   101  	case *packet.Signature:
   102  		hashFunc = sig.Hash
   103  	case *packet.SignatureV3:
   104  		hashFunc = sig.Hash
   105  	default:
   106  		return errors.UnsupportedError("unrecognized signature")
   107  	}
   108  
   109  	h := hashFunc.New()
   110  	if _, err := io.Copy(h, contentf); err != nil && err != io.EOF {
   111  		return err
   112  	}
   113  	switch sig := p.(type) {
   114  	case *packet.Signature:
   115  		err = key.VerifySignature(h, sig)
   116  	case *packet.SignatureV3:
   117  		err = key.VerifySignatureV3(h, sig)
   118  	default:
   119  		panic("unreachable")
   120  	}
   121  	return err
   122  }