mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 13:50:01 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			256 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			256 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package libtrust
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"encoding/pem"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"os"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	// ErrKeyFileDoesNotExist indicates that the private key file does not exist.
 | |
| 	ErrKeyFileDoesNotExist = errors.New("key file does not exist")
 | |
| )
 | |
| 
 | |
| func readKeyFileBytes(filename string) ([]byte, error) {
 | |
| 	data, err := ioutil.ReadFile(filename)
 | |
| 	if err != nil {
 | |
| 		if os.IsNotExist(err) {
 | |
| 			err = ErrKeyFileDoesNotExist
 | |
| 		} else {
 | |
| 			err = fmt.Errorf("unable to read key file %s: %s", filename, err)
 | |
| 		}
 | |
| 
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return data, nil
 | |
| }
 | |
| 
 | |
| /*
 | |
| 	Loading and Saving of Public and Private Keys in either PEM or JWK format.
 | |
| */
 | |
| 
 | |
| // LoadKeyFile opens the given filename and attempts to read a Private Key
 | |
| // encoded in either PEM or JWK format (if .json or .jwk file extension).
 | |
| func LoadKeyFile(filename string) (PrivateKey, error) {
 | |
| 	contents, err := readKeyFileBytes(filename)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	var key PrivateKey
 | |
| 
 | |
| 	if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") {
 | |
| 		key, err = UnmarshalPrivateKeyJWK(contents)
 | |
| 		if err != nil {
 | |
| 			return nil, fmt.Errorf("unable to decode private key JWK: %s", err)
 | |
| 		}
 | |
| 	} else {
 | |
| 		key, err = UnmarshalPrivateKeyPEM(contents)
 | |
| 		if err != nil {
 | |
| 			return nil, fmt.Errorf("unable to decode private key PEM: %s", err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return key, nil
 | |
| }
 | |
| 
 | |
| // LoadPublicKeyFile opens the given filename and attempts to read a Public Key
 | |
| // encoded in either PEM or JWK format (if .json or .jwk file extension).
 | |
| func LoadPublicKeyFile(filename string) (PublicKey, error) {
 | |
| 	contents, err := readKeyFileBytes(filename)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	var key PublicKey
 | |
| 
 | |
| 	if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") {
 | |
| 		key, err = UnmarshalPublicKeyJWK(contents)
 | |
| 		if err != nil {
 | |
| 			return nil, fmt.Errorf("unable to decode public key JWK: %s", err)
 | |
| 		}
 | |
| 	} else {
 | |
| 		key, err = UnmarshalPublicKeyPEM(contents)
 | |
| 		if err != nil {
 | |
| 			return nil, fmt.Errorf("unable to decode public key PEM: %s", err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return key, nil
 | |
| }
 | |
| 
 | |
| // SaveKey saves the given key to a file using the provided filename.
 | |
| // This process will overwrite any existing file at the provided location.
 | |
| func SaveKey(filename string, key PrivateKey) error {
 | |
| 	var encodedKey []byte
 | |
| 	var err error
 | |
| 
 | |
| 	if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") {
 | |
| 		// Encode in JSON Web Key format.
 | |
| 		encodedKey, err = json.MarshalIndent(key, "", "    ")
 | |
| 		if err != nil {
 | |
| 			return fmt.Errorf("unable to encode private key JWK: %s", err)
 | |
| 		}
 | |
| 	} else {
 | |
| 		// Encode in PEM format.
 | |
| 		pemBlock, err := key.PEMBlock()
 | |
| 		if err != nil {
 | |
| 			return fmt.Errorf("unable to encode private key PEM: %s", err)
 | |
| 		}
 | |
| 		encodedKey = pem.EncodeToMemory(pemBlock)
 | |
| 	}
 | |
| 
 | |
| 	err = ioutil.WriteFile(filename, encodedKey, os.FileMode(0600))
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("unable to write private key file %s: %s", filename, err)
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // SavePublicKey saves the given public key to the file.
 | |
| func SavePublicKey(filename string, key PublicKey) error {
 | |
| 	var encodedKey []byte
 | |
| 	var err error
 | |
| 
 | |
| 	if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") {
 | |
| 		// Encode in JSON Web Key format.
 | |
| 		encodedKey, err = json.MarshalIndent(key, "", "    ")
 | |
| 		if err != nil {
 | |
| 			return fmt.Errorf("unable to encode public key JWK: %s", err)
 | |
| 		}
 | |
| 	} else {
 | |
| 		// Encode in PEM format.
 | |
| 		pemBlock, err := key.PEMBlock()
 | |
| 		if err != nil {
 | |
| 			return fmt.Errorf("unable to encode public key PEM: %s", err)
 | |
| 		}
 | |
| 		encodedKey = pem.EncodeToMemory(pemBlock)
 | |
| 	}
 | |
| 
 | |
| 	err = ioutil.WriteFile(filename, encodedKey, os.FileMode(0644))
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("unable to write public key file %s: %s", filename, err)
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Public Key Set files
 | |
| 
 | |
| type jwkSet struct {
 | |
| 	Keys []json.RawMessage `json:"keys"`
 | |
| }
 | |
| 
 | |
| // LoadKeySetFile loads a key set
 | |
| func LoadKeySetFile(filename string) ([]PublicKey, error) {
 | |
| 	if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") {
 | |
| 		return loadJSONKeySetFile(filename)
 | |
| 	}
 | |
| 
 | |
| 	// Must be a PEM format file
 | |
| 	return loadPEMKeySetFile(filename)
 | |
| }
 | |
| 
 | |
| func loadJSONKeySetRaw(data []byte) ([]json.RawMessage, error) {
 | |
| 	if len(data) == 0 {
 | |
| 		// This is okay, just return an empty slice.
 | |
| 		return []json.RawMessage{}, nil
 | |
| 	}
 | |
| 
 | |
| 	keySet := jwkSet{}
 | |
| 
 | |
| 	err := json.Unmarshal(data, &keySet)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("unable to decode JSON Web Key Set: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	return keySet.Keys, nil
 | |
| }
 | |
| 
 | |
| func loadJSONKeySetFile(filename string) ([]PublicKey, error) {
 | |
| 	contents, err := readKeyFileBytes(filename)
 | |
| 	if err != nil && err != ErrKeyFileDoesNotExist {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return UnmarshalPublicKeyJWKSet(contents)
 | |
| }
 | |
| 
 | |
| func loadPEMKeySetFile(filename string) ([]PublicKey, error) {
 | |
| 	data, err := readKeyFileBytes(filename)
 | |
| 	if err != nil && err != ErrKeyFileDoesNotExist {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return UnmarshalPublicKeyPEMBundle(data)
 | |
| }
 | |
| 
 | |
| // AddKeySetFile adds a key to a key set
 | |
| func AddKeySetFile(filename string, key PublicKey) error {
 | |
| 	if strings.HasSuffix(filename, ".json") || strings.HasSuffix(filename, ".jwk") {
 | |
| 		return addKeySetJSONFile(filename, key)
 | |
| 	}
 | |
| 
 | |
| 	// Must be a PEM format file
 | |
| 	return addKeySetPEMFile(filename, key)
 | |
| }
 | |
| 
 | |
| func addKeySetJSONFile(filename string, key PublicKey) error {
 | |
| 	encodedKey, err := json.Marshal(key)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("unable to encode trusted client key: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	contents, err := readKeyFileBytes(filename)
 | |
| 	if err != nil && err != ErrKeyFileDoesNotExist {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	rawEntries, err := loadJSONKeySetRaw(contents)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	rawEntries = append(rawEntries, json.RawMessage(encodedKey))
 | |
| 	entriesWrapper := jwkSet{Keys: rawEntries}
 | |
| 
 | |
| 	encodedEntries, err := json.MarshalIndent(entriesWrapper, "", "    ")
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("unable to encode trusted client keys: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	err = ioutil.WriteFile(filename, encodedEntries, os.FileMode(0644))
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("unable to write trusted client keys file %s: %s", filename, err)
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func addKeySetPEMFile(filename string, key PublicKey) error {
 | |
| 	// Encode to PEM, open file for appending, write PEM.
 | |
| 	file, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_RDWR, os.FileMode(0644))
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("unable to open trusted client keys file %s: %s", filename, err)
 | |
| 	}
 | |
| 	defer file.Close()
 | |
| 
 | |
| 	pemBlock, err := key.PEMBlock()
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("unable to encoded trusted key: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	_, err = file.Write(pem.EncodeToMemory(pemBlock))
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("unable to write trusted keys file: %s", err)
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 |