aboutsummaryrefslogblamecommitdiff
path: root/private_key.go
blob: aa28e78e0a29482ec06b92b47910c3aef9b24348 (plain) (tree)
1
2
3
4
5
6
7
8
9


            
                         
                


             
                                

 




                              
     
                         


                                                                 













                                                                        
 
 





















                                                                                

                                                    


















































                                                                                                                    
                       
































                                                                                                                     

                                                                                
                                                              
















                                                                   
 


                                                                         



                                                                    
 









                                                    
 
package main

import (
	"crypto/elliptic"
	"errors"
	"fmt"
	"os"

	"github.com/gibheer/pki"
)

const (
	RsaLowerLength = 2048
	RsaUpperLength = 16384
)

var (
	// error messages
	ErrNoPKFound     = errors.New("no private key found")
	ErrNoPUFound     = errors.New("no public key found")
	ErrUnknownFormat = errors.New("key is an unknown format")

	// the possible ecdsa curves allowed to be used
	EcdsaCurves = []int{224, 256, 384, 521}

	// Command to create a private key
	CmdCreatePrivateKey = &Command{
		Use:     "create-private",
		Short:   "create a private key",
		Long:    "Create an ecdsa or rsa key with this command",
		Example: "create-private -type=ecdsa -length=521",
		Run:     create_private_key,
	}
	// private key specific stuff
	FlagPrivateKeyGeneration privateKeyGenerationFlags
)

type (
	// The flags specific to create a private key
	privateKeyGenerationFlags struct {
		Type  string         // type of the private key (rsa, ecdsa)
		Curve elliptic.Curve // curve for ecdsa
		Size  int            // bitsize for rsa
	}
)

// create a new private key
func create_private_key(cmd *Command, args []string) {
	err := checkFlags(checkOutput, checkPrivateKeyGeneration)
	if err != nil {
		crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err)
	}

	var pk pki.Pemmer
	switch FlagPrivateKeyGeneration.Type {
	case "ecdsa":
		pk, err = pki.NewPrivateKeyEcdsa(FlagPrivateKeyGeneration.Curve)
	case "rsa":
		pk, err = pki.NewPrivateKeyRsa(FlagPrivateKeyGeneration.Size)
	case "ed25519":
		pk, err = pki.NewPrivateKeyEd25519()
	default:
		crash_with_help(cmd, ErrorInput, "Unknown private key type '%s'", FlagPrivateKeyGeneration.Type)
	}
	if err != nil {
		crash_with_help(cmd, ErrorProgram, "Error creating private key: %s", err)
	}
	marsh_pem, err := pk.MarshalPem()
	if err != nil {
		crash_with_help(cmd, ErrorProgram, "Error when marshalling to pem: %s", err)
	}
	_, err = marsh_pem.WriteTo(FlagOutput)
	if err != nil {
		crash_with_help(cmd, ErrorProgram, "Error when writing output: %s", err)
	}
}

// This function adds the private key generation flags.
func InitFlagPrivateKeyGeneration(cmd *Command) {
	cmd.Flags().StringVar(&flagContainer.cryptType, "type", "ecdsa", "the type of the private key (ecdsa, rsa)")
	cmd.Flags().IntVar(
		&flagContainer.length,
		"length", 521,
		fmt.Sprintf("%d - %d for rsa; one of %v for ecdsa", RsaLowerLength, RsaUpperLength, EcdsaCurves),
	)
}

// check the private key generation variables and move them to the work space
func checkPrivateKeyGeneration() error {
	pk_type := flagContainer.cryptType
	FlagPrivateKeyGeneration.Type = pk_type
	switch pk_type {
	case "ecdsa":
		switch flagContainer.length {
		case 224:
			FlagPrivateKeyGeneration.Curve = elliptic.P224()
		case 256:
			FlagPrivateKeyGeneration.Curve = elliptic.P256()
		case 384:
			FlagPrivateKeyGeneration.Curve = elliptic.P384()
		case 521:
			FlagPrivateKeyGeneration.Curve = elliptic.P521()
		default:
			return fmt.Errorf("Curve %d unknown!", flagContainer.length)
		}
	case "rsa":
		size := flagContainer.length
		if RsaLowerLength <= size && size <= RsaUpperLength {
			FlagPrivateKeyGeneration.Size = size
		} else {
			return fmt.Errorf("Length of %d is not allowed for rsa!", size)
		}
	case "ed25519":
	default:
		return fmt.Errorf("Type %s is unknown!", pk_type)
	}
	return nil
}

// add the private key option to the requested flags
func InitFlagPrivateKey(cmd *Command) {
	cmd.Flags().StringVar(&flagContainer.privateKeyPath, "private-key", "", "path to the private key (required)")
}

// check the private key flag and load the private key
func checkPrivateKey() error {
	if flagContainer.privateKeyPath == "" {
		return fmt.Errorf("No private key given!")
	}
	// check permissions of private key file
	info, err := os.Stat(flagContainer.privateKeyPath)
	if err != nil {
		return fmt.Errorf("Error reading private key: %s", err)
	}
	if info.Mode().Perm().String()[4:] != "------" {
		return fmt.Errorf("private key file modifyable by others!")
	}

	pk, err := ReadPrivateKeyFile(flagContainer.privateKeyPath)
	if err != nil {
		return fmt.Errorf("Error reading private key: %s", err)
	}
	FlagPrivateKey = pk
	return nil
}

// Read the private key from the path and try to figure out which type of key it
// might be.
func ReadPrivateKeyFile(path string) (pki.PrivateKey, error) {
	raw_pk, err := readSectionFromFile(path, pki.PemLabelEcdsa)
	if err == nil {
		pk, err := pki.LoadPrivateKeyEcdsa(raw_pk)
		if err != nil {
			return nil, err
		}
		return pk, nil
	}
	raw_pk, err = readSectionFromFile(path, pki.PemLabelRsa)
	if err == nil {
		pk, err := pki.LoadPrivateKeyRsa(raw_pk)
		if err != nil {
			return nil, err
		}
		return pk, nil
	}
	return nil, ErrNoPKFound
}

// read the public key and try to figure out what kind of key it might be
func ReadPublicKeyFile(path string) (pki.PublicKey, error) {
	raw_pu, err := readSectionFromFile(path, pki.PemLabelPublic)
	if err != nil {
		return nil, ErrNoPUFound
	}

	var public pki.PublicKey
	public, err = pki.LoadPublicKeyEcdsa(raw_pu)
	if err == nil {
		return public, nil
	}
	public, err = pki.LoadPublicKeyRsa(raw_pu)
	if err == nil {
		return public, nil
	}
	return nil, ErrUnknownFormat
}