You've already forked step-ca-cli
mirror of
https://github.com/smallstep/cli.git
synced 2026-10-29 00:17:23 +03:00
Add method to Parse a DER-encoded file.
This commit is contained in:
@@ -96,6 +96,18 @@ func WithPasswordFile(filename string) Options {
|
||||
}
|
||||
}
|
||||
|
||||
// WithPasswordPrompt ask the user for a password and adds it to the context.
|
||||
func WithPasswordPrompt(prompt string) Options {
|
||||
return func(ctx *context) error {
|
||||
b, err := ui.PromptPassword(prompt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx.password = b
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithPKCS8 with v set to true returns an option used in the Serialize method
|
||||
// to use the PKCS#8 encoding form on the private keys. With v set to false
|
||||
// default form will be used.
|
||||
@@ -366,3 +378,26 @@ func Serialize(in interface{}, opts ...Options) (p *pem.Block, err error) {
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// ParseDER parses the given DER-encoded bytes and results the public or private
|
||||
// key encoded.
|
||||
func ParseDER(b []byte) (interface{}, error) {
|
||||
// Try private keys
|
||||
key, err := ParsePKCS8PrivateKey(b)
|
||||
if err != nil {
|
||||
if key, err = x509.ParseECPrivateKey(b); err != nil {
|
||||
key, err = x509.ParsePKCS1PrivateKey(b)
|
||||
}
|
||||
}
|
||||
|
||||
// Try public key
|
||||
if err != nil {
|
||||
if key, err = x509.ParsePKIXPublicKey(b); err != nil {
|
||||
if key, err = x509.ParsePKCS1PublicKey(b); err != nil {
|
||||
return nil, errors.New("error decoding DER; bad format")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -488,66 +489,67 @@ func TestSerialize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestWriteKey(t *testing.T) {
|
||||
keyOut := "./test.key"
|
||||
pass := "pass"
|
||||
func TestParseDER(t *testing.T) {
|
||||
k1, err := Read("testdata/openssl.rsa2048.pem")
|
||||
assert.FatalError(t, err)
|
||||
k2, err := Read("testdata/openssl.p256.pem")
|
||||
assert.FatalError(t, err)
|
||||
k3, err := Read("testdata/pkcs8/openssl.ed25519.pem")
|
||||
assert.FatalError(t, err)
|
||||
rsaKey := k1.(*rsa.PrivateKey)
|
||||
ecdsaKey := k2.(*ecdsa.PrivateKey)
|
||||
edKey := k3.(ed25519.PrivateKey)
|
||||
// Ed25519 der files
|
||||
edPubDer, err := ioutil.ReadFile("testdata/pkcs8/openssl.ed25519.pub.der")
|
||||
assert.FatalError(t, err)
|
||||
edPrivDer, err := ioutil.ReadFile("testdata/pkcs8/openssl.ed25519.der")
|
||||
assert.FatalError(t, err)
|
||||
|
||||
tests := map[string]struct {
|
||||
key func() (interface{}, error)
|
||||
keyOut string
|
||||
pass string
|
||||
err error
|
||||
}{
|
||||
"success": {
|
||||
key: func() (interface{}, error) {
|
||||
return GenerateKey(DefaultKeyType, DefaultKeyCurve, 0)
|
||||
},
|
||||
keyOut: keyOut,
|
||||
pass: pass,
|
||||
err: errors.New("failed to convert private key to PEM block: encryption passphrase cannot be empty"),
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Logf("Running test case: %s", name)
|
||||
|
||||
key, err := test.key()
|
||||
assert.FatalError(t, err)
|
||||
|
||||
err = WritePrivateKey(key, test.pass, test.keyOut)
|
||||
if err != nil {
|
||||
if assert.NotNil(t, test.err) {
|
||||
assert.HasPrefix(t, err.Error(), test.err.Error())
|
||||
}
|
||||
} else {
|
||||
// Check key permissions
|
||||
fileInfo, err := os.Stat(test.keyOut)
|
||||
toDER := func(k interface{}) []byte {
|
||||
switch k := k.(type) {
|
||||
case *rsa.PublicKey, *ecdsa.PublicKey:
|
||||
b, err := x509.MarshalPKIXPublicKey(k)
|
||||
assert.FatalError(t, err)
|
||||
fileMode := fileInfo.Mode()
|
||||
if fileMode != 0600 {
|
||||
t.Errorf("FileMode mismatch for file %s -- expected: `%d`, but got: `%d`",
|
||||
test.keyOut, fileMode, 0600)
|
||||
}
|
||||
|
||||
switch k := key.(type) {
|
||||
case *ecdsa.PrivateKey:
|
||||
// Verify that key written to file is correct
|
||||
plain, err := x509.MarshalECPrivateKey(k)
|
||||
assert.FatalError(t, err)
|
||||
keyFileBytes, err := ioutil.ReadFile(test.keyOut)
|
||||
assert.FatalError(t, err)
|
||||
pemKey, _ := pem.Decode(keyFileBytes)
|
||||
assert.True(t, x509.IsEncryptedPEMBlock(pemKey))
|
||||
assert.Equals(t, pemKey.Type, "EC PRIVATE KEY")
|
||||
assert.Equals(t, pemKey.Headers["Proc-Type"], "4,ENCRYPTED")
|
||||
der, err := x509.DecryptPEMBlock(pemKey, []byte(pass))
|
||||
assert.FatalError(t, err)
|
||||
assert.Equals(t, der, plain)
|
||||
default:
|
||||
t.Errorf("unexpected key type %T", k)
|
||||
}
|
||||
return b
|
||||
case *rsa.PrivateKey:
|
||||
return x509.MarshalPKCS1PrivateKey(k)
|
||||
case *ecdsa.PrivateKey:
|
||||
b, err := x509.MarshalECPrivateKey(k)
|
||||
assert.FatalError(t, err)
|
||||
return b
|
||||
default:
|
||||
t.Fatalf("unsupported key type %T", k)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type args struct {
|
||||
b []byte
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want interface{}
|
||||
wantErr bool
|
||||
}{
|
||||
{"rsa public key", args{toDER(rsaKey.Public())}, rsaKey.Public(), false},
|
||||
{"rsa private key", args{toDER(rsaKey)}, rsaKey, false},
|
||||
{"ecdsa public key", args{toDER(ecdsaKey.Public())}, ecdsaKey.Public(), false},
|
||||
{"ecdsa private key", args{toDER(ecdsaKey)}, ecdsaKey, false},
|
||||
{"ed25519 public key", args{edPubDer}, edKey.Public(), false},
|
||||
{"ed25519 private key", args{edPrivDer}, edKey, false},
|
||||
{"fail", args{[]byte("fooo")}, nil, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ParseDER(tt.args.b)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ParseDER() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("ParseDER() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user