github.com/tompreston/snapd@v0.0.0-20210817193607-954edfcb9611/cmd/snap/keymgr.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2021 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package main
    21  
    22  import (
    23  	"errors"
    24  	"fmt"
    25  	"os"
    26  
    27  	"golang.org/x/crypto/ssh/terminal"
    28  
    29  	"github.com/snapcore/snapd/asserts"
    30  	"github.com/snapcore/snapd/i18n"
    31  )
    32  
    33  type KeypairManager interface {
    34  	asserts.KeypairManager
    35  
    36  	GetByName(keyNname string) (asserts.PrivateKey, error)
    37  	Export(keyName string) ([]byte, error)
    38  	List() ([]asserts.ExternalKeyInfo, error)
    39  	Delete(keyName string) error
    40  }
    41  
    42  func getKeypairManager() (KeypairManager, error) {
    43  	keymgrPath := os.Getenv("SNAPD_EXT_KEYMGR")
    44  	if keymgrPath != "" {
    45  		keypairMgr, err := asserts.NewExternalKeypairManager(keymgrPath)
    46  		if err != nil {
    47  			return nil, fmt.Errorf(i18n.G("cannot setup external keypair manager: %v"), err)
    48  		}
    49  		return keypairMgr, nil
    50  	}
    51  	keypairMgr := asserts.NewGPGKeypairManager()
    52  	return keypairMgr, nil
    53  }
    54  
    55  type takingPassKeyGen interface {
    56  	Generate(passphrase string, keyName string) error
    57  }
    58  
    59  type ownSecuringKeyGen interface {
    60  	Generate(keyName string) error
    61  }
    62  
    63  func generateKey(keypairMgr KeypairManager, keyName string) error {
    64  	switch keyGen := keypairMgr.(type) {
    65  	case takingPassKeyGen:
    66  		return takePassGenKey(keyGen, keyName)
    67  	case ownSecuringKeyGen:
    68  		err := keyGen.Generate(keyName)
    69  		if _, ok := err.(*asserts.ExternalUnsupportedOpError); ok {
    70  			return fmt.Errorf(i18n.G("cannot generate external keypair manager key via snap command, use the appropriate external procedure to create a 4096-bit RSA key under the name/label %q"), keyName)
    71  		}
    72  		return err
    73  	default:
    74  		return fmt.Errorf("internal error: unsupported keypair manager %T", keypairMgr)
    75  	}
    76  }
    77  
    78  func takePassGenKey(keyGen takingPassKeyGen, keyName string) error {
    79  	fmt.Fprint(Stdout, i18n.G("Passphrase: "))
    80  	passphrase, err := terminal.ReadPassword(0)
    81  	fmt.Fprint(Stdout, "\n")
    82  	if err != nil {
    83  		return err
    84  	}
    85  	fmt.Fprint(Stdout, i18n.G("Confirm passphrase: "))
    86  	confirmPassphrase, err := terminal.ReadPassword(0)
    87  	fmt.Fprint(Stdout, "\n")
    88  	if err != nil {
    89  		return err
    90  	}
    91  	if string(passphrase) != string(confirmPassphrase) {
    92  		return errors.New(i18n.G("passphrases do not match"))
    93  	}
    94  
    95  	return keyGen.Generate(string(passphrase), keyName)
    96  }