From 5e460649b80159855f6000d5922e2f653d43b7b5 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Tue, 19 Mar 2024 12:32:41 +1030 Subject: [PATCH] x-pack/filebeat/input/{cel,httpjson}: fix PEM key validation Previously the validation was attempting to parse the PEM text as a key and was also attempting to parse the data as the wrong kind of key. --- CHANGELOG.next.asciidoc | 1 + x-pack/filebeat/input/cel/config_auth.go | 11 ++++- x-pack/filebeat/input/cel/config_okta_auth.go | 2 +- x-pack/filebeat/input/cel/config_test.go | 41 +++++++++++++++++++ x-pack/filebeat/input/httpjson/config_auth.go | 13 +++++- .../input/httpjson/config_okta_auth.go | 2 +- x-pack/filebeat/input/httpjson/config_test.go | 41 +++++++++++++++++++ 7 files changed, 106 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 1422424e423..1cd8999245b 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -102,6 +102,7 @@ fields added to events containing the Beats version. {pull}37553[37553] - Fix duplicated addition of regexp extension in CEL input. {pull}38181[38181] - Fix the incorrect values generated by the uri_parts processor. {pull}38216[38216] - Fix HTTPJSON handling of empty object bodies in POST requests. {issue}33961[33961] {pull}38290[38290] +- Fix PEM key validation for CEL and HTTPJSON inputs. {pull}38405[38405] *Heartbeat* diff --git a/x-pack/filebeat/input/cel/config_auth.go b/x-pack/filebeat/input/cel/config_auth.go index d6b35d633e6..9418c25df31 100644 --- a/x-pack/filebeat/input/cel/config_auth.go +++ b/x-pack/filebeat/input/cel/config_auth.go @@ -5,9 +5,11 @@ package cel import ( + "bytes" "context" "crypto/x509" "encoding/json" + "encoding/pem" "errors" "fmt" "io/fs" @@ -341,7 +343,14 @@ func (o *oAuth2Config) validateOktaProvider() error { } // jwk_pem if o.OktaJWKPEM != "" { - _, err := x509.ParsePKCS1PrivateKey([]byte(o.OktaJWKPEM)) + blk, rest := pem.Decode([]byte(o.OktaJWKPEM)) + if rest := bytes.TrimSpace(rest); len(rest) != 0 { + return fmt.Errorf("PEM text has trailing data: %s", rest) + } + _, err := x509.ParsePKCS8PrivateKey(blk.Bytes) + if err != nil { + return fmt.Errorf("okta validation error: %w", err) + } return err } // jwk_file diff --git a/x-pack/filebeat/input/cel/config_okta_auth.go b/x-pack/filebeat/input/cel/config_okta_auth.go index 74366afd3d5..a1ee2391aa4 100644 --- a/x-pack/filebeat/input/cel/config_okta_auth.go +++ b/x-pack/filebeat/input/cel/config_okta_auth.go @@ -182,7 +182,7 @@ func signJWT(cnf *oauth2.Config, key any) (string, error) { Expiration(now.Add(time.Hour)). Build() if err != nil { - return "", err + return "", fmt.Errorf("failed to create token: %w", err) } signedToken, err := jwt.Sign(tok, jwt.WithKey(jwa.RS256, key)) if err != nil { diff --git a/x-pack/filebeat/input/cel/config_test.go b/x-pack/filebeat/input/cel/config_test.go index 7acf74df08c..0a686df099c 100644 --- a/x-pack/filebeat/input/cel/config_test.go +++ b/x-pack/filebeat/input/cel/config_test.go @@ -539,6 +539,47 @@ var oAuth2ValidationTests = []struct { }, }, }, + { + name: "okta_successful_pem_oauth2_validation", + input: map[string]interface{}{ + "auth.oauth2": map[string]interface{}{ + "provider": "okta", + "client.id": "a_client_id", + "token_url": "localhost", + "scopes": []string{"foo"}, + "okta.jwk_pem": ` +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCOuef3HMRhohVT +5kSoAJgV+atpDjkwTwkOq+ImnbBlv75GaApG90w8VpjXjhqN/1KJmwfyrKiquiMq +OPu+o/672Dys5rUAaWSbT7wRF1GjLDDZrM0GHRdV4DGxM/LKI8I5yE1Mx3EzV+D5 +ZLmcRc5U4oEoMwtGpr0zRZ7uUr6a28UQwcUsVIPItc1/9rERlo1WTv8dcaj4ECC3 +2Sc0y/F+9XqwJvLd4Uv6ckzP0Sv4tbDA+7jpD9MneAIUiZ4LVj2cwbBd+YRY6jXx +MkevcCSmSX60clBY1cIFkw1DYHqtdHEwAQcQHLGMoi72xRP2qrdzIPsaTKVYoHVo +WA9vADdHAgMBAAECggEAIlx7jjCsztyYyeQsL05FTzUWoWo9NnYwtgmHnshkCXsK +MiUmJEOxZO1sSqj5l6oakupyFWigCspZYPbrFNCiqVK7+NxqQzkccY/WtT6p9uDS +ufUyPwCN96zMCd952lSVlBe3FH8Hr9a+YQxw60CbFjCZ67WuR0opTsi6JKJjJSDb +TQQZ4qJR97D05I1TgfmO+VO7G/0/dDaNHnnlYz0AnOgZPSyvrU2G5cYye4842EMB +ng81xjHD+xp55JNui/xYkhmYspYhrB2KlEjkKb08OInUjBeaLEAgA1r9yOHsfV/3 +DQzDPRO9iuqx5BfJhdIqUB1aifrye+sbxt9uMBtUgQKBgQDVdfO3GYT+ZycOQG9P +QtdMn6uiSddchVCGFpk331u6M6yafCKjI/MlJDl29B+8R5sVsttwo8/qnV/xd3cn +pY14HpKAsE4l6/Ciagzoj+0NqfPEDhEzbo8CyArcd7pSxt3XxECAfZe2+xivEPHe +gFO60vSFjFtvlLRMDMOmqX3kYQKBgQCrK1DISyQTnD6/axsgh2/ESOmT7n+JRMx/ +YzA7Lxu3zGzUC8/sRDa1C41t054nf5ZXJueYLDSc4kEAPddzISuCLxFiTD2FQ75P +lHWMgsEzQObDm4GPE9cdKOjoAvtAJwbvZcjDa029CDx7aCaDzbNvdmplZ7EUrznR +55U8Wsm8pwKBgBytxTmzZwfbCgdDJvFKNKzpwuCB9TpL+v6Y6Kr2Clfg+26iAPFU +MiWqUUInGGBuamqm5g6jI5sM28gQWeTsvC4IRXyes1Eq+uCHSQax15J/Y+3SSgNT +9kjUYYkvWMwoRcPobRYWSZze7XkP2L8hFJ7EGvAaZGqAWxzgliS9HtnhAoGAONZ/ +UqMw7Zoac/Ga5mhSwrj7ZvXxP6Gqzjofj+eKqrOlB5yMhIX6LJATfH6iq7cAMxxm +Fu/G4Ll4oB3o5wACtI3wldV/MDtYfJBtoCTjBqPsfNOsZ9hMvBATlsc2qwzKjsAb +tFhzTevoOYpSD75EcSS/G8Ec2iN9bagatBnpl00CgYBVqAOFZelNfP7dj//lpk8y +EUAw7ABOq0S9wkpFWTXIVPoBQUipm3iAUqGNPmvr/9ShdZC9xeu5AwKram4caMWJ +ExRhcDP1hFM6CdmSkIYEgBKvN9N0O4Lx1ba34gk74Hm65KXxokjJHOC0plO7c7ok +LNV/bIgMHOMoxiGrwyjAhg== +-----END PRIVATE KEY----- +`, + }, + }, + }, } func TestConfigOauth2Validation(t *testing.T) { diff --git a/x-pack/filebeat/input/httpjson/config_auth.go b/x-pack/filebeat/input/httpjson/config_auth.go index d05592dfa50..3f22e5131eb 100644 --- a/x-pack/filebeat/input/httpjson/config_auth.go +++ b/x-pack/filebeat/input/httpjson/config_auth.go @@ -5,9 +5,11 @@ package httpjson import ( + "bytes" "context" "crypto/x509" "encoding/json" + "encoding/pem" "errors" "fmt" "io/fs" @@ -309,8 +311,15 @@ func (o *oAuth2Config) validateOktaProvider() error { } // jwk_pem if o.OktaJWKPEM != "" { - _, err := x509.ParsePKCS1PrivateKey([]byte(o.OktaJWKPEM)) - return err + blk, rest := pem.Decode([]byte(o.OktaJWKPEM)) + if rest := bytes.TrimSpace(rest); len(rest) != 0 { + return fmt.Errorf("PEM text has trailing data: %s", rest) + } + _, err := x509.ParsePKCS8PrivateKey(blk.Bytes) + if err != nil { + return fmt.Errorf("okta validation error: %w", err) + } + return nil } // jwk_file if o.OktaJWKFile != "" { diff --git a/x-pack/filebeat/input/httpjson/config_okta_auth.go b/x-pack/filebeat/input/httpjson/config_okta_auth.go index c2b4289d9c9..9693ef389ab 100644 --- a/x-pack/filebeat/input/httpjson/config_okta_auth.go +++ b/x-pack/filebeat/input/httpjson/config_okta_auth.go @@ -179,7 +179,7 @@ func signJWT(cnf *oauth2.Config, key any) (string, error) { Expiration(now.Add(time.Hour)). Build() if err != nil { - return "", err + return "", fmt.Errorf("failed to create token: %w", err) } signedToken, err := jwt.Sign(tok, jwt.WithKey(jwa.RS256, key)) if err != nil { diff --git a/x-pack/filebeat/input/httpjson/config_test.go b/x-pack/filebeat/input/httpjson/config_test.go index d88c6ac4a62..910510b6e9c 100644 --- a/x-pack/filebeat/input/httpjson/config_test.go +++ b/x-pack/filebeat/input/httpjson/config_test.go @@ -499,6 +499,47 @@ func TestConfigOauth2Validation(t *testing.T) { }, }, }, + { + name: "okta successful pem oauth2 validation", + input: map[string]interface{}{ + "auth.oauth2": map[string]interface{}{ + "provider": "okta", + "client.id": "a_client_id", + "token_url": "localhost", + "scopes": []string{"foo"}, + "okta.jwk_pem": ` +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCOuef3HMRhohVT +5kSoAJgV+atpDjkwTwkOq+ImnbBlv75GaApG90w8VpjXjhqN/1KJmwfyrKiquiMq +OPu+o/672Dys5rUAaWSbT7wRF1GjLDDZrM0GHRdV4DGxM/LKI8I5yE1Mx3EzV+D5 +ZLmcRc5U4oEoMwtGpr0zRZ7uUr6a28UQwcUsVIPItc1/9rERlo1WTv8dcaj4ECC3 +2Sc0y/F+9XqwJvLd4Uv6ckzP0Sv4tbDA+7jpD9MneAIUiZ4LVj2cwbBd+YRY6jXx +MkevcCSmSX60clBY1cIFkw1DYHqtdHEwAQcQHLGMoi72xRP2qrdzIPsaTKVYoHVo +WA9vADdHAgMBAAECggEAIlx7jjCsztyYyeQsL05FTzUWoWo9NnYwtgmHnshkCXsK +MiUmJEOxZO1sSqj5l6oakupyFWigCspZYPbrFNCiqVK7+NxqQzkccY/WtT6p9uDS +ufUyPwCN96zMCd952lSVlBe3FH8Hr9a+YQxw60CbFjCZ67WuR0opTsi6JKJjJSDb +TQQZ4qJR97D05I1TgfmO+VO7G/0/dDaNHnnlYz0AnOgZPSyvrU2G5cYye4842EMB +ng81xjHD+xp55JNui/xYkhmYspYhrB2KlEjkKb08OInUjBeaLEAgA1r9yOHsfV/3 +DQzDPRO9iuqx5BfJhdIqUB1aifrye+sbxt9uMBtUgQKBgQDVdfO3GYT+ZycOQG9P +QtdMn6uiSddchVCGFpk331u6M6yafCKjI/MlJDl29B+8R5sVsttwo8/qnV/xd3cn +pY14HpKAsE4l6/Ciagzoj+0NqfPEDhEzbo8CyArcd7pSxt3XxECAfZe2+xivEPHe +gFO60vSFjFtvlLRMDMOmqX3kYQKBgQCrK1DISyQTnD6/axsgh2/ESOmT7n+JRMx/ +YzA7Lxu3zGzUC8/sRDa1C41t054nf5ZXJueYLDSc4kEAPddzISuCLxFiTD2FQ75P +lHWMgsEzQObDm4GPE9cdKOjoAvtAJwbvZcjDa029CDx7aCaDzbNvdmplZ7EUrznR +55U8Wsm8pwKBgBytxTmzZwfbCgdDJvFKNKzpwuCB9TpL+v6Y6Kr2Clfg+26iAPFU +MiWqUUInGGBuamqm5g6jI5sM28gQWeTsvC4IRXyes1Eq+uCHSQax15J/Y+3SSgNT +9kjUYYkvWMwoRcPobRYWSZze7XkP2L8hFJ7EGvAaZGqAWxzgliS9HtnhAoGAONZ/ +UqMw7Zoac/Ga5mhSwrj7ZvXxP6Gqzjofj+eKqrOlB5yMhIX6LJATfH6iq7cAMxxm +Fu/G4Ll4oB3o5wACtI3wldV/MDtYfJBtoCTjBqPsfNOsZ9hMvBATlsc2qwzKjsAb +tFhzTevoOYpSD75EcSS/G8Ec2iN9bagatBnpl00CgYBVqAOFZelNfP7dj//lpk8y +EUAw7ABOq0S9wkpFWTXIVPoBQUipm3iAUqGNPmvr/9ShdZC9xeu5AwKram4caMWJ +ExRhcDP1hFM6CdmSkIYEgBKvN9N0O4Lx1ba34gk74Hm65KXxokjJHOC0plO7c7ok +LNV/bIgMHOMoxiGrwyjAhg== +-----END PRIVATE KEY----- +`, + }, + }, + }, } for _, c := range cases {