-
Notifications
You must be signed in to change notification settings - Fork 164
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: dmitriy kalinin <dkalinin@pivotal.io>
- Loading branch information
1 parent
1752cc9
commit 10de537
Showing
6 changed files
with
295 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package types | ||
|
||
import ( | ||
"crypto/rand" | ||
"crypto/rsa" | ||
"crypto/x509" | ||
"encoding/pem" | ||
"fmt" | ||
) | ||
|
||
const ( | ||
rsaKeyGeneratorKeyBits = 2048 | ||
rsaKeyGeneratorHeaderPrivateKey = "RSA PRIVATE KEY" | ||
rsaKeyGeneratorHeaderPublicKey = "PUBLIC KEY" | ||
) | ||
|
||
type RSAKeyGenerator struct{} | ||
|
||
func NewRSAKeyGenerator() RSAKeyGenerator { | ||
return RSAKeyGenerator{} | ||
} | ||
|
||
type RSAKey struct { | ||
PrivateKey string `json:"private_key" yaml:"private_key"` | ||
PublicKey string `json:"public_key" yaml:"public_key"` | ||
} | ||
|
||
func (g RSAKeyGenerator) Generate(parameters interface{}) (interface{}, error) { | ||
priv, pub, err := g.generateRSAKeyPair() | ||
if err != nil { | ||
return nil, fmt.Errorf("Generating RSA key pair: %s", err) | ||
} | ||
|
||
pubKeyStr, err := g.publicKeyToPEM(pub) | ||
if err != nil { | ||
return nil, fmt.Errorf("Generating RSA public key pair: %s", err) | ||
} | ||
|
||
return RSAKey{ | ||
PrivateKey: g.privateKeyToPEM(priv), | ||
PublicKey: pubKeyStr, | ||
}, nil | ||
} | ||
|
||
func (g RSAKeyGenerator) encodePEM(keyBytes []byte, keyType string) string { | ||
block := &pem.Block{ | ||
Type: keyType, | ||
Bytes: keyBytes, | ||
} | ||
|
||
return string(pem.EncodeToMemory(block)) | ||
} | ||
|
||
func (g RSAKeyGenerator) generateRSAKeyPair() (*rsa.PrivateKey, *rsa.PublicKey, error) { | ||
private, err := rsa.GenerateKey(rand.Reader, rsaKeyGeneratorKeyBits) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
public := private.Public().(*rsa.PublicKey) | ||
|
||
return private, public, nil | ||
} | ||
|
||
func (g RSAKeyGenerator) privateKeyToPEM(privateKey *rsa.PrivateKey) string { | ||
return g.encodePEM(x509.MarshalPKCS1PrivateKey(privateKey), rsaKeyGeneratorHeaderPrivateKey) | ||
} | ||
|
||
func (g RSAKeyGenerator) publicKeyToPEM(publicKey *rsa.PublicKey) (string, error) { | ||
keyBytes, err := x509.MarshalPKIXPublicKey(publicKey) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return g.encodePEM(keyBytes, rsaKeyGeneratorHeaderPublicKey), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package types_test | ||
|
||
import ( | ||
"crypto/x509" | ||
"encoding/json" | ||
"encoding/pem" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
"gopkg.in/yaml.v2" | ||
|
||
. "config_server/types" | ||
) | ||
|
||
var _ = FDescribe("RSAKeyGenerator", func() { | ||
var generator ValueGenerator | ||
|
||
BeforeEach(func() { | ||
generator = NewRSAKeyGenerator() | ||
}) | ||
|
||
Context("Generate", func() { | ||
It("generates an rsa key with 2048 bits", func() { | ||
rsaKey, err := generator.Generate(nil) | ||
Expect(err).ToNot(HaveOccurred()) | ||
|
||
typedRSAKey := rsaKey.(RSAKey) | ||
Expect(typedRSAKey.PrivateKey).To(ContainSubstring("PRIVATE KEY")) | ||
Expect(typedRSAKey.PublicKey).To(ContainSubstring("PUBLIC KEY")) | ||
|
||
privBlock, _ := pem.Decode([]byte(typedRSAKey.PrivateKey)) | ||
|
||
privKey, err := x509.ParsePKCS1PrivateKey(privBlock.Bytes) | ||
Expect(err).ToNot(HaveOccurred()) | ||
|
||
pubBlock, _ := pem.Decode([]byte(typedRSAKey.PublicKey)) | ||
|
||
pubKey, err := x509.ParsePKIXPublicKey(pubBlock.Bytes) | ||
Expect(err).ToNot(HaveOccurred()) | ||
|
||
Expect(privKey.Public()).To(Equal(pubKey)) | ||
}) | ||
|
||
It("serializes nicely in json/yaml", func() { | ||
rsaKey, err := generator.Generate(nil) | ||
Expect(err).ToNot(HaveOccurred()) | ||
|
||
bytes, err := yaml.Marshal(rsaKey) | ||
Expect(err).ToNot(HaveOccurred()) | ||
Expect(string(bytes)).To(ContainSubstring("private_key")) | ||
Expect(string(bytes)).To(ContainSubstring("public_key")) | ||
|
||
bytes, err = json.Marshal(rsaKey) | ||
Expect(err).ToNot(HaveOccurred()) | ||
Expect(string(bytes)).To(ContainSubstring("private_key")) | ||
Expect(string(bytes)).To(ContainSubstring("public_key")) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package types | ||
|
||
import ( | ||
"crypto/md5" | ||
"crypto/rand" | ||
"crypto/rsa" | ||
"crypto/x509" | ||
"encoding/pem" | ||
"fmt" | ||
|
||
"golang.org/x/crypto/ssh" | ||
) | ||
|
||
const ( | ||
sshKeyGeneratorKeyBits = 2048 | ||
sshKeyGeneratorHeaderPrivateKey = "RSA PRIVATE KEY" | ||
sshKeyGeneratorHeaderPublicKey = "PUBLIC KEY" | ||
) | ||
|
||
type SSHKeyGenerator struct{} | ||
|
||
func NewSSHKeyGenerator() SSHKeyGenerator { | ||
return SSHKeyGenerator{} | ||
} | ||
|
||
type SSHKey struct { | ||
PrivateKey string `json:"private_key" yaml:"private_key"` | ||
PublicKey string `json:"public_key" yaml:"public_key"` | ||
PublicKeyFingerprint string `json:"public_key_fingerprint" yaml:"public_key_fingerprint"` | ||
} | ||
|
||
func (g SSHKeyGenerator) Generate(parameters interface{}) (interface{}, error) { | ||
priv, pub, err := g.generateRSAKeyPair() | ||
if err != nil { | ||
return nil, fmt.Errorf("Generating RSA key pair: %s", err) | ||
} | ||
|
||
sshPubKey, err := ssh.NewPublicKey(pub) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return SSHKey{ | ||
PrivateKey: g.privateKeyToPEM(priv), | ||
PublicKey: string(ssh.MarshalAuthorizedKey(sshPubKey)), | ||
PublicKeyFingerprint: g.fingerprintMD5(sshPubKey), | ||
}, nil | ||
} | ||
|
||
func (g SSHKeyGenerator) encodePEM(keyBytes []byte, keyType string) string { | ||
block := &pem.Block{ | ||
Type: keyType, | ||
Bytes: keyBytes, | ||
} | ||
|
||
return string(pem.EncodeToMemory(block)) | ||
} | ||
|
||
func (g SSHKeyGenerator) generateRSAKeyPair() (*rsa.PrivateKey, *rsa.PublicKey, error) { | ||
private, err := rsa.GenerateKey(rand.Reader, sshKeyGeneratorKeyBits) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
public := private.Public().(*rsa.PublicKey) | ||
return private, public, nil | ||
} | ||
|
||
func (g SSHKeyGenerator) privateKeyToPEM(privateKey *rsa.PrivateKey) string { | ||
return g.encodePEM(x509.MarshalPKCS1PrivateKey(privateKey), sshKeyGeneratorHeaderPrivateKey) | ||
} | ||
|
||
func (g SSHKeyGenerator) fingerprintMD5(key ssh.PublicKey) string { | ||
hash := md5.Sum(key.Marshal()) | ||
out := "" | ||
for i := 0; i < len(hash); i++ { | ||
if i > 0 { | ||
out += ":" | ||
} | ||
out += fmt.Sprintf("%02x", hash[i]) // don't forget the leading zeroes | ||
} | ||
return out | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package types_test | ||
|
||
import ( | ||
"crypto/x509" | ||
"encoding/json" | ||
"encoding/pem" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
"golang.org/x/crypto/ssh" | ||
"gopkg.in/yaml.v2" | ||
|
||
. "config_server/types" | ||
) | ||
|
||
var _ = FDescribe("SSHKeyGenerator", func() { | ||
var generator ValueGenerator | ||
|
||
BeforeEach(func() { | ||
generator = NewSSHKeyGenerator() | ||
}) | ||
|
||
Context("Generate", func() { | ||
It("generates an ssh key with 2048 bits", func() { | ||
sshKey, err := generator.Generate(nil) | ||
Expect(err).ToNot(HaveOccurred()) | ||
|
||
typedSSHKey := sshKey.(SSHKey) | ||
Expect(typedSSHKey.PrivateKey).To(ContainSubstring("PRIVATE KEY")) | ||
Expect(len(typedSSHKey.PublicKeyFingerprint)).To(Equal(47)) | ||
Expect(typedSSHKey.PublicKey).To(ContainSubstring("ssh-rsa ")) | ||
|
||
privBlock, _ := pem.Decode([]byte(typedSSHKey.PrivateKey)) | ||
|
||
privKey, err := x509.ParsePKCS1PrivateKey(privBlock.Bytes) | ||
Expect(err).ToNot(HaveOccurred()) | ||
|
||
pubKey, err := ssh.NewPublicKey(privKey.Public()) | ||
Expect(err).ToNot(HaveOccurred()) | ||
|
||
expectedPubKey := ssh.MarshalAuthorizedKey(pubKey) | ||
Expect(expectedPubKey).To(Equal([]byte(typedSSHKey.PublicKey))) | ||
}) | ||
|
||
It("serializes nicely in json/yaml", func() { | ||
sshKey, err := generator.Generate(nil) | ||
Expect(err).ToNot(HaveOccurred()) | ||
|
||
bytes, err := yaml.Marshal(sshKey) | ||
Expect(err).ToNot(HaveOccurred()) | ||
Expect(string(bytes)).To(ContainSubstring("private_key")) | ||
Expect(string(bytes)).To(ContainSubstring("public_key")) | ||
Expect(string(bytes)).To(ContainSubstring("public_key_fingerprint")) | ||
|
||
bytes, err = json.Marshal(sshKey) | ||
Expect(err).ToNot(HaveOccurred()) | ||
Expect(string(bytes)).To(ContainSubstring("private_key")) | ||
Expect(string(bytes)).To(ContainSubstring("public_key")) | ||
Expect(string(bytes)).To(ContainSubstring("public_key_fingerprint")) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package types_test | ||
|
||
import ( | ||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
"testing" | ||
) | ||
|
||
func TestReg(t *testing.T) { | ||
RegisterFailHandler(Fail) | ||
RunSpecs(t, "config_server/types") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters