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

     1  package libkb
     2  
     3  import (
     4  	"bytes"
     5  	"crypto"
     6  	"fmt"
     7  	"io"
     8  
     9  	"github.com/keybase/go-crypto/openpgp/armor"
    10  
    11  	"github.com/keybase/go-crypto/openpgp"
    12  	"github.com/keybase/go-crypto/openpgp/errors"
    13  	"github.com/keybase/go-crypto/openpgp/packet"
    14  )
    15  
    16  func ExtractPGPSignatureHashMethod(keyring openpgp.KeyRing, sig []byte) (crypto.Hash, uint64, error) {
    17  	var (
    18  		rd io.Reader
    19  
    20  		p                 packet.Packet
    21  		hashFunc          crypto.Hash
    22  		issuerFingerprint []byte
    23  		issuerKeyID       uint64
    24  		err               error
    25  	)
    26  
    27  	if IsArmored(sig) {
    28  		armored, err := armor.Decode(bytes.NewReader(sig))
    29  		if err != nil {
    30  			return 0, 0, err
    31  		}
    32  		rd = armored.Body
    33  	} else {
    34  		rd = bytes.NewReader(sig)
    35  	}
    36  
    37  	packets := packet.NewReader(rd)
    38  	for {
    39  		p, err = packets.Next()
    40  		if err == io.EOF {
    41  			if hashFunc != 0 {
    42  				return hashFunc, 0, nil
    43  			}
    44  
    45  			return 0, 0, errors.ErrUnknownIssuer
    46  		}
    47  		if err != nil {
    48  			return 0, 0, err
    49  		}
    50  
    51  		switch sig := p.(type) {
    52  		case *packet.Signature:
    53  			if sig.IssuerKeyId == nil {
    54  				return 0, 0, errors.StructuralError("signature doesn't have an issuer")
    55  			}
    56  			issuerKeyID = *sig.IssuerKeyId
    57  			hashFunc = sig.Hash
    58  			issuerFingerprint = sig.IssuerFingerprint
    59  		case *packet.SignatureV3:
    60  			issuerKeyID = sig.IssuerKeyId
    61  			hashFunc = sig.Hash
    62  		default:
    63  			return 0, 0, errors.StructuralError("non signature packet found")
    64  		}
    65  
    66  		if keyring != nil {
    67  			keys := keyring.KeysByIdUsage(issuerKeyID, issuerFingerprint, packet.KeyFlagSign)
    68  			if len(keys) > 0 {
    69  				return hashFunc, issuerKeyID, nil
    70  			}
    71  		}
    72  	}
    73  }
    74  
    75  var HashToName = map[crypto.Hash]string{
    76  	crypto.MD4:         "MD4",
    77  	crypto.MD5:         "MD5",
    78  	crypto.SHA1:        "SHA1",
    79  	crypto.SHA224:      "SHA2-224",
    80  	crypto.SHA256:      "SHA2-256",
    81  	crypto.SHA384:      "SHA2-384",
    82  	crypto.SHA512:      "SHA2-512",
    83  	crypto.RIPEMD160:   "RIPEMD-160",
    84  	crypto.SHA3_224:    "SHA3-224",
    85  	crypto.SHA3_256:    "SHA3-256",
    86  	crypto.SHA3_384:    "SHA3-384",
    87  	crypto.SHA3_512:    "SHA3-512",
    88  	crypto.SHA512_224:  "SHA2-512/224",
    89  	crypto.SHA512_256:  "SHA2-512/256",
    90  	crypto.BLAKE2s_256: "BLAKE2s-256",
    91  	crypto.BLAKE2b_256: "BLAKE2b-256",
    92  	crypto.BLAKE2b_384: "BLAKE2b-384",
    93  	crypto.BLAKE2b_512: "BLAKE2b-512",
    94  }
    95  
    96  func IsHashSecure(hash crypto.Hash) bool {
    97  	switch hash {
    98  	case crypto.SHA224,
    99  		crypto.SHA256,
   100  		crypto.SHA384,
   101  		crypto.SHA512,
   102  		crypto.SHA3_224,
   103  		crypto.SHA3_256,
   104  		crypto.SHA3_384,
   105  		crypto.SHA3_512,
   106  		crypto.SHA512_224,
   107  		crypto.SHA512_256,
   108  		crypto.BLAKE2s_256,
   109  		crypto.BLAKE2b_256,
   110  		crypto.BLAKE2b_384,
   111  		crypto.BLAKE2b_512:
   112  		return true
   113  	default:
   114  		return false
   115  	}
   116  }
   117  
   118  type HashSecurityWarningType uint8
   119  
   120  const (
   121  	HashSecurityWarningUnknown HashSecurityWarningType = iota
   122  	HashSecurityWarningSignatureHash
   123  	HashSecurityWarningSignersIdentityHash
   124  	HashSecurityWarningRecipientsIdentityHash
   125  	HashSecurityWarningOurIdentityHash
   126  )
   127  
   128  type HashSecurityWarning struct {
   129  	kind        HashSecurityWarningType
   130  	hash        crypto.Hash
   131  	fingerprint *PGPFingerprint
   132  }
   133  
   134  func NewHashSecurityWarning(kind HashSecurityWarningType, hash crypto.Hash, fp *PGPFingerprint) HashSecurityWarning {
   135  	return HashSecurityWarning{kind: kind, hash: hash, fingerprint: fp}
   136  }
   137  
   138  func (h HashSecurityWarning) String() string {
   139  	switch h.kind {
   140  	case HashSecurityWarningSignatureHash:
   141  		return fmt.Sprintf("Message was signed using an insecure hash scheme (%s)", HashToName[h.hash])
   142  	case HashSecurityWarningSignersIdentityHash:
   143  		return fmt.Sprintf("Signer's key %s uses an insecure hash scheme (%s)", h.fingerprint.String(), HashToName[h.hash])
   144  	case HashSecurityWarningRecipientsIdentityHash:
   145  		return fmt.Sprintf("Recipient's key %s uses an insecure hash scheme (%s)", h.fingerprint.String(), HashToName[h.hash])
   146  	case HashSecurityWarningOurIdentityHash:
   147  		return fmt.Sprintf("Our PGP key %s uses an insecure hash scheme (%s)", h.fingerprint.String(), HashToName[h.hash])
   148  	default:
   149  		return fmt.Sprintf("Hash security warning was passed an incorrect kind, got %d", h.kind)
   150  	}
   151  }
   152  
   153  type HashSecurityWarnings []HashSecurityWarning
   154  
   155  func (hs HashSecurityWarnings) Strings() (res []string) {
   156  	for _, h := range hs {
   157  		res = append(res, h.String())
   158  	}
   159  	return
   160  }