Skip to content

Commit

Permalink
chore: autodetection of private key type
Browse files Browse the repository at this point in the history
Changelog: None
Ticket: None

Signed-off-by: Fabio Tranchitella <[email protected]>
  • Loading branch information
tranchitella committed Oct 25, 2023
1 parent bfab588 commit 91cc9a1
Show file tree
Hide file tree
Showing 12 changed files with 160 additions and 382 deletions.
14 changes: 0 additions & 14 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,26 +72,12 @@

# default_tenant_token: <VALID_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
Expand Down
10 changes: 0 additions & 10 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ""

Expand Down Expand Up @@ -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},
Expand Down
39 changes: 39 additions & 0 deletions jwt/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
package jwt

import (
"crypto/ed25519"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"os"

"github.com/pkg/errors"
)

Expand All @@ -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
Expand All @@ -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")
}
16 changes: 12 additions & 4 deletions jwt/jwt_ed25519_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ package jwt

import (
"crypto/ed25519"
"crypto/x509"
"encoding/pem"
"os"
"testing"
"time"

jwtgo "github.com/golang-jwt/jwt/v4"
"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) {
Expand Down Expand Up @@ -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 {
Expand Down
13 changes: 10 additions & 3 deletions jwt/jwt_rsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ package jwt

import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"os"
"testing"
"time"

jwtgo "github.com/golang-jwt/jwt/v4"
"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) {
Expand Down Expand Up @@ -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
}

Expand Down
57 changes: 57 additions & 0 deletions jwt/jwt_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
})
}
}
12 changes: 12 additions & 0 deletions jwt/testdata/dsa.pem
Original file line number Diff line number Diff line change
@@ -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-----
28 changes: 28 additions & 0 deletions jwt/testdata/rsa_pkcs8.pem
Original file line number Diff line number Diff line change
@@ -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-----
49 changes: 0 additions & 49 deletions keys/key.go

This file was deleted.

Loading

0 comments on commit 91cc9a1

Please sign in to comment.