github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/pgp_decrypt.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  	"fmt"
     8  	"io"
     9  
    10  	"github.com/keybase/client/go/libkb"
    11  	"github.com/keybase/client/go/protocol/keybase1"
    12  )
    13  
    14  type PGPDecryptArg struct {
    15  	Source       io.Reader
    16  	Sink         io.WriteCloser
    17  	AssertSigned bool
    18  	SignedBy     string
    19  }
    20  
    21  // PGPDecrypt decrypts data read from source into sink for the
    22  // logged in user.
    23  type PGPDecrypt struct {
    24  	libkb.Contextified
    25  	arg        *PGPDecryptArg
    26  	signStatus *libkb.SignatureStatus
    27  	signer     *libkb.User
    28  }
    29  
    30  // NewPGPDecrypt creates a PGPDecrypt engine.
    31  func NewPGPDecrypt(g *libkb.GlobalContext, arg *PGPDecryptArg) *PGPDecrypt {
    32  	return &PGPDecrypt{
    33  		arg:          arg,
    34  		Contextified: libkb.NewContextified(g),
    35  	}
    36  }
    37  
    38  // Name is the unique engine name.
    39  func (e *PGPDecrypt) Name() string {
    40  	return "PGPDecrypt"
    41  }
    42  
    43  // GetPrereqs returns the engine prereqs.
    44  func (e *PGPDecrypt) Prereqs() Prereqs {
    45  	return Prereqs{}
    46  }
    47  
    48  // RequiredUIs returns the required UIs.
    49  func (e *PGPDecrypt) RequiredUIs() []libkb.UIKind {
    50  	return []libkb.UIKind{libkb.SecretUIKind, libkb.LogUIKind, libkb.PgpUIKind}
    51  }
    52  
    53  // SubConsumers returns the other UI consumers for this engine.
    54  func (e *PGPDecrypt) SubConsumers() []libkb.UIConsumer {
    55  	return []libkb.UIConsumer{
    56  		&ScanKeys{},
    57  		&ResolveThenIdentify2{},
    58  	}
    59  }
    60  
    61  // Run starts the engine.
    62  func (e *PGPDecrypt) Run(m libkb.MetaContext) (err error) {
    63  	defer m.Trace("PGPDecrypt#Run", &err)()
    64  
    65  	m.Debug("| ScanKeys")
    66  	sk, err := NewScanKeys(m)
    67  	if err != nil {
    68  		return err
    69  	}
    70  	m.Debug("| PGPDecrypt")
    71  	e.signStatus, err = libkb.PGPDecrypt(m.G(), e.arg.Source, e.arg.Sink, sk)
    72  	if err != nil {
    73  		return err
    74  	}
    75  
    76  	m.Debug("| Sink Close")
    77  	if err = e.arg.Sink.Close(); err != nil {
    78  		return err
    79  	}
    80  
    81  	// get the owner of the signing key
    82  	e.signer = sk.KeyOwner(e.signStatus.KeyID)
    83  
    84  	if len(e.arg.SignedBy) > 0 {
    85  		e.arg.AssertSigned = true
    86  	}
    87  
    88  	if !e.signStatus.IsSigned {
    89  		if !e.arg.AssertSigned {
    90  			return nil
    91  		}
    92  		return libkb.BadSigError{E: "no signature in message"}
    93  	}
    94  	if !e.signStatus.Verified {
    95  		return e.signStatus.SignatureError
    96  	}
    97  
    98  	// message is signed and verified
    99  
   100  	// generate sha1 warnings for the key bundles
   101  	if e.signStatus.Entity != nil {
   102  		if warnings := libkb.NewPGPKeyBundle(e.signStatus.Entity).SecurityWarnings(
   103  			libkb.HashSecurityWarningSignersIdentityHash,
   104  		); warnings != nil {
   105  			e.signStatus.Warnings = append(e.signStatus.Warnings, warnings...)
   106  		}
   107  	}
   108  
   109  	if len(e.arg.SignedBy) > 0 {
   110  		if e.signer == nil {
   111  			return libkb.BadSigError{
   112  				E: fmt.Sprintf("Signer not a keybase user, cannot match signed by assertion %q", e.arg.SignedBy),
   113  			}
   114  		}
   115  
   116  		// identify the SignedBy assertion
   117  		arg := keybase1.Identify2Arg{
   118  			UserAssertion:    e.arg.SignedBy,
   119  			AlwaysBlock:      true,
   120  			NeedProofSet:     true,
   121  			NoSkipSelf:       true,
   122  			IdentifyBehavior: keybase1.TLFIdentifyBehavior_CLI,
   123  		}
   124  		eng := NewResolveThenIdentify2(m.G(), &arg)
   125  		if err := RunEngine2(m, eng); err != nil {
   126  			return err
   127  		}
   128  		res, err := eng.Result(m)
   129  		if err != nil {
   130  			return err
   131  		}
   132  		signByUser := res.Upk
   133  
   134  		if !signByUser.GetUID().Equal(e.signer.GetUID()) {
   135  			return libkb.BadSigError{
   136  				E: fmt.Sprintf("Signer %q did not match signed by assertion %q", e.signer.GetName(), e.arg.SignedBy),
   137  			}
   138  		}
   139  	} else {
   140  		if e.signer == nil {
   141  			// signer isn't a keybase user
   142  			m.Debug("message signed by key unknown to keybase: %X", e.signStatus.KeyID)
   143  			if err := OutputSignatureNonKeybase(m, e.signStatus.KeyID, e.signStatus.SignatureTime, e.signStatus.Warnings); err != nil {
   144  				return err
   145  			}
   146  			return libkb.BadSigError{
   147  				E: fmt.Sprintf("Message signed by an unknown key: %X", e.signStatus.KeyID),
   148  			}
   149  		}
   150  
   151  		// identify the signer
   152  		arg := keybase1.Identify2Arg{
   153  			UserAssertion:    e.signer.GetName(),
   154  			AlwaysBlock:      true,
   155  			NeedProofSet:     true,
   156  			NoSkipSelf:       true,
   157  			IdentifyBehavior: keybase1.TLFIdentifyBehavior_CLI,
   158  		}
   159  		eng := NewResolveThenIdentify2(m.G(), &arg)
   160  		if err := RunEngine2(m, eng); err != nil {
   161  			return err
   162  		}
   163  	}
   164  
   165  	if e.signStatus.Entity == nil {
   166  		return libkb.NoKeyError{Msg: fmt.Sprintf("In signature verification: no public key found for PGP ID %x", e.signStatus.KeyID)}
   167  	}
   168  
   169  	if entity := e.signStatus.Entity; len(entity.UnverifiedRevocations) > 0 {
   170  		return libkb.BadSigError{
   171  			E: fmt.Sprintf("Key %x belonging to %q has been revoked by its designated revoker.", entity.PrimaryKey.KeyId, e.signer.GetName()),
   172  		}
   173  	}
   174  
   175  	bundle := libkb.NewPGPKeyBundle(e.signStatus.Entity)
   176  	return OutputSignatureSuccess(m, bundle.GetFingerprint(), e.signer, e.signStatus.SignatureTime, e.signStatus.Warnings)
   177  }
   178  
   179  func (e *PGPDecrypt) SignatureStatus() *libkb.SignatureStatus {
   180  	return e.signStatus
   181  }
   182  
   183  func (e *PGPDecrypt) Signer() *libkb.User {
   184  	return e.signer
   185  }