github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/pgp_verify.go (about)

     1  // Copyright 2015 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package engine
     5  
     6  import (
     7  	"bytes"
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  
    12  	"github.com/keybase/client/go/libkb"
    13  	"github.com/keybase/client/go/protocol/keybase1"
    14  	"github.com/keybase/go-crypto/openpgp"
    15  	"github.com/keybase/go-crypto/openpgp/armor"
    16  	"github.com/keybase/go-crypto/openpgp/clearsign"
    17  	"github.com/keybase/go-crypto/openpgp/packet"
    18  )
    19  
    20  type PGPVerifyArg struct {
    21  	Source    io.Reader
    22  	Signature []byte
    23  	SignedBy  string
    24  }
    25  
    26  // PGPVerify is an engine.
    27  type PGPVerify struct {
    28  	arg        *PGPVerifyArg
    29  	source     io.Reader
    30  	signStatus *libkb.SignatureStatus
    31  	signer     *libkb.User
    32  	libkb.Contextified
    33  }
    34  
    35  // NewPGPVerify creates a PGPVerify engine.
    36  func NewPGPVerify(g *libkb.GlobalContext, arg *PGPVerifyArg) *PGPVerify {
    37  	return &PGPVerify{
    38  		arg:          arg,
    39  		Contextified: libkb.NewContextified(g),
    40  	}
    41  }
    42  
    43  // Name is the unique engine name.
    44  func (e *PGPVerify) Name() string {
    45  	return "PGPVerify"
    46  }
    47  
    48  // GetPrereqs returns the engine prereqs.
    49  func (e *PGPVerify) Prereqs() Prereqs {
    50  	return Prereqs{}
    51  }
    52  
    53  // RequiredUIs returns the required UIs.
    54  func (e *PGPVerify) RequiredUIs() []libkb.UIKind {
    55  	return []libkb.UIKind{libkb.PgpUIKind}
    56  }
    57  
    58  // SubConsumers returns the other UI consumers for this engine.
    59  func (e *PGPVerify) SubConsumers() []libkb.UIConsumer {
    60  	return []libkb.UIConsumer{
    61  		&PGPDecrypt{},
    62  		&ScanKeys{},
    63  		&ResolveThenIdentify2{},
    64  	}
    65  }
    66  
    67  // Run starts the engine.
    68  func (e *PGPVerify) Run(m libkb.MetaContext) error {
    69  	var err error
    70  	defer m.Trace("PGPVerify#Run", &err)()
    71  	var sc libkb.StreamClassification
    72  	sc, e.source, err = libkb.ClassifyStream(e.arg.Source)
    73  
    74  	// For a Detached signature, we'll be expecting an UnknownStreamError
    75  	if err != nil {
    76  		if _, ok := err.(libkb.UnknownStreamError); !ok || len(e.arg.Signature) == 0 {
    77  			return err
    78  		}
    79  	}
    80  
    81  	if sc.Format == libkb.CryptoMessageFormatPGP && sc.Type == libkb.CryptoMessageTypeClearSignature {
    82  		err = e.runClearsign(m)
    83  		return err
    84  	}
    85  	if len(e.arg.Signature) == 0 {
    86  		err = e.runAttached(m)
    87  		return err
    88  	}
    89  	err = e.runDetached(m)
    90  	return err
    91  }
    92  
    93  func (e *PGPVerify) SignatureStatus() *libkb.SignatureStatus {
    94  	return e.signStatus
    95  }
    96  
    97  func (e *PGPVerify) Signer() *libkb.User {
    98  	return e.signer
    99  }
   100  
   101  // runAttached verifies an attached signature
   102  func (e *PGPVerify) runAttached(m libkb.MetaContext) error {
   103  	arg := &PGPDecryptArg{
   104  		Source:       e.source,
   105  		Sink:         libkb.NopWriteCloser{W: io.Discard},
   106  		AssertSigned: true,
   107  		SignedBy:     e.arg.SignedBy,
   108  	}
   109  	eng := NewPGPDecrypt(m.G(), arg)
   110  	if err := RunEngine2(m, eng); err != nil {
   111  		return err
   112  	}
   113  	e.signStatus = eng.SignatureStatus()
   114  	e.signer = eng.Signer()
   115  
   116  	return nil
   117  }
   118  
   119  // runDetached verifies a detached signature
   120  func (e *PGPVerify) runDetached(m libkb.MetaContext) error {
   121  	sk, err := NewScanKeys(m)
   122  	if err != nil {
   123  		return err
   124  	}
   125  	checkfn := openpgp.CheckDetachedSignature
   126  	if libkb.IsArmored(e.arg.Signature) {
   127  		checkfn = openpgp.CheckArmoredDetachedSignature
   128  	}
   129  	signer, err := checkfn(sk, e.source, bytes.NewReader(e.arg.Signature))
   130  	if err != nil {
   131  		return err
   132  	}
   133  	hashMethod, _, err := libkb.ExtractPGPSignatureHashMethod(sk, e.arg.Signature)
   134  	if err != nil {
   135  		return err
   136  	}
   137  
   138  	e.signer = sk.KeyOwnerByEntity(signer)
   139  	e.signStatus = &libkb.SignatureStatus{IsSigned: true}
   140  
   141  	if !libkb.IsHashSecure(hashMethod) {
   142  		e.signStatus.Warnings = append(
   143  			e.signStatus.Warnings,
   144  			libkb.NewHashSecurityWarning(
   145  				libkb.HashSecurityWarningSignatureHash,
   146  				hashMethod,
   147  				nil,
   148  			),
   149  		)
   150  	}
   151  
   152  	if signer != nil {
   153  		if len(signer.UnverifiedRevocations) > 0 {
   154  			return libkb.BadSigError{
   155  				E: fmt.Sprintf("Key %x belonging to %q has been revoked by its designated revoker.", signer.PrimaryKey.KeyId, e.signer.GetName()),
   156  			}
   157  		}
   158  
   159  		e.signStatus.Verified = true
   160  		e.signStatus.Entity = signer
   161  		if err := e.checkSignedBy(m); err != nil {
   162  			return err
   163  		}
   164  
   165  		var r io.Reader = bytes.NewReader(e.arg.Signature)
   166  		if libkb.IsArmored(e.arg.Signature) {
   167  			block, err := armor.Decode(r)
   168  			if err != nil {
   169  				return err
   170  			}
   171  			r = block.Body
   172  		}
   173  
   174  		p, err := packet.Read(r)
   175  		if err != nil {
   176  			return err
   177  		}
   178  
   179  		if val, ok := p.(*packet.Signature); ok {
   180  			e.signStatus.SignatureTime = val.CreationTime
   181  		} else if val, ok := p.(*packet.SignatureV3); ok {
   182  			e.signStatus.SignatureTime = val.CreationTime
   183  		}
   184  
   185  		if warnings := libkb.NewPGPKeyBundle(signer).SecurityWarnings(
   186  			libkb.HashSecurityWarningSignersIdentityHash,
   187  		); len(warnings) > 0 {
   188  			e.signStatus.Warnings = append(
   189  				e.signStatus.Warnings,
   190  				warnings...,
   191  			)
   192  		}
   193  
   194  		fingerprint := libkb.PGPFingerprint(signer.PrimaryKey.Fingerprint)
   195  		err = OutputSignatureSuccess(m, fingerprint, e.signer, e.signStatus.SignatureTime, e.signStatus.Warnings)
   196  		if err != nil {
   197  			return err
   198  		}
   199  	}
   200  
   201  	return nil
   202  }
   203  
   204  // runClearsign verifies a clearsign signature
   205  func (e *PGPVerify) runClearsign(m libkb.MetaContext) error {
   206  	// clearsign decode only works with the whole data slice, not a reader
   207  	// so have to read it all here:
   208  	msg, err := io.ReadAll(e.source)
   209  	if err != nil {
   210  		return err
   211  	}
   212  	b, _ := clearsign.Decode(msg)
   213  	if b == nil {
   214  		return errors.New("Unable to decode clearsigned message")
   215  	}
   216  
   217  	sigBody, err := io.ReadAll(b.ArmoredSignature.Body)
   218  	if err != nil {
   219  		return err
   220  	}
   221  
   222  	sk, err := NewScanKeys(m)
   223  	if err != nil {
   224  		return err
   225  	}
   226  
   227  	signer, err := openpgp.CheckDetachedSignature(sk, bytes.NewReader(b.Bytes), bytes.NewReader(sigBody))
   228  	if err != nil {
   229  		return fmt.Errorf("Check sig error: %s", err)
   230  	}
   231  	hashMethod, _, err := libkb.ExtractPGPSignatureHashMethod(sk, sigBody)
   232  	if err != nil {
   233  		return err
   234  	}
   235  
   236  	e.signer = sk.KeyOwnerByEntity(signer)
   237  	e.signStatus = &libkb.SignatureStatus{IsSigned: true}
   238  
   239  	if !libkb.IsHashSecure(hashMethod) {
   240  		e.signStatus.Warnings = append(
   241  			e.signStatus.Warnings,
   242  			libkb.NewHashSecurityWarning(
   243  				libkb.HashSecurityWarningSignatureHash,
   244  				hashMethod,
   245  				nil,
   246  			),
   247  		)
   248  	}
   249  
   250  	if signer != nil {
   251  		if len(signer.UnverifiedRevocations) > 0 {
   252  			return libkb.BadSigError{
   253  				E: fmt.Sprintf("Key %x belonging to %q has been revoked by its designated revoker.", signer.PrimaryKey.KeyId, e.signer.GetName()),
   254  			}
   255  		}
   256  
   257  		e.signStatus.Verified = true
   258  		e.signStatus.Entity = signer
   259  		if err := e.checkSignedBy(m); err != nil {
   260  			return err
   261  		}
   262  
   263  		p, err := packet.Read(bytes.NewReader(sigBody))
   264  		if err != nil {
   265  			return err
   266  		}
   267  
   268  		if val, ok := p.(*packet.Signature); ok {
   269  			e.signStatus.SignatureTime = val.CreationTime
   270  		} else if val, ok := p.(*packet.SignatureV3); ok {
   271  			e.signStatus.SignatureTime = val.CreationTime
   272  		}
   273  
   274  		if warnings := libkb.NewPGPKeyBundle(signer).SecurityWarnings(
   275  			libkb.HashSecurityWarningSignersIdentityHash,
   276  		); len(warnings) > 0 {
   277  			e.signStatus.Warnings = append(
   278  				e.signStatus.Warnings,
   279  				warnings...,
   280  			)
   281  		}
   282  
   283  		fingerprint := libkb.PGPFingerprint(signer.PrimaryKey.Fingerprint)
   284  		err = OutputSignatureSuccess(m, fingerprint, e.signer, e.signStatus.SignatureTime, e.signStatus.Warnings)
   285  		if err != nil {
   286  			return err
   287  		}
   288  	}
   289  
   290  	return nil
   291  }
   292  
   293  func (e *PGPVerify) checkSignedBy(m libkb.MetaContext) error {
   294  	if len(e.arg.SignedBy) == 0 {
   295  		// no assertion necessary
   296  		return nil
   297  	}
   298  	if !e.signStatus.Verified || e.signStatus.Entity == nil || e.signer == nil {
   299  		// signature not valid, so no need to assert
   300  		return nil
   301  	}
   302  
   303  	// have: a valid signature, the signature's owner, and a user assertion to
   304  	// match against
   305  	m.Debug("checking signed by assertion: %q", e.arg.SignedBy)
   306  
   307  	// load the user in SignedBy
   308  	arg := keybase1.Identify2Arg{
   309  		UserAssertion: e.arg.SignedBy,
   310  		AlwaysBlock:   true,
   311  		NeedProofSet:  true,
   312  		NoSkipSelf:    true,
   313  	}
   314  	eng := NewResolveThenIdentify2(e.G(), &arg)
   315  	if err := RunEngine2(m, eng); err != nil {
   316  		return err
   317  	}
   318  	res, err := eng.Result(m)
   319  	if err != nil {
   320  		return err
   321  	}
   322  	signByUser := res.Upk
   323  
   324  	// check if it is equal to signature owner
   325  	if !e.signer.GetUID().Equal(signByUser.GetUID()) {
   326  		return libkb.BadSigError{
   327  			E: fmt.Sprintf("Signer %q did not match signed by assertion %q", e.signer.GetName(), e.arg.SignedBy),
   328  		}
   329  	}
   330  	return nil
   331  }