github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/templates/signer/signer.go (about)

     1  package signer
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ecdsa"
     6  	"crypto/rand"
     7  	"crypto/sha256"
     8  	"crypto/x509"
     9  	"encoding/gob"
    10  	"encoding/pem"
    11  	"errors"
    12  	"fmt"
    13  	"os"
    14  
    15  	fileutil "github.com/projectdiscovery/utils/file"
    16  	"golang.org/x/crypto/ssh"
    17  )
    18  
    19  type Signer struct {
    20  	options       *Options
    21  	sshSigner     ssh.Signer
    22  	sshVerifier   ssh.PublicKey
    23  	ecdsaSigner   *ecdsa.PrivateKey
    24  	ecdsaVerifier *ecdsa.PublicKey
    25  }
    26  
    27  func New(options *Options) (*Signer, error) {
    28  	var (
    29  		privateKeyData, passphraseData, publicKeyData []byte
    30  		err                                           error
    31  	)
    32  	if options.PrivateKeyName != "" {
    33  		privateKeyData, err = readKeyFromFileOrEnv(options.PrivateKeyName)
    34  		if err != nil {
    35  			return nil, err
    36  		}
    37  	} else {
    38  		privateKeyData = options.PrivateKeyData
    39  	}
    40  
    41  	if options.PassphraseName != "" {
    42  		passphraseData = readKeyFromFileOrEnvWithDefault(options.PassphraseName, []byte{})
    43  	} else {
    44  		passphraseData = options.PassphraseData
    45  	}
    46  
    47  	if options.PublicKeyName != "" {
    48  		publicKeyData, err = readKeyFromFileOrEnv(options.PublicKeyName)
    49  		if err != nil {
    50  			return nil, err
    51  		}
    52  	} else {
    53  		publicKeyData = options.PublicKeyData
    54  	}
    55  
    56  	signer := &Signer{options: options}
    57  
    58  	switch signer.options.Algorithm {
    59  	case RSA:
    60  		signer.sshSigner, signer.sshVerifier, err = parseRsa(privateKeyData, publicKeyData, passphraseData)
    61  	case ECDSA:
    62  		signer.ecdsaSigner, signer.ecdsaVerifier, err = parseECDSA(privateKeyData, publicKeyData)
    63  	default:
    64  		return nil, ErrUnknownAlgorithm
    65  	}
    66  
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	return signer, nil
    72  }
    73  
    74  func NewVerifier(options *Options) (*Signer, error) {
    75  	var (
    76  		publicKeyData []byte
    77  		err           error
    78  	)
    79  	if options.PublicKeyName != "" {
    80  		publicKeyData, err = readKeyFromFileOrEnv(options.PrivateKeyName)
    81  		if err != nil {
    82  			return nil, err
    83  		}
    84  	} else {
    85  		publicKeyData = options.PublicKeyData
    86  	}
    87  
    88  	signer := &Signer{options: options}
    89  
    90  	switch signer.options.Algorithm {
    91  	case RSA:
    92  		signer.sshVerifier, err = parseRsaPublicKey(publicKeyData)
    93  	case ECDSA:
    94  		signer.ecdsaVerifier, err = parseECDSAPublicKey(publicKeyData)
    95  	default:
    96  		return nil, ErrUnknownAlgorithm
    97  	}
    98  
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	return signer, nil
   104  }
   105  
   106  func (s *Signer) Sign(data []byte) ([]byte, error) {
   107  	dataHash := sha256.Sum256(data)
   108  	switch s.options.Algorithm {
   109  	case RSA:
   110  		sshSignature, err := s.sshSigner.Sign(rand.Reader, dataHash[:])
   111  		if err != nil {
   112  			return nil, err
   113  		}
   114  		var signatureData bytes.Buffer
   115  		if err := gob.NewEncoder(&signatureData).Encode(sshSignature); err != nil {
   116  			return nil, err
   117  		}
   118  		return signatureData.Bytes(), nil
   119  	case ECDSA:
   120  		r, s, err := ecdsa.Sign(rand.Reader, s.ecdsaSigner, dataHash[:])
   121  		if err != nil {
   122  			return nil, err
   123  		}
   124  		ecdsaSignature := &EcdsaSignature{R: r, S: s}
   125  		var signatureData bytes.Buffer
   126  		if err := gob.NewEncoder(&signatureData).Encode(ecdsaSignature); err != nil {
   127  			return nil, err
   128  		}
   129  		return signatureData.Bytes(), nil
   130  	default:
   131  		return nil, ErrUnknownAlgorithm
   132  	}
   133  }
   134  
   135  func (s *Signer) Verify(data, signatureData []byte) (bool, error) {
   136  	dataHash := sha256.Sum256(data)
   137  	switch s.options.Algorithm {
   138  	case RSA:
   139  		signature := &ssh.Signature{}
   140  		if err := gob.NewDecoder(bytes.NewReader(signatureData)).Decode(&signature); err != nil {
   141  			return false, err
   142  		}
   143  		if err := s.sshVerifier.Verify(dataHash[:], signature); err != nil {
   144  			return false, err
   145  		}
   146  		return true, nil
   147  	case ECDSA:
   148  		signature := &EcdsaSignature{}
   149  		if err := gob.NewDecoder(bytes.NewReader(signatureData)).Decode(&signature); err != nil {
   150  			return false, err
   151  		}
   152  		return ecdsa.Verify(s.ecdsaVerifier, dataHash[:], signature.R, signature.S), nil
   153  	default:
   154  		return false, ErrUnknownAlgorithm
   155  	}
   156  }
   157  
   158  func parseRsa(privateKeyData, passphraseData, publicKeyData []byte) (ssh.Signer, ssh.PublicKey, error) {
   159  	privateKey, err := parseRsaPrivateKey(privateKeyData, passphraseData)
   160  	if err != nil {
   161  		return nil, nil, err
   162  	}
   163  
   164  	publicKey, err := parseRsaPublicKey(publicKeyData)
   165  	if err != nil {
   166  		return nil, nil, err
   167  	}
   168  
   169  	return privateKey, publicKey, nil
   170  }
   171  
   172  func parseRsaPrivateKey(privateKeyData, passphraseData []byte) (ssh.Signer, error) {
   173  	if len(passphraseData) > 0 {
   174  		return ssh.ParsePrivateKeyWithPassphrase(privateKeyData, passphraseData)
   175  	}
   176  	return ssh.ParsePrivateKey(privateKeyData)
   177  }
   178  
   179  func parseRsaPublicKey(publicKeyData []byte) (ssh.PublicKey, error) {
   180  	publicKey, _, _, _, err := ssh.ParseAuthorizedKey(publicKeyData)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  
   185  	return publicKey, nil
   186  }
   187  
   188  func parseECDSA(privateKeyData, publicKeyData []byte) (*ecdsa.PrivateKey, *ecdsa.PublicKey, error) {
   189  	privateKey, err := parseECDSAPrivateKey(privateKeyData)
   190  	if err != nil {
   191  		return nil, nil, err
   192  	}
   193  	publicKey, err := parseECDSAPublicKey(publicKeyData)
   194  	if err != nil {
   195  		return nil, nil, err
   196  	}
   197  	return privateKey, publicKey, nil
   198  }
   199  
   200  func parseECDSAPrivateKey(privateKeyData []byte) (*ecdsa.PrivateKey, error) {
   201  	blockPriv, _ := pem.Decode(privateKeyData)
   202  	return x509.ParseECPrivateKey(blockPriv.Bytes)
   203  }
   204  
   205  func parseECDSAPublicKey(publicKeyData []byte) (*ecdsa.PublicKey, error) {
   206  	blockPub, _ := pem.Decode(publicKeyData)
   207  	genericPublicKey, err := x509.ParsePKIXPublicKey(blockPub.Bytes)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  	if publicKey, ok := genericPublicKey.(*ecdsa.PublicKey); ok {
   212  		return publicKey, nil
   213  	}
   214  
   215  	return nil, errors.New("couldn't parse ecdsa public key")
   216  }
   217  
   218  func readKeyFromFileOrEnvWithDefault(keypath string, defaultValue []byte) []byte {
   219  	keyValue, err := readKeyFromFileOrEnv(keypath)
   220  	if err != nil {
   221  		return defaultValue
   222  	}
   223  	return keyValue
   224  }
   225  
   226  func readKeyFromFileOrEnv(keypath string) ([]byte, error) {
   227  	if fileutil.FileExists(keypath) {
   228  		return os.ReadFile(keypath)
   229  	}
   230  	if keydata := os.Getenv(keypath); keydata != "" {
   231  		return []byte(keydata), nil
   232  	}
   233  	return nil, fmt.Errorf("Private key not found in file or environment variable: %s", keypath)
   234  }