diff --git a/config.yaml b/config.yaml index bfa26e4d3..e60d3b6e4 100644 --- a/config.yaml +++ b/config.yaml @@ -72,26 +72,12 @@ # default_tenant_token: -# Private key type - used for JWT signing -# Defaults to: rsa -# Supported values: rsa, ed25519 -# Overwrite with environment variable: DEVICEAUTH_SERVER_PRIV_KEY_TYPE - -# server_priv_key_type: rsa - # Private key path - used for JWT signing # Defaults to: /etc/deviceauth/rsa/private.pem # Overwrite with environment variable: DEVICEAUTH_SERVER_PRIV_KEY_PATH # server_priv_key_path: /etc/deviceauth/rsa/private.pem -# Private key type - used for JWT signing -# Defaults to: rsa -# Supported values: rsa, ed25519 -# Overwrite with environment variable: DEVICEAUTH_SERVER_FALLBACK_PRIV_KEY_TYPE - -# server_fallback_priv_key_type: rsa - # Fallback private key path - used for JWT verification # Defaults to: none # Overwrite with environment variable: DEVICEAUTH_SERVER_FALLBACK_PRIV_KEY_PATH diff --git a/config/config.go b/config/config.go index ab1add06f..e057e2a30 100644 --- a/config/config.go +++ b/config/config.go @@ -52,17 +52,9 @@ const ( SettingDefaultTenantToken = "default_tenant_token" SettingDefaultTenantTokenDefault = "" - SettingServerPrivKeyType = "server_priv_key_type" - SettingServerPrivKeyTypeRSA = "rsa" - SettingServerPrivKeyTypeEd25519 = "ed25519" - SettingServerPrivKeyTypeDefault = SettingServerPrivKeyTypeRSA - SettingServerPrivKeyPath = "server_priv_key_path" SettingServerPrivKeyPathDefault = "/etc/deviceauth/rsa/private.pem" - SettingServerFallbackPrivKeyType = "server_fallback_priv_key_type" - SettingServerFallbackPrivKeyTypeDefault = SettingServerPrivKeyTypeRSA - SettingServerFallbackPrivKeyPath = "server_fallback_priv_key_path" SettingServerFallbackPrivKeyPathDefault = "" @@ -107,9 +99,7 @@ var ( {Key: SettingEnableReporting, Value: SettingEnableReportingDefault}, {Key: SettingTenantAdmAddr, Value: SettingTenantAdmAddrDefault}, {Key: SettingDefaultTenantToken, Value: SettingDefaultTenantTokenDefault}, - {Key: SettingServerPrivKeyType, Value: SettingServerPrivKeyTypeDefault}, {Key: SettingServerPrivKeyPath, Value: SettingServerPrivKeyPathDefault}, - {Key: SettingServerFallbackPrivKeyType, Value: SettingServerFallbackPrivKeyTypeDefault}, {Key: SettingServerFallbackPrivKeyPath, Value: SettingServerFallbackPrivKeyPathDefault}, {Key: SettingJWTIssuer, Value: SettingJWTIssuerDefault}, {Key: SettingJWTExpirationTimeout, Value: SettingJWTExpirationTimeoutDefault}, diff --git a/jwt/jwt.go b/jwt/jwt.go index 25412710a..f5340c629 100644 --- a/jwt/jwt.go +++ b/jwt/jwt.go @@ -14,6 +14,12 @@ package jwt import ( + "crypto/ed25519" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "os" + "github.com/pkg/errors" ) @@ -22,6 +28,11 @@ var ( ErrTokenInvalid = errors.New("jwt: token invalid") ) +const ( + pemHeaderPKCS1 = "RSA PRIVATE KEY" + pemHeaderPKCS8 = "PRIVATE KEY" +) + // Handler jwt generator/verifier // //go:generate ../utils/mockgen.sh @@ -37,3 +48,31 @@ type Handler interface { // ErrTokenInvalid when the token is invalid (malformed, missing required claims, etc.) Validate(string) error } + +func NewJWTHandler(privateKeyPath string) (Handler, error) { + priv, err := os.ReadFile(privateKeyPath) + block, _ := pem.Decode(priv) + if block == nil { + return nil, errors.Wrap(err, "failed to read private key") + } + switch block.Type { + case pemHeaderPKCS1: + privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, errors.Wrap(err, "failed to read rsa private key") + } + return NewJWTHandlerRS256(privKey), nil + case pemHeaderPKCS8: + key, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, errors.Wrap(err, "failed to read private key") + } + switch v := key.(type) { + case *rsa.PrivateKey: + return NewJWTHandlerRS256(v), nil + case ed25519.PrivateKey: + return NewJWTHandlerEd25519(&v), nil + } + } + return nil, errors.Errorf("unsupported server private key type") +} diff --git a/jwt/jwt_ed25519_test.go b/jwt/jwt_ed25519_test.go index 4e508c0c5..07a7428e8 100644 --- a/jwt/jwt_ed25519_test.go +++ b/jwt/jwt_ed25519_test.go @@ -15,6 +15,9 @@ package jwt import ( "crypto/ed25519" + "crypto/x509" + "encoding/pem" + "os" "testing" "time" @@ -22,8 +25,6 @@ import ( "github.com/mendersoftware/go-lib-micro/mongo/oid" "github.com/pkg/errors" "github.com/stretchr/testify/assert" - - "github.com/mendersoftware/deviceauth/keys" ) func TestNewJWTHandlerEd25519(t *testing.T) { @@ -281,12 +282,19 @@ func TestJWTHandlerEd25519Validate(t *testing.T) { } func loadEd25519PrivKey(path string, t *testing.T) *ed25519.PrivateKey { - key, err := keys.LoadEd25519Private(path) + pemData, err := os.ReadFile(path) if err != nil { t.Fatalf("failed to load key: %v", err) } - return key + block, _ := pem.Decode(pemData) + assert.Equal(t, block.Type, pemHeaderPKCS8) + + key, err := x509.ParsePKCS8PrivateKey(block.Bytes) + assert.NoError(t, err) + + retKey := key.(ed25519.PrivateKey) + return &retKey } func parseGeneratedTokenEd25519(t *testing.T, token string, key *ed25519.PrivateKey) *jwtgo.Token { diff --git a/jwt/jwt_rsa_test.go b/jwt/jwt_rsa_test.go index 94c2c063f..d2aedf529 100644 --- a/jwt/jwt_rsa_test.go +++ b/jwt/jwt_rsa_test.go @@ -15,6 +15,9 @@ package jwt import ( "crypto/rsa" + "crypto/x509" + "encoding/pem" + "os" "testing" "time" @@ -22,8 +25,6 @@ import ( "github.com/mendersoftware/go-lib-micro/mongo/oid" "github.com/pkg/errors" "github.com/stretchr/testify/assert" - - "github.com/mendersoftware/deviceauth/keys" ) func TestNewJWTHandlerRS256(t *testing.T) { @@ -306,11 +307,17 @@ func TestJWTHandlerRS256Validate(t *testing.T) { } func loadRSAPrivKey(path string, t *testing.T) *rsa.PrivateKey { - key, err := keys.LoadRSAPrivate(path) + pemData, err := os.ReadFile(path) if err != nil { t.Fatalf("failed to load key: %v", err) } + block, _ := pem.Decode(pemData) + assert.Equal(t, block.Type, pemHeaderPKCS1) + + key, err := x509.ParsePKCS1PrivateKey(block.Bytes) + assert.NoError(t, err) + return key } diff --git a/jwt/jwt_test.go b/jwt/jwt_test.go new file mode 100644 index 000000000..8fd60c58c --- /dev/null +++ b/jwt/jwt_test.go @@ -0,0 +1,57 @@ +// Copyright 2023 Northern.tech AS +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package jwt + +import ( + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" +) + +func TestNewJWTHandler(t *testing.T) { + testCases := map[string]struct { + privateKeyPath string + err error + }{ + "ok, pkcs1, rsa": { + privateKeyPath: "./testdata/rsa.pem", + }, + "ok, pkcs8, rsa": { + privateKeyPath: "./testdata/rsa_pkcs8.pem", + }, + "ok, pkcs8, ed25519": { + privateKeyPath: "./testdata/ed25519.pem", + }, + "ko": { + privateKeyPath: "./testdata/doesnotexist.pem", + err: errors.New("failed to read private key: open ./testdata/doesnotexist.pem: no such file or directory"), + }, + "unknown priate key type": { + privateKeyPath: "./testdata/dsa.pem", + err: errors.New("unsupported server private key type"), + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + _, err := NewJWTHandler(tc.privateKeyPath) + if tc.err != nil { + assert.EqualError(t, err, tc.err.Error()) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/jwt/testdata/dsa.pem b/jwt/testdata/dsa.pem new file mode 100644 index 000000000..363dd17ce --- /dev/null +++ b/jwt/testdata/dsa.pem @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBvAIBAAKBgQDaqdgwD3YvYwgbWzs8RQQOm8RmPztSYMUrcM7KQtdJ111sTZ/x +VAq84frCt/TEupAN5hUFkC+bpJ/diZixQgPvLKo6FVtBKy97HSpuZT8n2pUYZ9/4 +sBTR5YQtP9qExXUYO/yR+fZ+RE9w0TbSAtHW2YZHKnoowJAHdoEGMbaChQIVAK/q +iXNHCha4xHnIdD2jT0OUs03fAoGBAMnCeTgO09r2GquRAQmGFAT/6IGMhux7KOC8 +QrW7jDaqAYLiuA45E3Ira584RF2rg0VhewxcdEMbqNzqCeSKk9OAmwXpJ1J8vCUR +dRojGz0DYZHJbcspoGtZF1IF6Z3BoaggRcLX6/KYLbnzFZnBXV/+//gRTbm/V2ie +BzCWE/qEAoGBANbrGxzVTTdTD8MaVtlOpjU3RqoGFHmFCd4lv0PIt2mjFsXO3Dt/ +6BMtJVREtb74WF0SUGmnpy6FTYoDb05j2LhH1IvCSkFT5hUK0WtAJ3NidJ6ARxxD +z2QITWI1FTr1K9NbZdR6DoTxeKfV6wWbuLywlwoWYmLe6oAmq21Oft4XAhRcKcLk +r2R/Rn1uchUL8ru0B2OVkg== +-----END DSA PRIVATE KEY----- diff --git a/jwt/testdata/rsa_pkcs8.pem b/jwt/testdata/rsa_pkcs8.pem new file mode 100644 index 000000000..ba0d407a4 --- /dev/null +++ b/jwt/testdata/rsa_pkcs8.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCc8AY24055iFqf +ozlNDkK9BvpPw2McT/lJWJia2vhy7CnXMKZDEuQEmma0WFbpxLcUsD+uh/18OCjw +k3kl1eT11tuF7n0zKebq0OD4tbLWSh5Zww7cziDErCgkL+DRoCeHjwwKdOMaxpPs +BPe6V1oR537Ay4Bgze0nleFm0BPBsNxtpn/AG9BPVjZthK0A8lLYKOE0aOsg35gt +NVQYZjnE+2O9WVBxblFPYu+1E7NQ0iqFi9jH7ood+mU6FWoHoxF7XBkSLAIiYhVt +oy3I+3aueW2etr01Jd5YdcsKCmL3UnrxhFnZF8dbWxoGy0dmGIQQVJANH4hp+NXo +mrQD2/LVAgMBAAECggEAF7A6O+g5FOqiRTThxhIIPFiUiVwkdmZS6kGLfVpehJhF +o4PmILs1/ETjCkdITS5idSa6YgmIV0rx0Qhtkaq0ze/RwGhUcRfa0WhYgOoKNcLH +zIQ/FtCtTQpwX6/zZyjdtp4+sshcbFL7inVggDnFsGypKwg8l0AWEzLSLE7toH9p +LP47HAJ9WWFyZ3BzibUjLEiMlK/w8UTDAv5IUT3dkSEe6ztTAwbZoZ3r+CJyhDUA +U7VvJQwhh/vXTBiOw75PKFykz1Bp2P5ZuGW21DVYhRQcyq9NegPhTepHt/cSQysC +y51J9mIFrp2M4oTBpMw694N9Ozk3kVZRoeiUzl4m8QKBgQDb69bc2I8qO6OTrHK7 +/Xw/9Wghts/R+GdnSLpzIeZI1zUQvR1LvJDRxOfY+kFw+94tADOa66vPBYTn2F4E +Mo0CZNIEnkdyUvUy0MFoefbNBhHAHo9arilTq1DbCG81Di+GP7iRyo+3y01stTqz +TsPGuvk2ywcNALd1ZBUMgODUpQKBgQC2rwYaKTHr0Tu3EMfZ1bw4smEuUtbSis9v +K3iS8AMr1e3QaDqQGARiME+iz3zcijYXKVARVhj8ebiu8qKdPNbJqDq+bRFmLhkT +10XTT6XRPCnOBcotk9HTrezIj4Fb+1XSV/SXJdRN/eqB9pp6unzJZkuxLRIGNFex +HIdlRqvecQKBgAx60qOPqngkEEFGDPC8Drv2aiVXoW1x4jRLPUFhUBccF0fO44Wz +uqgcu2dltCb8M/xrwYHuE77YulUJwzQLxlK3c++NJ9LGAGIU1JTgLvAtgv5a/ZmQ +vomf9COp092341yD6y5ix0sPv2IG2sDoHFX/sDq6xLipLL/9oPAntBp9AoGAMo0W +HDEgDkg0xQCQvNenIO1DdQUZSuN8aR/XWpmt1vh4uT3OTsdGl0EVGFFgFMruEtSs +wk9X1K1+DHM5ylbmfKDfuIgH04WYDOR5/vJASTjjvI3fl2MbIf8z0X/cZO6UngMW +vKiMKhTESrhJoQJvu29iLKHzJeJgDbN+R+kZcBECgYBfMy025YhOJArPtmzFrHuN +IwVasR+3iuDTr7WMIR130vAvY12PaYR5+NbMt1mNkV9O+MZtKCdCvphCtf/kEpXv +v9cqQKUxh/YrI0nvysc7GoQWtZKYip9xa0kjVyhLeZ8Xs7M1CXok4rXcDxCQPPbz +ugFPykXGUqka4p+VEoEKgw== +-----END PRIVATE KEY----- diff --git a/keys/key.go b/keys/key.go deleted file mode 100644 index 970cd946b..000000000 --- a/keys/key.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2023 Northern.tech AS -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -package keys - -import ( - "crypto/ed25519" - "crypto/rsa" - "os" - - "github.com/golang-jwt/jwt/v4" - "github.com/pkg/errors" -) - -const ( - ErrMsgPrivKeyReadFailed = "failed to read server private key file" -) - -func LoadRSAPrivate(privKeyPath string) (*rsa.PrivateKey, error) { - pemData, err := os.ReadFile(privKeyPath) - if err != nil { - return nil, errors.Wrap(err, ErrMsgPrivKeyReadFailed) - } - return jwt.ParseRSAPrivateKeyFromPEM(pemData) -} - -func LoadEd25519Private(privKeyPath string) (*ed25519.PrivateKey, error) { - pemData, err := os.ReadFile(privKeyPath) - if err != nil { - return nil, errors.Wrap(err, ErrMsgPrivKeyReadFailed) - } - private, err := jwt.ParseEdPrivateKeyFromPEM(pemData) - if err != nil { - return nil, err - } - // safe, already asserted by `jwt.ParseEdPrivateKeyFromPEM` - key := private.(ed25519.PrivateKey) - return &key, nil -} diff --git a/keys/key_test.go b/keys/key_test.go deleted file mode 100644 index 08361593c..000000000 --- a/keys/key_test.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2023 Northern.tech AS -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -package keys - -import ( - "fmt" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestLoadRsaPrivateKey(t *testing.T) { - t.Parallel() - - testCases := []struct { - PrivateKey string - Error string - }{ - { - PrivateKey: PrivateKeyRSAPKCS1, - Error: "", - }, - { - PrivateKey: PrivateKeyRSA, - Error: "", - }, - { - PrivateKey: PrivateKeyECDSAP521, - Error: "key is not a valid RSA private key", - }, - { - PrivateKey: "randomGarbage", - Error: "Key must be a PEM encoded PKCS1 or PKCS8 key", - }, - { - PrivateKey: `-----BEGIN PRIVATE KEY----- -randomPKCS8Garba ------END PRIVATE KEY-----`, - Error: "asn1: structure error: length too large", - }, - { - PrivateKey: PublicKeyECDSAP521, - Error: "asn1: structure error: tags don't match", - }, - } - - for i := range testCases { - tc := testCases[i] - t.Run(fmt.Sprintf("tc %d", i), func(t *testing.T) { - t.Parallel() - - fd, err := os.CreateTemp(t.TempDir(), "private*.pem") - if err != nil { - panic(err) - } - _, err = fd.Write([]byte(tc.PrivateKey)) - fd.Close() - if err != nil { - panic(err) - } - - key, err := LoadRSAPrivate(fd.Name()) - if tc.Error != "" { - assert.ErrorContains(t, err, tc.Error) - } else { - assert.NoError(t, err) - assert.NotNil(t, key) - } - }) - } - - t.Run("error/file not exist", func(t *testing.T) { - path := filepath.Join(t.TempDir(), "not-exist.pem") - _, err := LoadRSAPrivate(path) - var expected *os.PathError - assert.ErrorAs(t, err, &expected) - }) -} - -func TestLoadEd25519Private(t *testing.T) { - t.Parallel() - - testCases := []struct { - PrivateKey string - Error string - }{ - { - PrivateKey: PrivateKeyEd25519, - Error: "", - }, - { - PrivateKey: PrivateKeyEdDSA, - Error: "x509: failed to parse private key (use ParseECPrivateKey instead for this key format)", - }, - { - PrivateKey: "randomGarbage", - Error: "Key must be a PEM encoded PKCS1 or PKCS8 key", - }, - { - PrivateKey: `-----BEGIN PRIVATE KEY----- -randomPKCS8Garba ------END PRIVATE KEY-----`, - Error: "asn1: structure error: length too large", - }, - { - PrivateKey: PublicKeyECDSAP521, - Error: "asn1: structure error: tags don't match", - }, - } - - for i := range testCases { - tc := testCases[i] - t.Run(fmt.Sprintf("tc %d", i), func(t *testing.T) { - t.Parallel() - - fd, err := os.CreateTemp(t.TempDir(), "private*.pem") - if err != nil { - panic(err) - } - _, err = fd.Write([]byte(tc.PrivateKey)) - fd.Close() - if err != nil { - panic(err) - } - - key, err := LoadEd25519Private(fd.Name()) - if tc.Error != "" { - assert.ErrorContains(t, err, tc.Error) - } else { - assert.NoError(t, err) - assert.NotNil(t, key) - } - }) - } - - t.Run("error/file not exist", func(t *testing.T) { - path := filepath.Join(t.TempDir(), "not-exist.pem") - _, err := LoadEd25519Private(path) - var expected *os.PathError - assert.ErrorAs(t, err, &expected) - }) -} - -const ( - PrivateKeyECDSAP521 = `-----BEGIN PRIVATE KEY----- -MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIBb5dG63AsYEDyDzz2 -8NxEY/K2X4zqpQ2RkCbwn3vsXHsFDWQMQjT6+hFs1aPoHquYcYXi4q9TJwHwcXzp -4J6J/uGhgYkDgYYABABjebTZZu6l6Orhb6NKwQ1YsIsgTg5BFJXuBRnApl0cm7hq -4lP9yH3qsW+okIs+r3YktApw45js5T0JWEqhGX021QGaZtw2ezL7PROkWV5A/ihc -VmpBmV0lMDAStu+Vlj9g5oM8TphpTXF24VXDk8O8+Swwq+Sp1mpRjWI9AizzBPMq -bQ== ------END PRIVATE KEY-----` - PublicKeyECDSAP521 = `-----BEGIN PUBLIC KEY----- -MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAY3m02Wbupejq4W+jSsENWLCLIE4O -QRSV7gUZwKZdHJu4auJT/ch96rFvqJCLPq92JLQKcOOY7OU9CVhKoRl9NtUBmmbc -Nnsy+z0TpFleQP4oXFZqQZldJTAwErbvlZY/YOaDPE6YaU1xduFVw5PDvPksMKvk -qdZqUY1iPQIs8wTzKm0= ------END PUBLIC KEY-----` - PrivateKeyRSA = `-----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDvaEqOq1uOTrSj -uAVIBKwQ7gspal8nPL4mKEuw2rO0upV7PSFKrANv7qyWy6ZzxoxbkdyqZFSQH3wS -z6uJEado0BfH8lF2U3W/+LRj5dPyVs2DTjLNRqCC7klhk5s5jtosEcnYechPHWPm -ggM5iJe7sni0JxE88KUwHVDjEydzbvRXTQSp2ccX6fAyMAWpNQr7AWfy4rHoWsfc -APIW/2ai6ufs+PXbNurjaxoZMxawaR5QM7kVhNFlfOSVq7TxRmfkZZDvVSGc4as2 -g+clnlQsnM6C1UfercGwvkGfIIueUtN9SLZIgpuVTXLNswLOBjvOx/ESzFohmBUp -FgCnd+zxAgMBAAECggEAYuXhTtiI5NuskalWPS746bF8WOqBTlMwddDVm8Rs0i71 -y0gwdYljjhy5nT2ZkGAn4Tf7QURbDoKDHb4+LUxmrMyx1j5K2qeVj+0sj8wEZyrm -kOR/5f7UFeJb2/w+9mMFy4i5qjx8u/n3J+TzchP0ImySolE1NMhwZNTncjaaaHtT -w2HInbdnfuMX8AKX5OSsYl6upE99JU9Vd53JZophu02wf8hdeobWbn4akxl4YGlO -3ZXYfE4L9+wpvB/weV1Eof7zn0+a4cCjilSySWEnOiBb/ZUg+mEdJA/eMR0rHmex -KbqZbzrk6AWxPmn4FOpD2PspFAHGrJ6lIoaCdOZ/dQKBgQD+wCIFDJ3tFjhAONoG -A8RNeYbsicx2gWRdwnlMKcqdGgvgWoyd1FQReB0+1MOp1csihmAsaOCYo6vmhDvq -WFEpJhCxiztXsYkfilB6xbQ2LhvTsXaPlJBA6SMDJ2XgA+NFCE9iYNjeurTp1/aj -LyETbU7RFkO06TcuJiofljDkcwKBgQDwlOS0B0DaDRekinD/BH7O22J5MDyUtxjO -xv8J00LfvXhxuDhEhTbT4mMJgTyCk0jgsFEpRbpMdqjWH6R+NbE1tekFpazkgYd9 -z4HMLmic17XKOXWnledOaAkQB6USINp4GWLdGjiAeB3ELmmev91ZcfbU0d68LOo5 -ODMLaD50CwKBgBeJWttKkiDAh8vvNL2PhYh+7OdXx+s/Ay3idOCDj/O531UIKKvA -XVAL3+/ZKoa7ePwknCgePHn9zTkMCJkbNcxuduZgbcgpX/jpB4yATakf03RYlhKn -8Df/EjwNXM04rrvHC8aUGhVh/KsKSABFr3GjDMAmpXTGg1GhNw0aDERfAoGBANYa -a/6bheeIR0YzvqP1iDTnoRdhCkj/OaCsEETaMmWT5SCvZcP1GfovOxw2W3eJRA5S -W6hzWXy7DT6iIm3/spmuLpbL/rXNYJtilIz1sDwE7M/vmvltutBYXdhaNVmQy1ye -mxFSSH5sZ3E0LOMOtRrpBVYZADRPdJM/pI2+U/ZJAoGBANVYEY7eJDSwnGcJFvf4 -C4RrvNsyrQOLOF5+u5HAhWxrsRZXM+0I7Dqvid+/4yOVXY3Sdr6x0wOzjFMO1nxZ -vAodwAZdy5kWtFJjBOKruBAfkxxQ3dqTiofsm0Jp+h4SEnj/DsSLe3la2/BGXkhm -BWwgHX6PoC7FAdbJ3tILBxD2 ------END PRIVATE KEY-----` - PrivateKeyRSAPKCS1 = `-----BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEA2Bkw7DIJg8+7hQPHSWp1YditDQTn/aF5Uc8yNlzkcCyi4lpY -hc7rKQkzPKRqopNRGhSPKpjRxt4OQz4ZRsAlDjQ5HpbknEZKOkWLbf8M2mG4u2wF -a4mdDZo3+rXwPyYffSlTbmovbg0MKcbV8Pqb6YeW/nF1zX4FSNcSvVY1CDHRdnp2 -P16clWA4vUKSzOX6mxAuYjfuqE6SKtBDDQMtAWXqEvY1LYTBh0P3ny6VsHWhaecP -AmMJNyOkvXTHrrNI2cUSh+++ilbuTqTEi77Cw7jLPVcJr+IodcCER1oZ+9oyliLD -pdYNOlM26WGM2Ul48KH4ToAGRvJhfQjkla5/owIDAQABAoIBADCYqanULtOXmaH2 -EZDvAeq5IWF2Iv2knHXLVI1pIm4fe5nPm2yr9bJKwVz31Isu+eQVj4SSzUodkbOJ -eYGxoCOrltTMNij2naaxEQPxgWBy7WoohqeCUPFIJyKYW6i32Aj7jCmec4AaKwwS -DPaeRQWlWk1qEoXduy6AP1SY2GA4+f8StG3+xMOWUlo3H1qIWUKwAcQnW5q2XWiF -0q2Nayuz/D17xG8IPVx/T3ZFA1t7P8Y5gjM0LHwf8GWu0KcAZaK2myrF67O3zhQe -7QSmMjiyKNymE/rUuLH+apx6HBCkpuvHVjbqG4strt2mUYsvmp6peyMPupqIm4Kl -xnq1CeECgYEA8hAzk7XD+ZwxxTCOvvq0tJqncaLQeW3HZMKo4nqNhnrjN21NW8Gg -xQ6wh+9uH4WHLHRLp0HNP/z9jLmFcHQygebcHDTQrwLGgAAy+nnxIh40cNWdR4B/ -dJA6GxWkapgQw84byDXnJROYJRede4+ITlR0KOfPzERXTHfo5jXM0JsCgYEA5IpK -TE8dl/1DDaXCWzWW0orKslKl49/tIzZrV8JLiGvGehCOCAdgLOLMsE96iUQka9T2 -us2120ltVjTuo95RulqJHcP5Hb6Z4jxK7ho5V28AzMpWJc3Sto8kS1Y+abAiGNyN -4NJqeDI+P2ATW8eQOJIsCrpT28Fyb3Ylov/nKZkCgYAKnX9FiQERHzJnjVuVMHVg -Pi/9ocA2swO9fXPeirVOInF4asirr3AXdC91pqBTrY1h+6+dpBsWJUgRNcmORuo4 -HCGm8wH7ysldr6SMq3BRqLVwBU4iZpYwTGrf6TEOo6CIla9ONl7ul09iwQhc9Mxr -cvStHo1UTeLuLYv/HHjg5QKBgE2X8k/kUKzo7Ro2HD3xfOqw+s7+ppouzgm1kU5z -hkekJ/gLpN1u+6Vhv5Ng+L6gJymBXd/gtgzk6j1prVhvxBncYU982RjTPNYGGH6s -4qkf5Aqj7Anbzt3yzaTSfFBP39PHFlituD5k+KN10DzKDdpXLqLZzlz/WgYj+/VS -oz6JAoGAUaG6yncXpdmZmDfGhxwQtfZ5saJoj/KooKrnwerxoItDsUYLeIGmwDgV -yLMn8dwhm2xg8cjYsdR2uxEiBhGtA0VH6PnAnOU5Bnw4haOWiZ6D4zh7PAGh5jAW -j/ZC1+dPF08FixsQbPxEtTYZe9/9cvhbB0iVg5ir6X2Y7EfW+LY= ------END RSA PRIVATE KEY-----` - PrivateKeyEdDSA = `-----BEGIN EC PRIVATE KEY----- -MHcCAQEEIObQL4Tfegl+9PQUDCHceXk5kgLfpnwWKrcHcbUZnmwioAoGCCqGSM49 -AwEHoUQDQgAEfPeNXqdQ6L2VnVRrOjtsLj9LWJId1dLEERv7j+3U9dGasF1UWrg/ -fZKOwSHuqhAjvdPMFAKmUgePNjU14bjy5A== ------END EC PRIVATE KEY-----` - PrivateKeyEd25519 = `-----BEGIN PRIVATE KEY----- -MC4CAQAwBQYDK2VwBCIEIG1ZSPHHBCWnpD1hZAsEMxMemPK26E6EbxxXgsA5M/9H ------END PRIVATE KEY-----` -) diff --git a/server.go b/server.go index 3febcb9ce..11a8d5c19 100644 --- a/server.go +++ b/server.go @@ -30,7 +30,6 @@ import ( dconfig "github.com/mendersoftware/deviceauth/config" "github.com/mendersoftware/deviceauth/devauth" "github.com/mendersoftware/deviceauth/jwt" - "github.com/mendersoftware/deviceauth/keys" "github.com/mendersoftware/deviceauth/store/mongo" ) @@ -49,23 +48,6 @@ func SetupAPI(stacktype string) (*rest.Api, error) { return api, nil } -func getJWTHandler(privateKeyType, privateKeyPath string) (jwt.Handler, error) { - if privateKeyType == dconfig.SettingServerPrivKeyTypeRSA { - privKey, err := keys.LoadRSAPrivate(privateKeyPath) - if err != nil { - return nil, errors.Wrap(err, "failed to read rsa private key") - } - return jwt.NewJWTHandlerRS256(privKey), nil - } else if privateKeyType == dconfig.SettingServerPrivKeyTypeEd25519 { - privKey, err := keys.LoadEd25519Private(privateKeyPath) - if err != nil { - return nil, errors.Wrap(err, "failed to read ed25519 private key") - } - return jwt.NewJWTHandlerEd25519(privKey), nil - } - return nil, errors.Errorf("unsupported server private key type %v", privateKeyType) -} - func RunServer(c config.Reader) error { var tenantadmAddr = c.GetString(dconfig.SettingTenantAdmAddr) @@ -85,15 +67,13 @@ func RunServer(c config.Reader) error { return errors.Wrap(err, "database connection failed") } - jwtHandler, err := getJWTHandler( - c.GetString(dconfig.SettingServerPrivKeyType), + jwtHandler, err := jwt.NewJWTHandler( c.GetString(dconfig.SettingServerPrivKeyPath), ) var jwtFallbackHandler jwt.Handler fallback := c.GetString(dconfig.SettingServerFallbackPrivKeyPath) if err == nil && fallback != "" { - jwtFallbackHandler, err = getJWTHandler( - c.GetString(dconfig.SettingServerFallbackPrivKeyType), + jwtFallbackHandler, err = jwt.NewJWTHandler( fallback, ) } diff --git a/server_test.go b/server_test.go index 9452ba00a..0c6ad1731 100644 --- a/server_test.go +++ b/server_test.go @@ -16,8 +16,6 @@ package main import ( "testing" - "github.com/mendersoftware/deviceauth/config" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" ) @@ -31,46 +29,3 @@ func TestSetupApi(t *testing.T) { assert.NotNil(t, api) assert.Nil(t, err) } - -func TestGetJWTHandler(t *testing.T) { - testCases := map[string]struct { - privateKeyType string - privateKeyPath string - fallbackPrivateKeyPath string - err error - }{ - "ok, rsa": { - privateKeyType: config.SettingServerPrivKeyTypeRSA, - privateKeyPath: "jwt/testdata/rsa.pem", - }, - "ko, rsa": { - privateKeyType: config.SettingServerPrivKeyTypeRSA, - privateKeyPath: "jwt/testdata/doesnotexist.pem", - err: errors.New("failed to read rsa private key: failed to read server private key file: open jwt/testdata/doesnotexist.pem: no such file or directory"), - }, - "ok, ed25519": { - privateKeyType: config.SettingServerPrivKeyTypeEd25519, - privateKeyPath: "jwt/testdata/ed25519.pem", - }, - "ko, ed25519": { - privateKeyType: config.SettingServerPrivKeyTypeEd25519, - privateKeyPath: "jwt/testdata/doesnotexist.pem", - err: errors.New("failed to read ed25519 private key: failed to read server private key file: open jwt/testdata/doesnotexist.pem: no such file or directory"), - }, - "unknown priate key type": { - privateKeyType: "dummy", - err: errors.New("unsupported server private key type dummy"), - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - _, err := getJWTHandler(tc.privateKeyType, tc.privateKeyPath) - if tc.err != nil { - assert.EqualError(t, err, tc.err.Error()) - } else { - assert.NoError(t, err) - } - }) - } -}