go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/network/resources/openpgp.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package resources
     5  
     6  import (
     7  	"encoding/hex"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/ProtonMail/go-crypto/openpgp"
    12  	"github.com/ProtonMail/go-crypto/openpgp/packet"
    13  	"go.mondoo.com/cnquery/llx"
    14  	"go.mondoo.com/cnquery/providers-sdk/v1/plugin"
    15  )
    16  
    17  func (p *mqlOpenpgpEntities) list(content string) ([]interface{}, error) {
    18  	entries, err := openpgp.ReadArmoredKeyRing(strings.NewReader(content))
    19  	if err != nil {
    20  		return nil, err
    21  	}
    22  
    23  	res := []interface{}{}
    24  	// to create certificate resources
    25  	for i := range entries {
    26  		entity := entries[i]
    27  
    28  		if entity == nil {
    29  			continue
    30  		}
    31  
    32  		pubKey, err := newMqlOpenpgpPublicKey(p.MqlRuntime, entity.PrimaryKey)
    33  		if err != nil {
    34  			return nil, err
    35  		}
    36  
    37  		mqlCert, err := CreateResource(p.MqlRuntime, "openpgp.entity", map[string]*llx.RawData{
    38  			"primaryPublicKey": llx.ResourceData(pubKey, "openpgp.publicKey"),
    39  		})
    40  		if err != nil {
    41  			return nil, err
    42  		}
    43  
    44  		c := mqlCert.(*mqlOpenpgpEntity)
    45  		c._identities = entity.Identities
    46  		res = append(res, c)
    47  	}
    48  	return res, nil
    49  }
    50  
    51  func pgpAlgoString(algorithm packet.PublicKeyAlgorithm) string {
    52  	var pubKeyAlgo string
    53  
    54  	switch algorithm {
    55  	case packet.PubKeyAlgoRSA:
    56  		pubKeyAlgo = "rsa"
    57  	case packet.PubKeyAlgoRSAEncryptOnly:
    58  		pubKeyAlgo = "rsa_encrypt_only"
    59  	case packet.PubKeyAlgoRSASignOnly:
    60  		pubKeyAlgo = "rsa_sign_only"
    61  	case packet.PubKeyAlgoElGamal:
    62  		pubKeyAlgo = "elgamal"
    63  	case packet.PubKeyAlgoDSA:
    64  		pubKeyAlgo = "dsa"
    65  	case packet.PubKeyAlgoECDH:
    66  		pubKeyAlgo = "ecdh"
    67  	case packet.PubKeyAlgoECDSA:
    68  		pubKeyAlgo = "ecdsa"
    69  	case packet.PubKeyAlgoEdDSA:
    70  		pubKeyAlgo = "eddsa"
    71  	}
    72  
    73  	return pubKeyAlgo
    74  }
    75  
    76  func newMqlOpenpgpPublicKey(runtime *plugin.Runtime, publicKey *packet.PublicKey) (*mqlOpenpgpPublicKey, error) {
    77  	pubKeyAlgo := pgpAlgoString(publicKey.PubKeyAlgo)
    78  	// we ignore the error here since it happens only when no algorithm is found
    79  	bitlength, _ := publicKey.BitLength()
    80  
    81  	o, err := CreateResource(runtime, "openpgp.publicKey", map[string]*llx.RawData{
    82  		"id":           llx.StringData(publicKey.KeyIdString()),
    83  		"version":      llx.IntData(int64(publicKey.Version)),
    84  		"fingerprint":  llx.StringData(hex.EncodeToString(publicKey.Fingerprint)),
    85  		"keyAlgorithm": llx.StringData(pubKeyAlgo),
    86  		"bitLength":    llx.IntData(int64(bitlength)),
    87  		"creationTime": llx.TimeData(publicKey.CreationTime),
    88  	})
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	return o.(*mqlOpenpgpPublicKey), nil
    94  }
    95  
    96  type mqlOpenpgpEntityInternal struct {
    97  	_identities map[string]*openpgp.Identity
    98  }
    99  
   100  func (r *mqlOpenpgpEntity) id() (string, error) {
   101  	fp := r.PrimaryPublicKey.Data.GetFingerprint()
   102  	if fp.Error != nil {
   103  		return "", fp.Error
   104  	}
   105  	return "openpgp.entity/" + fp.Data, nil
   106  }
   107  
   108  func (r *mqlOpenpgpEntity) identities() ([]interface{}, error) {
   109  	fp := r.PrimaryPublicKey.Data.GetFingerprint()
   110  	if fp.Error != nil {
   111  		return nil, fp.Error
   112  	}
   113  
   114  	res := []interface{}{}
   115  	for k := range r._identities {
   116  		identity := r._identities[k]
   117  		o, err := CreateResource(r.MqlRuntime, "openpgp.identity", map[string]*llx.RawData{
   118  			"fingerprint": llx.StringData(fp.Data),
   119  			"id":          llx.StringData(identity.UserId.Id),
   120  			"name":        llx.StringData(identity.UserId.Name),
   121  			"email":       llx.StringData(identity.UserId.Email),
   122  			"comment":     llx.StringData(identity.UserId.Comment),
   123  		})
   124  		if err != nil {
   125  			return nil, err
   126  		}
   127  		cur := o.(*mqlOpenpgpIdentity)
   128  		cur._signatures = identity.Signatures
   129  
   130  		res = append(res, cur)
   131  	}
   132  
   133  	return res, nil
   134  }
   135  
   136  func (r *mqlOpenpgpPublicKey) id() (string, error) {
   137  	return "openpgp.publickey/" + r.Fingerprint.Data, nil
   138  }
   139  
   140  type mqlOpenpgpIdentityInternal struct {
   141  	_signatures []*packet.Signature
   142  }
   143  
   144  func (r *mqlOpenpgpIdentity) id() (string, error) {
   145  	return "openpgp.identity/" + r.Fingerprint.Data + "/" + r.Name.Data, nil
   146  }
   147  
   148  func (r *mqlOpenpgpIdentity) signatures() ([]interface{}, error) {
   149  	res := []interface{}{}
   150  	for k := range r._signatures {
   151  		signature := r._signatures[k]
   152  
   153  		var signatureType string
   154  		switch signature.SigType {
   155  		case packet.SigTypeBinary:
   156  			signatureType = "binary"
   157  		case packet.SigTypeText:
   158  			signatureType = "text"
   159  		case packet.SigTypeGenericCert:
   160  			signatureType = "generic_cert"
   161  		case packet.SigTypePersonaCert:
   162  			signatureType = "persona_cert"
   163  		case packet.SigTypeCasualCert:
   164  			signatureType = "casual_cert"
   165  		case packet.SigTypePositiveCert:
   166  			signatureType = "positive_cert"
   167  		case packet.SigTypeSubkeyBinding:
   168  			signatureType = "subkey_binding"
   169  		case packet.SigTypePrimaryKeyBinding:
   170  			signatureType = "primary_key_binding"
   171  		case packet.SigTypeDirectSignature:
   172  			signatureType = "direct_signature"
   173  		case packet.SigTypeKeyRevocation:
   174  			signatureType = "key_revocation"
   175  		case packet.SigTypeSubkeyRevocation:
   176  			signatureType = "subkey_revocation"
   177  		case packet.SigTypeCertificationRevocation:
   178  			signatureType = "cert_revocation"
   179  		}
   180  
   181  		lifetime := int64(-1)
   182  		var expirationTime *llx.RawData
   183  		if signature.SigLifetimeSecs != nil {
   184  			// NOTE: this can potentially overflow
   185  			lifetime = int64(*signature.SigLifetimeSecs)
   186  
   187  			expiry := signature.CreationTime.Add(time.Duration(*signature.SigLifetimeSecs) * time.Second)
   188  			diff := expiry.Unix() - time.Now().Unix()
   189  			ts := llx.DurationToTime(diff)
   190  			expirationTime = llx.TimeData(ts)
   191  		} else {
   192  			expirationTime = llx.NilData
   193  		}
   194  
   195  		keyLifetime := int64(-1)
   196  		var keyExpirationTime *llx.RawData
   197  		if signature.KeyLifetimeSecs != nil {
   198  			// NOTE: this can potentially overflow
   199  			keyLifetime = int64(*signature.KeyLifetimeSecs)
   200  
   201  			expiry := signature.CreationTime.Add(time.Duration(*signature.KeyLifetimeSecs) * time.Second)
   202  			diff := expiry.Unix() - time.Now().Unix()
   203  			ts := llx.DurationToTime(diff)
   204  			keyExpirationTime = llx.TimeData(ts)
   205  		} else {
   206  			expirationTime = llx.NilData
   207  		}
   208  
   209  		o, err := CreateResource(r.MqlRuntime, "openpgp.signature", map[string]*llx.RawData{
   210  			"fingerprint":     llx.StringData(r.Fingerprint.Data),
   211  			"identityName":    llx.StringData(r.Id.Data),
   212  			"hash":            llx.StringData(signature.Hash.String()),
   213  			"version":         llx.IntData(int64(signature.Version)),
   214  			"signatureType":   llx.StringData(signatureType),
   215  			"keyAlgorithm":    llx.StringData(pgpAlgoString(signature.PubKeyAlgo)),
   216  			"creationTime":    llx.TimeData(signature.CreationTime),
   217  			"lifetimeSecs":    llx.IntData(lifetime),
   218  			"expiresIn":       expirationTime,
   219  			"keyLifetimeSecs": llx.IntData(keyLifetime),
   220  			"keyExpiresIn":    keyExpirationTime,
   221  		})
   222  		if err != nil {
   223  			return nil, err
   224  		}
   225  		sig := o.(*mqlOpenpgpSignature)
   226  		res = append(res, sig)
   227  	}
   228  
   229  	return res, nil
   230  }
   231  
   232  func (r *mqlOpenpgpSignature) id() (string, error) {
   233  	return "openpgp.identity/" + r.Fingerprint.Data + "/" + r.IdentityName.Data + "/" + r.Hash.Data, nil
   234  }