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 }