@@ -2,12 +2,19 @@ package main
22
33import (
44 "bufio"
5+ "crypto/ecdsa"
6+ "crypto/elliptic"
7+ "crypto/rand"
8+ "crypto/rsa"
9+ "crypto/x509"
10+ "encoding/pem"
511 "fmt"
612 "github.com/aws/aws-sdk-go/aws"
713 "github.com/aws/aws-sdk-go/aws/ec2metadata"
814 "github.com/aws/aws-sdk-go/aws/session"
915 "github.com/aws/aws-sdk-go/service/kms"
1016 "github.com/codegangsta/cli"
17+ "golang.org/x/crypto/ssh"
1118 "io/ioutil"
1219 "os"
1320)
@@ -24,30 +31,113 @@ func encryptFlags() []cli.Flag {
2431 Value : "ca-key.kms" ,
2532 Usage : "The filename for key output" ,
2633 },
34+ cli.BoolFlag {
35+ Name : "generate-ecdsa" ,
36+ Usage : "When set generate an ECDSA key from Curve P384" ,
37+ },
38+ cli.BoolFlag {
39+ Name : "generate-rsa" ,
40+ Usage : "When set generate a 4096 bit RSA key" ,
41+ },
42+ }
43+ }
44+
45+ func generateRsa () ([]byte , error ) {
46+ key , err := rsa .GenerateKey (rand .Reader , 4096 )
47+ if err != nil {
48+ return nil , err
49+ }
50+ derBlock := x509 .MarshalPKCS1PrivateKey (key )
51+ pemBlock := & pem.Block {
52+ Type : "RSA PRIVATE KEY" ,
53+ Bytes : derBlock ,
54+ }
55+ return pem .EncodeToMemory (pemBlock ), nil
56+ }
57+
58+ func generateEcdsa () ([]byte , error ) {
59+ key , err := ecdsa .GenerateKey (elliptic .P384 (), rand .Reader )
60+ if err != nil {
61+ return nil , err
62+ }
63+ derBlock , err := x509 .MarshalECPrivateKey (key )
64+ if err != nil {
65+ return nil , err
66+ }
67+ pemBlock := & pem.Block {
68+ Type : "EC PRIVATE KEY" ,
69+ Bytes : derBlock ,
2770 }
71+ return pem .EncodeToMemory (pemBlock ), nil
2872}
2973
30- func encryptKey (c * cli.Context ) {
74+ func cmdEncryptKey (c * cli.Context ) {
3175 region , err := ec2metadata .New (session .New (), aws .NewConfig ()).Region ()
3276 if err != nil {
3377 fmt .Printf ("Unable to determine our region: %s" , err )
3478 os .Exit (1 )
3579 }
80+ keyId := c .String ("key-id" )
81+
82+ var ciphertext []byte
83+ if c .Bool ("generate-ecdsa" ) || c .Bool ("generate-rsa" ) {
84+ var key []byte
85+ if c .Bool ("generate-ecdsa" ) {
86+ key , err = generateEcdsa ()
87+ } else {
88+ key , err = generateRsa ()
89+ }
90+ if err != nil {
91+ fmt .Printf ("Unable to generate key: %s" , err )
92+ os .Exit (1 )
93+ }
94+ ciphertext , err = encryptKey (key , region , keyId )
95+ if err != nil {
96+ fmt .Printf ("Unable to generate ecdsa key: %s" , err )
97+ os .Exit (1 )
98+ }
99+ signer , err := ssh .ParsePrivateKey (key )
100+ if err != nil {
101+ fmt .Printf ("Unable to parse generated private key: %s" , err )
102+ os .Exit (1 )
103+ }
104+ err = ioutil .WriteFile (c .String ("output" )+ ".pub" , ssh .MarshalAuthorizedKey (signer .PublicKey ()), 0644 )
105+ if err != nil {
106+ fmt .Printf ("Unable to write new public key: %s" , err )
107+ os .Exit (1 )
108+ }
109+ } else {
110+ ciphertext , err = encryptKeyFromStdin (keyId , region )
111+ if err != nil {
112+ fmt .Printf ("Failed to encrypt key: %s" , err )
113+ os .Exit (1 )
114+ }
115+ }
116+ err = ioutil .WriteFile (c .String ("output" ), ciphertext , 0644 )
117+ if err != nil {
118+ fmt .Printf ("Unable to write new encrypted private key: %s" , err )
119+ os .Exit (1 )
120+ }
121+ }
122+
123+ func encryptKeyFromStdin (keyId , region string ) ([]byte , error ) {
36124 keyContents , err := ioutil .ReadAll (bufio .NewReader (os .Stdin ))
37125 if err != nil {
38126 fmt .Printf ("Unable to read private key: %s" , err )
39127 os .Exit (1 )
40128 }
129+ return encryptKey (keyContents , region , keyId )
130+ }
131+
132+ func encryptKey (plaintextKey []byte , region , kmsKeyId string ) ([]byte , error ) {
41133 svc := kms .New (session .New (), aws .NewConfig ().WithRegion (region ))
42134 params := & kms.EncryptInput {
43- Plaintext : keyContents ,
44- KeyId : aws .String (c . String ( "key-id" ) ),
135+ Plaintext : plaintextKey ,
136+ KeyId : aws .String (kmsKeyId ),
45137 }
46138 resp , err := svc .Encrypt (params )
47139 if err != nil {
48- fmt .Printf ("Unable to Encrypt CA key: %v\n " , err )
49- os .Exit (1 )
140+ return nil , fmt .Errorf ("Unable to Encrypt CA key: %v\n " , err )
50141 }
51- keyContents = resp .CiphertextBlob
52- ioutil .WriteFile (c .String ("output" ), resp .CiphertextBlob , 0444 )
142+ return []byte (resp .CiphertextBlob ), nil
53143}
0 commit comments