forked from TrueCloudLab/certificates
Add support for password encrypted files
This commit is contained in:
parent
80542d6d9a
commit
edc7c4d90e
4 changed files with 133 additions and 40 deletions
|
@ -58,6 +58,7 @@ type CertificateIssuer struct {
|
||||||
Provisioner string `json:"provisioner,omitempty"`
|
Provisioner string `json:"provisioner,omitempty"`
|
||||||
Certificate string `json:"crt,omitempty"`
|
Certificate string `json:"crt,omitempty"`
|
||||||
Key string `json:"key,omitempty"`
|
Key string `json:"key,omitempty"`
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate checks the fields in Options.
|
// Validate checks the fields in Options.
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
package stepcas
|
package stepcas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/smallstep/certificates/cas/apiv1"
|
"github.com/smallstep/certificates/cas/apiv1"
|
||||||
"go.step.sm/crypto/jose"
|
"go.step.sm/crypto/jose"
|
||||||
"go.step.sm/crypto/pemutil"
|
|
||||||
"go.step.sm/crypto/randutil"
|
"go.step.sm/crypto/randutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type jwkIssuer struct {
|
type jwkIssuer struct {
|
||||||
caURL *url.URL
|
caURL *url.URL
|
||||||
keyFile string
|
|
||||||
issuer string
|
issuer string
|
||||||
|
keyFile string
|
||||||
|
password string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newJWKIssuer(caURL *url.URL, cfg *apiv1.CertificateIssuer) (*jwkIssuer, error) {
|
func newJWKIssuer(caURL *url.URL, cfg *apiv1.CertificateIssuer) (*jwkIssuer, error) {
|
||||||
_, err := newJWKSigner(cfg.Key)
|
_, err := newJWKSigner(cfg.Key, cfg.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &jwkIssuer{
|
return &jwkIssuer{
|
||||||
caURL: caURL,
|
caURL: caURL,
|
||||||
keyFile: cfg.Key,
|
|
||||||
issuer: cfg.Provisioner,
|
issuer: cfg.Provisioner,
|
||||||
|
keyFile: cfg.Key,
|
||||||
|
password: cfg.Password,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ func (i *jwkIssuer) Lifetime(d time.Duration) time.Duration {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *jwkIssuer) createToken(aud, sub string, sans []string) (string, error) {
|
func (i *jwkIssuer) createToken(aud, sub string, sans []string) (string, error) {
|
||||||
signer, err := newJWKSigner(i.keyFile)
|
signer, err := newJWKSigner(i.keyFile, i.password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -76,15 +76,11 @@ func (i *jwkIssuer) createToken(aud, sub string, sans []string) (string, error)
|
||||||
return tok, nil
|
return tok, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newJWKSigner(keyFile string) (jose.Signer, error) {
|
func newJWKSigner(keyFile, password string) (jose.Signer, error) {
|
||||||
key, err := pemutil.Read(keyFile)
|
signer, err := readKey(keyFile, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
signer, ok := key.(crypto.Signer)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("key is not a crypto.Signer")
|
|
||||||
}
|
|
||||||
kid, err := jose.Thumbprint(&jose.JSONWebKey{Key: signer.Public()})
|
kid, err := jose.Thumbprint(&jose.JSONWebKey{Key: signer.Public()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -23,6 +23,8 @@ import (
|
||||||
"github.com/smallstep/certificates/api"
|
"github.com/smallstep/certificates/api"
|
||||||
"github.com/smallstep/certificates/ca"
|
"github.com/smallstep/certificates/ca"
|
||||||
"github.com/smallstep/certificates/cas/apiv1"
|
"github.com/smallstep/certificates/cas/apiv1"
|
||||||
|
"go.step.sm/crypto/pemutil"
|
||||||
|
"go.step.sm/crypto/randutil"
|
||||||
"go.step.sm/crypto/x509util"
|
"go.step.sm/crypto/x509util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -39,6 +41,7 @@ var (
|
||||||
testX5CCrt *x509.Certificate
|
testX5CCrt *x509.Certificate
|
||||||
testX5CKey crypto.Signer
|
testX5CKey crypto.Signer
|
||||||
testX5CPath, testX5CKeyPath string
|
testX5CPath, testX5CKeyPath string
|
||||||
|
testPassword, testEncryptedKeyPath string
|
||||||
|
|
||||||
testCR *x509.CertificateRequest
|
testCR *x509.CertificateRequest
|
||||||
testCrt *x509.Certificate
|
testCrt *x509.Certificate
|
||||||
|
@ -104,6 +107,16 @@ func mustSerializeKey(filename string, key crypto.Signer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mustEncryptKey(filename string, key crypto.Signer) {
|
||||||
|
_, err := pemutil.Serialize(key,
|
||||||
|
pemutil.ToFile(filename, 0600),
|
||||||
|
pemutil.WithPKCS8(true),
|
||||||
|
pemutil.WithPassword([]byte(testPassword)))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testCAHelper(t *testing.T) (*url.URL, *ca.Client) {
|
func testCAHelper(t *testing.T) (*url.URL, *ca.Client) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
@ -167,31 +180,45 @@ func testCAHelper(t *testing.T) (*url.URL, *ca.Client) {
|
||||||
return u, client
|
return u, client
|
||||||
}
|
}
|
||||||
|
|
||||||
func testX5CIssuer(t *testing.T, caURL *url.URL) *x5cIssuer {
|
func testX5CIssuer(t *testing.T, caURL *url.URL, password string) *x5cIssuer {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
key, givenPassword := testX5CKeyPath, password
|
||||||
|
if password != "" {
|
||||||
|
key = testEncryptedKeyPath
|
||||||
|
password = testPassword
|
||||||
|
}
|
||||||
x5c, err := newX5CIssuer(caURL, &apiv1.CertificateIssuer{
|
x5c, err := newX5CIssuer(caURL, &apiv1.CertificateIssuer{
|
||||||
Type: "x5c",
|
Type: "x5c",
|
||||||
Provisioner: "X5C",
|
Provisioner: "X5C",
|
||||||
Certificate: testX5CPath,
|
Certificate: testX5CPath,
|
||||||
Key: testX5CKeyPath,
|
Key: key,
|
||||||
|
Password: password,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
x5c.password = givenPassword
|
||||||
return x5c
|
return x5c
|
||||||
}
|
}
|
||||||
|
|
||||||
func testJWKIssuer(t *testing.T, caURL *url.URL) *jwkIssuer {
|
func testJWKIssuer(t *testing.T, caURL *url.URL, password string) *jwkIssuer {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
x5c, err := newJWKIssuer(caURL, &apiv1.CertificateIssuer{
|
key, givenPassword := testX5CKeyPath, password
|
||||||
|
if password != "" {
|
||||||
|
key = testEncryptedKeyPath
|
||||||
|
password = testPassword
|
||||||
|
}
|
||||||
|
jwk, err := newJWKIssuer(caURL, &apiv1.CertificateIssuer{
|
||||||
Type: "jwk",
|
Type: "jwk",
|
||||||
Provisioner: "ra@doe.org",
|
Provisioner: "ra@doe.org",
|
||||||
Key: testX5CKeyPath,
|
Key: key,
|
||||||
|
Password: password,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
return x5c
|
jwk.password = givenPassword
|
||||||
|
return jwk
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
@ -214,6 +241,12 @@ func TestMain(m *testing.M) {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Password used to encrypto the key
|
||||||
|
testPassword, err = randutil.Hex(32)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
testRootFingerprint = x509util.Fingerprint(testRootCrt)
|
testRootFingerprint = x509util.Fingerprint(testRootCrt)
|
||||||
|
|
||||||
path, err := ioutil.TempDir(os.TempDir(), "stepcas")
|
path, err := ioutil.TempDir(os.TempDir(), "stepcas")
|
||||||
|
@ -236,6 +269,9 @@ func TestMain(m *testing.M) {
|
||||||
mustSerializeCrt(testX5CPath, testX5CCrt, testIssCrt)
|
mustSerializeCrt(testX5CPath, testX5CCrt, testIssCrt)
|
||||||
mustSerializeKey(testX5CKeyPath, testX5CKey)
|
mustSerializeKey(testX5CKeyPath, testX5CKey)
|
||||||
|
|
||||||
|
testEncryptedKeyPath = filepath.Join(path, "x5c.enc.key")
|
||||||
|
mustEncryptKey(testEncryptedKeyPath, testX5CKey)
|
||||||
|
|
||||||
code := m.Run()
|
code := m.Run()
|
||||||
if err := os.RemoveAll(path); err != nil {
|
if err := os.RemoveAll(path); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -473,8 +509,12 @@ func TestNew(t *testing.T) {
|
||||||
|
|
||||||
func TestStepCAS_CreateCertificate(t *testing.T) {
|
func TestStepCAS_CreateCertificate(t *testing.T) {
|
||||||
caURL, client := testCAHelper(t)
|
caURL, client := testCAHelper(t)
|
||||||
x5c := testX5CIssuer(t, caURL)
|
x5c := testX5CIssuer(t, caURL, "")
|
||||||
jwk := testJWKIssuer(t, caURL)
|
jwk := testJWKIssuer(t, caURL, "")
|
||||||
|
x5cEnc := testX5CIssuer(t, caURL, testPassword)
|
||||||
|
jwkEnc := testJWKIssuer(t, caURL, testPassword)
|
||||||
|
x5cBad := testX5CIssuer(t, caURL, "bad-password")
|
||||||
|
jwkBad := testJWKIssuer(t, caURL, "bad-password")
|
||||||
|
|
||||||
type fields struct {
|
type fields struct {
|
||||||
iss stepIssuer
|
iss stepIssuer
|
||||||
|
@ -498,6 +538,13 @@ func TestStepCAS_CreateCertificate(t *testing.T) {
|
||||||
Certificate: testCrt,
|
Certificate: testCrt,
|
||||||
CertificateChain: []*x509.Certificate{testIssCrt},
|
CertificateChain: []*x509.Certificate{testIssCrt},
|
||||||
}, false},
|
}, false},
|
||||||
|
{"ok with password", fields{x5cEnc, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{
|
||||||
|
CSR: testCR,
|
||||||
|
Lifetime: time.Hour,
|
||||||
|
}}, &apiv1.CreateCertificateResponse{
|
||||||
|
Certificate: testCrt,
|
||||||
|
CertificateChain: []*x509.Certificate{testIssCrt},
|
||||||
|
}, false},
|
||||||
{"ok jwk", fields{jwk, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{
|
{"ok jwk", fields{jwk, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{
|
||||||
CSR: testCR,
|
CSR: testCR,
|
||||||
Lifetime: time.Hour,
|
Lifetime: time.Hour,
|
||||||
|
@ -505,6 +552,13 @@ func TestStepCAS_CreateCertificate(t *testing.T) {
|
||||||
Certificate: testCrt,
|
Certificate: testCrt,
|
||||||
CertificateChain: []*x509.Certificate{testIssCrt},
|
CertificateChain: []*x509.Certificate{testIssCrt},
|
||||||
}, false},
|
}, false},
|
||||||
|
{"ok jwk with password", fields{jwkEnc, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{
|
||||||
|
CSR: testCR,
|
||||||
|
Lifetime: time.Hour,
|
||||||
|
}}, &apiv1.CreateCertificateResponse{
|
||||||
|
Certificate: testCrt,
|
||||||
|
CertificateChain: []*x509.Certificate{testIssCrt},
|
||||||
|
}, false},
|
||||||
{"fail CSR", fields{x5c, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{
|
{"fail CSR", fields{x5c, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{
|
||||||
CSR: nil,
|
CSR: nil,
|
||||||
Lifetime: time.Hour,
|
Lifetime: time.Hour,
|
||||||
|
@ -521,6 +575,14 @@ func TestStepCAS_CreateCertificate(t *testing.T) {
|
||||||
CSR: testFailCR,
|
CSR: testFailCR,
|
||||||
Lifetime: time.Hour,
|
Lifetime: time.Hour,
|
||||||
}}, nil, true},
|
}}, nil, true},
|
||||||
|
{"fail password", fields{x5cBad, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{
|
||||||
|
CSR: testCR,
|
||||||
|
Lifetime: time.Hour,
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail jwk password", fields{jwkBad, client, testRootFingerprint}, args{&apiv1.CreateCertificateRequest{
|
||||||
|
CSR: testCR,
|
||||||
|
Lifetime: time.Hour,
|
||||||
|
}}, nil, true},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -543,8 +605,8 @@ func TestStepCAS_CreateCertificate(t *testing.T) {
|
||||||
|
|
||||||
func TestStepCAS_RenewCertificate(t *testing.T) {
|
func TestStepCAS_RenewCertificate(t *testing.T) {
|
||||||
caURL, client := testCAHelper(t)
|
caURL, client := testCAHelper(t)
|
||||||
x5c := testX5CIssuer(t, caURL)
|
x5c := testX5CIssuer(t, caURL, "")
|
||||||
jwk := testJWKIssuer(t, caURL)
|
jwk := testJWKIssuer(t, caURL, "")
|
||||||
|
|
||||||
type fields struct {
|
type fields struct {
|
||||||
iss stepIssuer
|
iss stepIssuer
|
||||||
|
@ -591,8 +653,12 @@ func TestStepCAS_RenewCertificate(t *testing.T) {
|
||||||
|
|
||||||
func TestStepCAS_RevokeCertificate(t *testing.T) {
|
func TestStepCAS_RevokeCertificate(t *testing.T) {
|
||||||
caURL, client := testCAHelper(t)
|
caURL, client := testCAHelper(t)
|
||||||
x5c := testX5CIssuer(t, caURL)
|
x5c := testX5CIssuer(t, caURL, "")
|
||||||
jwk := testJWKIssuer(t, caURL)
|
jwk := testJWKIssuer(t, caURL, "")
|
||||||
|
x5cEnc := testX5CIssuer(t, caURL, testPassword)
|
||||||
|
jwkEnc := testJWKIssuer(t, caURL, testPassword)
|
||||||
|
x5cBad := testX5CIssuer(t, caURL, "bad-password")
|
||||||
|
jwkBad := testJWKIssuer(t, caURL, "bad-password")
|
||||||
|
|
||||||
type fields struct {
|
type fields struct {
|
||||||
iss stepIssuer
|
iss stepIssuer
|
||||||
|
@ -625,6 +691,10 @@ func TestStepCAS_RevokeCertificate(t *testing.T) {
|
||||||
}}, &apiv1.RevokeCertificateResponse{
|
}}, &apiv1.RevokeCertificateResponse{
|
||||||
Certificate: testCrt,
|
Certificate: testCrt,
|
||||||
}, false},
|
}, false},
|
||||||
|
{"ok with password", fields{x5cEnc, client, testRootFingerprint}, args{&apiv1.RevokeCertificateRequest{
|
||||||
|
SerialNumber: "ok",
|
||||||
|
Certificate: nil,
|
||||||
|
}}, &apiv1.RevokeCertificateResponse{}, false},
|
||||||
{"ok serial number jwk", fields{jwk, client, testRootFingerprint}, args{&apiv1.RevokeCertificateRequest{
|
{"ok serial number jwk", fields{jwk, client, testRootFingerprint}, args{&apiv1.RevokeCertificateRequest{
|
||||||
SerialNumber: "ok",
|
SerialNumber: "ok",
|
||||||
Certificate: nil,
|
Certificate: nil,
|
||||||
|
@ -641,6 +711,10 @@ func TestStepCAS_RevokeCertificate(t *testing.T) {
|
||||||
}}, &apiv1.RevokeCertificateResponse{
|
}}, &apiv1.RevokeCertificateResponse{
|
||||||
Certificate: testCrt,
|
Certificate: testCrt,
|
||||||
}, false},
|
}, false},
|
||||||
|
{"ok jwk with password", fields{jwkEnc, client, testRootFingerprint}, args{&apiv1.RevokeCertificateRequest{
|
||||||
|
SerialNumber: "ok",
|
||||||
|
Certificate: nil,
|
||||||
|
}}, &apiv1.RevokeCertificateResponse{}, false},
|
||||||
{"fail request", fields{x5c, client, testRootFingerprint}, args{&apiv1.RevokeCertificateRequest{
|
{"fail request", fields{x5c, client, testRootFingerprint}, args{&apiv1.RevokeCertificateRequest{
|
||||||
SerialNumber: "",
|
SerialNumber: "",
|
||||||
Certificate: nil,
|
Certificate: nil,
|
||||||
|
@ -651,6 +725,14 @@ func TestStepCAS_RevokeCertificate(t *testing.T) {
|
||||||
{"fail client revoke", fields{x5c, client, testRootFingerprint}, args{&apiv1.RevokeCertificateRequest{
|
{"fail client revoke", fields{x5c, client, testRootFingerprint}, args{&apiv1.RevokeCertificateRequest{
|
||||||
SerialNumber: "fail",
|
SerialNumber: "fail",
|
||||||
}}, nil, true},
|
}}, nil, true},
|
||||||
|
{"fail password", fields{x5cBad, client, testRootFingerprint}, args{&apiv1.RevokeCertificateRequest{
|
||||||
|
SerialNumber: "ok",
|
||||||
|
Certificate: nil,
|
||||||
|
}}, nil, true},
|
||||||
|
{"fail jwk password", fields{jwkBad, client, testRootFingerprint}, args{&apiv1.RevokeCertificateRequest{
|
||||||
|
SerialNumber: "ok",
|
||||||
|
Certificate: nil,
|
||||||
|
}}, nil, true},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -673,8 +755,8 @@ func TestStepCAS_RevokeCertificate(t *testing.T) {
|
||||||
|
|
||||||
func TestStepCAS_GetCertificateAuthority(t *testing.T) {
|
func TestStepCAS_GetCertificateAuthority(t *testing.T) {
|
||||||
caURL, client := testCAHelper(t)
|
caURL, client := testCAHelper(t)
|
||||||
x5c := testX5CIssuer(t, caURL)
|
x5c := testX5CIssuer(t, caURL, "")
|
||||||
jwk := testJWKIssuer(t, caURL)
|
jwk := testJWKIssuer(t, caURL, "")
|
||||||
|
|
||||||
type fields struct {
|
type fields struct {
|
||||||
iss stepIssuer
|
iss stepIssuer
|
||||||
|
|
|
@ -25,24 +25,26 @@ var timeNow = func() time.Time {
|
||||||
|
|
||||||
type x5cIssuer struct {
|
type x5cIssuer struct {
|
||||||
caURL *url.URL
|
caURL *url.URL
|
||||||
|
issuer string
|
||||||
certFile string
|
certFile string
|
||||||
keyFile string
|
keyFile string
|
||||||
issuer string
|
password string
|
||||||
}
|
}
|
||||||
|
|
||||||
// newX5CIssuer create a new x5c token issuer. The given configuration should be
|
// newX5CIssuer create a new x5c token issuer. The given configuration should be
|
||||||
// already validate.
|
// already validate.
|
||||||
func newX5CIssuer(caURL *url.URL, cfg *apiv1.CertificateIssuer) (*x5cIssuer, error) {
|
func newX5CIssuer(caURL *url.URL, cfg *apiv1.CertificateIssuer) (*x5cIssuer, error) {
|
||||||
_, err := newX5CSigner(cfg.Certificate, cfg.Key)
|
_, err := newX5CSigner(cfg.Certificate, cfg.Key, cfg.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &x5cIssuer{
|
return &x5cIssuer{
|
||||||
caURL: caURL,
|
caURL: caURL,
|
||||||
|
issuer: cfg.Provisioner,
|
||||||
certFile: cfg.Certificate,
|
certFile: cfg.Certificate,
|
||||||
keyFile: cfg.Key,
|
keyFile: cfg.Key,
|
||||||
issuer: cfg.Provisioner,
|
password: cfg.Password,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +79,7 @@ func (i *x5cIssuer) Lifetime(d time.Duration) time.Duration {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *x5cIssuer) createToken(aud, sub string, sans []string) (string, error) {
|
func (i *x5cIssuer) createToken(aud, sub string, sans []string) (string, error) {
|
||||||
signer, err := newX5CSigner(i.certFile, i.keyFile)
|
signer, err := newX5CSigner(i.certFile, i.keyFile, i.password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -116,8 +118,12 @@ func defaultClaims(iss, sub, aud, id string) jose.Claims {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newX5CSigner(certFile, keyFile string) (jose.Signer, error) {
|
func readKey(keyFile, password string) (crypto.Signer, error) {
|
||||||
key, err := pemutil.Read(keyFile)
|
var opts []pemutil.Options
|
||||||
|
if password != "" {
|
||||||
|
opts = append(opts, pemutil.WithPassword([]byte(password)))
|
||||||
|
}
|
||||||
|
key, err := pemutil.Read(keyFile, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -125,11 +131,19 @@ func newX5CSigner(certFile, keyFile string) (jose.Signer, error) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("key is not a crypto.Signer")
|
return nil, errors.New("key is not a crypto.Signer")
|
||||||
}
|
}
|
||||||
|
return signer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newX5CSigner(certFile, keyFile, password string) (jose.Signer, error) {
|
||||||
|
signer, err := readKey(keyFile, password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
kid, err := jose.Thumbprint(&jose.JSONWebKey{Key: signer.Public()})
|
kid, err := jose.Thumbprint(&jose.JSONWebKey{Key: signer.Public()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
certs, err := jose.ValidateX5C(certFile, key)
|
certs, err := jose.ValidateX5C(certFile, signer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "error validating x5c certificate chain and key")
|
return nil, errors.Wrap(err, "error validating x5c certificate chain and key")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue