Added key generate

This commit is contained in:
Diogo Monica 2015-06-16 16:07:38 -07:00 committed by David Lawrence
parent a7164b638b
commit 08124c18f6
2 changed files with 105 additions and 0 deletions

View File

@ -1,16 +1,24 @@
package main
import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math"
"math/big"
"net/url"
"os"
"path/filepath"
"time"
"github.com/docker/vetinari/trustmanager"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var subjectKeyID string
@ -26,6 +34,7 @@ func init() {
cmdKeys.AddCommand(cmdKeysTrust)
cmdKeys.AddCommand(cmdKeysList)
cmdKeys.AddCommand(cmdKeysRemove)
cmdKeys.AddCommand(cmdKeysGenerate)
}
var cmdKeysList = &cobra.Command{
@ -49,6 +58,13 @@ var cmdKeysTrust = &cobra.Command{
Run: keysTrust,
}
var cmdKeysGenerate = &cobra.Command{
Use: "generate [ QDN ]",
Short: "Generates a new key for a specific QDN.",
Long: "generates a new key for a specific QDN. Qualified Docker Name.",
Run: keysGenerate,
}
func keysRemove(cmd *cobra.Command, args []string) {
if len(args) < 1 {
cmd.Usage()
@ -114,6 +130,91 @@ func keysList(cmd *cobra.Command, args []string) {
}
func keysGenerate(cmd *cobra.Command, args []string) {
if len(args) < 1 {
cmd.Usage()
fatalf("must specify a QDN")
}
// (diogo): Validate QDNs
qualifiedDN := args[0]
key, err := generateKey(qualifiedDN)
if err != nil {
fatalf("could not generate key: %v", err)
}
template := newCertificate(qualifiedDN, qualifiedDN)
derBytes, err := x509.CreateCertificate(rand.Reader, template, template, key.(crypto.Signer).Public(), key)
if err != nil {
fatalf("failed to generate certificate: %s", err)
}
certName := filepath.Join(viper.GetString("privDir"), qualifiedDN+".crt")
certOut, err := os.Create(certName)
if err != nil {
fatalf("failed to save certificate: %s", err)
}
defer certOut.Close()
err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
if err != nil {
fatalf("failed to save certificate: %s", err)
}
}
func newCertificate(qualifiedDN, organization string) *x509.Certificate {
notBefore := time.Now()
notAfter := notBefore.Add(time.Hour * 24 * 365 * 2)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
fatalf("failed to generate serial number: %s", err)
}
return &x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{organization},
CommonName: qualifiedDN,
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning},
BasicConstraintsValid: true,
}
}
func generateKey(qualifiedDN string) (crypto.PrivateKey, error) {
curve := elliptic.P384()
key, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
return nil, fmt.Errorf("could not generate private key: %v", err)
}
keyBytes, err := x509.MarshalECPrivateKey(key)
if err != nil {
return nil, fmt.Errorf("could not marshal private key: %v", err)
}
keyName := filepath.Join(viper.GetString("privDir"), qualifiedDN+".key")
keyOut, err := os.OpenFile(keyName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return nil, fmt.Errorf("could not write privatekey: %v", err)
}
defer keyOut.Close()
err = pem.Encode(keyOut, &pem.Block{Type: "EC PRIVATE KEY", Bytes: keyBytes})
if err != nil {
return nil, fmt.Errorf("failed to encode key: %v", err)
}
return key, nil
}
func printCert(cert *x509.Certificate) {
timeDifference := cert.NotAfter.Sub(time.Now())
subjectKeyID := trustmanager.FingerprintCert(cert)

View File

@ -17,6 +17,7 @@ import (
const configFileName string = "config"
const configPath string = ".docker/trust/"
const caDir string = ".docker/trust/certificate_authorities/"
const privDir string = ".docker/trust/private/"
var caStore trustmanager.X509Store
@ -49,12 +50,15 @@ func init() {
// Set up the defaults for our config
viper.SetDefault("caDir", path.Join(homeDir, path.Dir(caDir)))
viper.SetDefault("privDir", path.Join(homeDir, path.Dir(privDir)))
// Get the final value for the CA directory
finalcaDir := viper.GetString("caDir")
finalPrivDir := viper.GetString("privDir")
// Ensure the existence of the CAs directory
createDirectory(finalcaDir)
createDirectory(finalPrivDir)
// Load all CAs that aren't expired and don't use SHA1
// We could easily add "return cert.IsCA && cert.BasicConstraintsValid" in order