Browse Source

Imported New Keystore from rkt.

Reformating with go fmt
layerset
Till Wegmüller 5 years ago
parent
commit
0181fee489
  1. 39
      common/common.go
  2. 2
      daemons/installd.go
  3. 8
      image/build.go
  4. 6
      image/build_test.go
  5. 45
      image/config.go
  6. 8
      image/constants.go
  7. 20
      image/profile.go
  8. 1
      imaged/daemon.go
  9. 2
      installd/bootenv.go
  10. 32
      installd/config.go
  11. 2
      installd/copyfile.go
  12. 10
      installd/devfsadm.go
  13. 2
      installd/filesystem.go
  14. 4
      installd/http.go
  15. 6
      installd/system_dirs.go
  16. 6
      installd/system_links.go
  17. 151
      keystore/data_for_test.go
  18. 42
      keystore/entity.go
  19. 71
      keystore/keyring.go
  20. 409
      keystore/keystore.go
  21. 362
      keystore/keystore_test.go
  22. 131
      keystore/keystoretest/keygen/keygen.go
  23. 537
      keystore/keystoretest/keymap.go
  24. 50
      keystore/keystoretest/openpgp.go
  25. 112
      keystore/utils.go
  26. 32
      ldd/ldd.go
  27. 2
      main.go
  28. 36
      pod/host.go
  29. 6
      uname/command.go
  30. 8
      uname/constants.go

39
common/common.go

@ -7,6 +7,39 @@ import (
"os"
)
const (
sharedVolumesDir = "/sharedVolumes"
SharedVolumePerm = os.FileMode(0755)
stage1Dir = "/stage1"
stage2Dir = "/opt/stage2"
AppsInfoDir = "/appsinfo"
EnvLockFd = "POD_LOCK_FD"
Stage1TreeStoreIDFilename = "stage1TreeStoreID"
AppTreeStoreIDFilename = "treeStoreID"
OverlayPreparedFilename = "overlay-prepared"
PrivateUsersPreparedFilename = "private-users-prepared"
PrepareLock = "prepareLock"
MetadataServicePort = 18112
MetadataServiceRegSock = "/run/pod/metadata-svc.sock"
APIServiceListenAddr = "localhost:15441"
DefaultLocalConfigDir = "/etc/pod"
DefaultSystemConfigDir = "/lib/pod"
// Default perm bits for the regular files
// within the stage1 directory. (e.g. image manifest,
// pod manifest, stage1ID, etc).
DefaultRegularFilePerm = os.FileMode(0640)
// Default perm bits for the regular directories
// within the stage1 directory.
DefaultRegularDirPerm = os.FileMode(0750)
)
var (
Errlog *log.Logger
Stdlog *log.Logger
@ -48,13 +81,13 @@ func FileExists(path string) bool {
return true
}
func RemoveEmpties(xs *[]string){
func RemoveEmpties(xs *[]string) {
j := 0
for i, x := range *xs {
if x != ""{
if x != "" {
(*xs)[j] = (*xs)[i]
j++
}
}
*xs = (*xs)[:j]
}
}

2
daemons/installd.go

@ -28,7 +28,7 @@ func main() {
var err error
*confFile, err = installd.HTTPDownloadTo(*confFile, "")
util.Must(err)
} else if strings.HasPrefix(*confFile, "nfs"){
} else if strings.HasPrefix(*confFile, "nfs") {
panic(common.NotSupportedError("Nfs Downloads"))
}
file, err := ioutil.ReadFile(*confFile)

8
image/build.go

@ -46,7 +46,7 @@ func BuildACI(imageProfile *Profile, target string) (err error) {
gw := gzip.NewWriter(outFile)
tw := tar.NewWriter(gw)
aciW := aci.NewImageWriter(imageProfile.Manifest, tw)
defer func (){
defer func() {
if cerr := aciW.Close(); cerr != nil && err == nil {
err = cerr
}
@ -71,7 +71,7 @@ func BuildACI(imageProfile *Profile, target string) (err error) {
//We have a Symlink thus Create it on the Target
dstTarget, _ := os.Readlink(file)
th, err = tar.FileInfoHeader(fileStat, dstTarget)
if err != nil{
if err != nil {
return fmt.Errorf("could not create header for smylink %s: %s", file, err)
}
th.Name = filepath.Join("rootfs", file)
@ -79,12 +79,12 @@ func BuildACI(imageProfile *Profile, target string) (err error) {
return fmt.Errorf("adding symlink %s to archive failed %s", file, err)
}
default:
if _, staterr := fileObj.Read(make([]byte, 1, 1)); staterr != nil{
if _, staterr := fileObj.Read(make([]byte, 1, 1)); staterr != nil {
//Workaround for non regular files and funky filesystems
continue
}
th, err = tar.FileInfoHeader(fileStat, "")
if err != nil{
if err != nil {
return fmt.Errorf("can not read tar heder for regualr file %s: %s", file, err)
}
th.Name = filepath.Join("rootfs", file)

6
image/build_test.go

@ -34,7 +34,7 @@ func TestBuildACI(t *testing.T) {
}
func TestBuildChroot(t *testing.T) {
if os.Getuid() == 0{
if os.Getuid() == 0 {
profile, err := NewProfile("testing")
if err != nil {
t.Fatal(err)
@ -46,7 +46,7 @@ func TestBuildChroot(t *testing.T) {
}
}
func TestBuildProfile(t *testing.T){
func TestBuildProfile(t *testing.T) {
profile, err := LoadProfile("../samples/profile.json")
if err != nil {
t.Fatal(err)
@ -59,4 +59,4 @@ func TestBuildProfile(t *testing.T){
if err = BuildACI(profile, "/tmp/testing-full.aci"); err != nil {
t.Fatal(err)
}
}
}

45
image/config.go

@ -13,18 +13,19 @@ import (
"git.wegmueller.it/toasterson/uxfiletool"
)
var Default_path string = "/etc/imagedefs.json"
var tmp_transportvar_walkDir = []string{}
var Default_path = "/etc/imagedefs.json"
var tmp_transportvar_walkDir []string
//var Default_path string = "$HOME/.config/imagedefs.json"
func init() {
if strings.Contains(Default_path, "$"){
if strings.Contains(Default_path, "$") {
Default_path = os.ExpandEnv(Default_path)
}
}
func walkIntoTmpVar(path string, info os.FileInfo, err error) error{
if !info.IsDir(){
func walkIntoTmpVar(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
tmp_transportvar_walkDir = append(tmp_transportvar_walkDir, path)
}
return nil
@ -35,16 +36,16 @@ type Config struct {
}
type ConfigSection struct {
Name string `json:"name"`
Devices []string `json:"devices,omitempty"`
Users []string `json:"users,omitempty"`
Groups []string `json:"groups,omitempty"`
Comment string `json:"comment,omitempty"`
Paths []string `json:"paths,omitempty"`
Name string `json:"name"`
Devices []string `json:"devices,omitempty"`
Users []string `json:"users,omitempty"`
Groups []string `json:"groups,omitempty"`
Comment string `json:"comment,omitempty"`
Paths []string `json:"paths,omitempty"`
Dependencies []string `json:"dependencies,omitempty"`
}
func LoadConfiguration(path string) (conf Config, err error){
func LoadConfiguration(path string) (conf Config, err error) {
if path == "" {
path = Default_path
}
@ -70,28 +71,28 @@ func SaveConfigSection(section ConfigSection) error {
return ioutil.WriteFile(Default_path, confJson, 0644)
}
func (c Config)GetFiles(sections []string) []string{
files := []string{}
for _, section := range sections{
func (c Config) GetFiles(sections []string) []string {
var files []string
for _, section := range sections {
sectionObj := c.Sections[section]
glog.Debugf("Getting Files for %s", sectionObj.Name)
paths := c.GetAllFromSection(&sectionObj, "paths")
glog.Tracef("Found %v", paths)
for _, path := range paths{
for _, path := range paths {
if strings.Contains(path, "*") {
//Lets assume we have a Pattern to resolve
glog.Debugf("%s needs globbing", path)
found := uxfiletool.FindByGlob(path)
glog.Tracef("Found %v", found)
files = append(files, found...)
} else if strings.Contains(path, "/"){
} else if strings.Contains(path, "/") {
//A / in the path means the path needs to be full, thus add it if its a file and add dir contents
pStat, err := os.Lstat(path)
if err != nil {
glog.Warnf("%s can not be read ignoring", path)
continue
}
if pStat.Mode().IsDir(){
if pStat.Mode().IsDir() {
glog.Debugf("%s is a directory getting Files", path)
foundfiles := uxfiletool.FindAllIn(path, uxfiletool.FindTypeFile)
glog.Tracef("Found files: %v", foundfiles)
@ -106,7 +107,7 @@ func (c Config)GetFiles(sections []string) []string{
} else {
//Lastly assume be will find that binary/lib in PATH
glog.Debugf("Assuming you want me to resolve %s in Path", path)
if strings.Contains(path, "lib"){
if strings.Contains(path, "lib") {
libs := uxfiletool.FindLib(path)
glog.Tracef("Found: %v libs", libs)
files = append(files, libs...)
@ -122,7 +123,7 @@ func (c Config)GetFiles(sections []string) []string{
common.RemoveEmpties(&files)
//After we have resolved all the relativity lets grab the shared libs of the files
for _, file := range files {
if ldd.IsExecutableBinary(file){
if ldd.IsExecutableBinary(file) {
glog.Debugf("Getting shared libs of: %s", file)
libs := ldd.GetSharedLibraries(file, []string{})
glog.Tracef("Found: %v", libs)
@ -147,11 +148,11 @@ func (c Config) GetAllFromSection(section *ConfigSection, variable string) []str
case "paths":
retVal = section.Paths
}
for _, dep := range section.Dependencies{
for _, dep := range section.Dependencies {
subsec, ok := c.Sections[dep]
if ok {
retVal = append(retVal, c.GetAllFromSection(&subsec, variable)...)
}
}
return retVal
}
}

8
image/constants.go

@ -2,8 +2,8 @@ package image
const (
TypeChroot = "chroot"
TypeZfs = "zfs"
TypeUfs = "ufs"
TypeTar = "tar"
TypeACI = "aci"
TypeZfs = "zfs"
TypeUfs = "ufs"
TypeTar = "tar"
TypeACI = "aci"
)

20
image/profile.go

@ -30,13 +30,13 @@ func (t Type) Validate() error {
}
type Profile struct {
Type Type `json:"type"`
FileSets []string `json:"file_sets"`
Type Type `json:"type"`
FileSets []string `json:"file_sets"`
Manifest schema.ImageManifest `json:"manifest"`
Files []string `json:"files,omitempty"`
Users []string `json:"users,omitempty"`
Groups []string `json:"groups,omitempty"`
Devices []string `json:"devices,omitempty"`
Files []string `json:"files,omitempty"`
Users []string `json:"users,omitempty"`
Groups []string `json:"groups,omitempty"`
Devices []string `json:"devices,omitempty"`
}
func LoadProfile(file string) (*Profile, error) {
@ -48,7 +48,7 @@ func LoadProfile(file string) (*Profile, error) {
return &p, json.Unmarshal(buff, &p)
}
func (p Profile) ResolveFiles(config *Config){
func (p Profile) ResolveFiles(config *Config) {
p.Files = config.GetFiles(p.FileSets)
}
@ -63,10 +63,10 @@ func (p Profile) Save(dir string) error {
func NewProfile(name string) (p Profile, err error) {
p = Profile{
Type: TypeChroot,
Type: TypeChroot,
Manifest: schema.ImageManifest{ACKind: schema.ImageManifestKind, ACVersion: schema.AppContainerVersion},
}
if name != ""{
if name != "" {
ident, err := types.NewACIdentifier(name)
if err != nil {
return p, err
@ -74,4 +74,4 @@ func NewProfile(name string) (p Profile, err error) {
p.Manifest.Name = *ident
}
return
}
}

1
imaged/daemon.go

@ -14,7 +14,6 @@ const (
)
type Imaged struct {
}
func (i *Imaged) List(pool string, reply *[]string) (err error) {

2
installd/bootenv.go

@ -1,6 +1,6 @@
package installd
func GetPathOfBootEnv(name string) (path string){
func GetPathOfBootEnv(name string) (path string) {
//TODO get Path via beadm
return name
}

32
installd/config.go

@ -10,24 +10,24 @@ const (
)
const (
InstallTypeBootEnv = "bootenv"
InstallTypeFullDisk = "fulldisk"
InstallTypeBootEnv = "bootenv"
InstallTypeFullDisk = "fulldisk"
InstallTypeEFIFullDisk = "efifulldisk"
)
type InstallConfiguration struct {
InstallType string `json:"install_type"` //Possible options are efi, bootenv, fulldisk, efifulldisk
RootFSType string `json:"root_fs_type"` //ufs, zfs
Disks []string `json:"disks"` //The Disks that shall be used
MediaType string `json:"media_type"` //Valid Values are SolNetboot, SolCdrom, SolUSB, IPS, ZAP, ZImage
UseBootEnvironments bool `json:"use_boot_environments:"` //Whether to use boot environments or not
ZFSLayout interface{} `json:"zfs_layout"` //The Partition Layout for ZFS. e.g Where is /var /etc and others located
PoolArgs map[string]string `json:"pool_args"` //Enable things like compression etc.
PoolType string `json:"pool_type"` //The Type of pool eg mirrored, raidz, single(default)
RPoolName string `json:"rpool_name"` //Name of the root pool
MediaURL string `json:"media_url"` //The URL the media can be found at. uses install_media if ommitted
BEName string `json:"be_name"` //Name of the new Boot Environment defaults to openindiana
SwapSize string `json:"swap_size"` //Size of the SWAP Partition defaults to 2g
DumpSize string `json:"dump_size"` //Size of the Dump Partition defaults to swap_size
BootLoader string `json:"boot_loader"` //Valid values are Loader and Grub
InstallType string `json:"install_type"` //Possible options are efi, bootenv, fulldisk, efifulldisk
RootFSType string `json:"root_fs_type"` //ufs, zfs
Disks []string `json:"disks"` //The Disks that shall be used
MediaType string `json:"media_type"` //Valid Values are SolNetboot, SolCdrom, SolUSB, IPS, ZAP, ZImage
UseBootEnvironments bool `json:"use_boot_environments:"` //Whether to use boot environments or not
ZFSLayout interface{} `json:"zfs_layout"` //The Partition Layout for ZFS. e.g Where is /var /etc and others located
PoolArgs map[string]string `json:"pool_args"` //Enable things like compression etc.
PoolType string `json:"pool_type"` //The Type of pool eg mirrored, raidz, single(default)
RPoolName string `json:"rpool_name"` //Name of the root pool
MediaURL string `json:"media_url"` //The URL the media can be found at. uses install_media if ommitted
BEName string `json:"be_name"` //Name of the new Boot Environment defaults to openindiana
SwapSize string `json:"swap_size"` //Size of the SWAP Partition defaults to 2g
DumpSize string `json:"dump_size"` //Size of the Dump Partition defaults to swap_size
BootLoader string `json:"boot_loader"` //Valid values are Loader and Grub
}

2
installd/copyfile.go

@ -54,4 +54,4 @@ func copyFileExact(source string, srcInfo os.FileInfo, dest string) {
util.Must(syscall.Chmod(dest, srcStat.Mode))
util.Must(syscall.Chown(dest, int(srcStat.Uid), int(srcStat.Gid)))
//util.Must(os.Chtimes(dest, time.Unix(int64(srcStat.Atim.Sec),int64(srcStat.Atim.Nsec)), time.Unix(int64(srcStat.Mtim.Sec),int64(srcStat.Mtim.Nsec))))
}
}

10
installd/devfsadm.go

@ -4,14 +4,14 @@ package installd
import "os/exec"
var devfsadm_bin string = "/usr/sbin/devfsadm"
var devfsadm_bin = "/usr/sbin/devfsadm"
func CreateDeviceLinks(root string, device_classes []string) (err error){
args := []string{}
if root != ""{
func CreateDeviceLinks(root string, device_classes []string) (err error) {
var args []string
if root != "" {
args = append(args, "-r", root)
}
for _, dev_class := range device_classes{
for _, dev_class := range device_classes {
args = append(args, "-c", dev_class)
}
devfsadm := exec.Command(devfsadm_bin, args...)

2
installd/filesystem.go

@ -47,4 +47,4 @@ func CreateDatasets(conf *InstallConfiguration) {
}
rpool := zpool.OpenPool(conf.RPoolName)
err = rpool.SetProperty("bootfs", fmt.Sprintf("%s/ROOT/%s", conf.RPoolName, conf.BEName))
}
}

4
installd/http.go

@ -16,7 +16,7 @@ func HTTPDownload(url string, location string) (err error) {
return doDownload(req).Err()
}
func HTTPDownloadTo(url string, location string) (file string, err error){
func HTTPDownloadTo(url string, location string) (file string, err error) {
if location == "" {
location = "/tmp/"
}
@ -25,7 +25,7 @@ func HTTPDownloadTo(url string, location string) (file string, err error){
return resp.Filename, resp.Err()
}
func doDownload(request *grab.Request) (resp *grab.Response){
func doDownload(request *grab.Request) (resp *grab.Response) {
client := grab.NewClient()
// start download
logger.Info(fmt.Sprintf("Downloading %v...", request.URL()))

6
installd/system_dirs.go

@ -13,8 +13,8 @@ import (
)
type DirConfig struct {
Name string
Mode int
Name string
Mode int
Owner string
Group string
}
@ -45,7 +45,7 @@ var defualtDirectories = []DirConfig{
{Name: "dev/zcons", Group: "sys"},
}
func MakeSystemDirectories(rootDir string, dirs []DirConfig){
func MakeSystemDirectories(rootDir string, dirs []DirConfig) {
dirs = append(dirs, defualtDirectories...)
for _, dir := range dirs {
path := fmt.Sprintf("%s/%s", rootDir, dir.Name)

6
installd/system_links.go

@ -10,7 +10,7 @@ import (
)
type LinkConfig struct {
Name string
Name string
Target string
}
@ -21,13 +21,13 @@ var defaultLinks = []LinkConfig{
{Name: "dld", Target: "../devices/pseudo/dld@0:ctl"},
}
func MakeDeviceLinks(rootDir string, links []LinkConfig){
func MakeDeviceLinks(rootDir string, links []LinkConfig) {
links = append(links, defaultLinks...)
for _, link := range links {
path := fmt.Sprintf("%s/dev/%s", rootDir, link.Name)
logger.Trace(fmt.Sprintf("Creating Special Link %s -> %s", path, link.Target))
err := os.Symlink(link.Target, path)
if err != nil{
if err != nil {
logger.Error(err)
}
}

151
keystore/data_for_test.go

@ -1,151 +0,0 @@
package keystore
import (
"fmt"
"io/ioutil"
"os"
)
var sampleKeys = []string{
// 3ofcoins.net provisional key
`-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2
mQENBFVnXGIBCADovl1Yw/Ftjz7QZ9qVEUmJ9ztduws50yk+RbY+R1UJQvLhWU10
izORyN1qrXTYrQKoiJDJ9eTc7WHqrJGsNrgZWGc5SvMTdfVtiRdfaKP5QrIgXI5/
EZwZjRgi3ty/hsq2RvpNkvC5cXp4sSYf63dEFFLD4Ps3G+Lc4adKyNn8gZSieHjv
0+aizg7DW+mqNxUy3NK5wkRo876EYbhVpGCZRxPq39p88wqb6j1Rkt68jNtMOWkA
euoCxfeXR9jbU7ArNFxmhg6/ND7Zq60PAC5aImBLolXXMAK62cBPJBTZulNXSNxF
iZZBtFl5COyQNHSwbZUOv4jdrOiwE894qC8NABEBAAG0MkFDSSAzb2Zjb2lucy5u
ZXQgKHByb3Zpc2lvbmFsKSA8aW5mb0Azb2Zjb2lucy5uZXQ+iQE3BBMBCAAhBQJV
Z1xiAhsDBQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEFPMwtY6FiZkYXEIAJiM
bGvBOIrjIKhW0y6syRIGuypkJw7dhp9EvMwzsvMLM86ze7iX2gNaBOGKWMdIRAYH
gKLN+f65ZOviOY5yy6fMG5A9ySlSWIKiLPDX6X/pXwMhmSUBkwhWKUWXIHd0+3d4
lGUWzzimTFfjWNlPWbHb08HMepMuNtCxtKkxvRgpH0yaWNCHQe3NsWAh6nYLsXpJ
A/2lomQ9K/qhHyZT18eYD1lHCpEOPksqifv5BKAFpXekGsFjTbYIKj6bgspaMg+d
GHMg3KUnCulgzhhbo0bMyMqrHm8waSF/JabTiIqp/ePFiUWqeirBdZ8yje6TA9eS
7UMOx+veKUT6Y5axbPaJARsEEAEIAAYFAlVnXLYACgkQRjqg8fR27d7nsAf3cxHv
Q+ljIyTqzxHDCgMmMLFPd8zzZ6cBTUYgb8R2G8EjYVg5Qu9zwv3FOZWaY19hBYDP
AzXjQtjkdQiwGvOppgui4CmnjJpNlyPd5J2A06fyeg2F28WJacrxUdTre1/UwN+c
9UUJo9o3OluVbaq1o9rXJnau79HOqWDoh8VdTzZAd3VO4SXuI7GUP49j6NC1t8FO
I7Qe0TLHzkZDeiZmVlK5OhfwhzMBQ5Qjv/9iT47Od91ryXKrHNAICyT32K4zawc0
/xs0oAQb5MOE4HrxW46e8UCT+2u+GrtS5ftWQqAMqnBF9oiRpSfXis3XgFyP5nU6
+ZaUESTObMoZyZ67uQENBFVnXGIBCADE19yLRCcO0NNBvDxWVFdFLsDKzl7vAQWm
cjaWBPJi0pWbi+vppECSjf8S5NNUXqx8MObG4i+ivBR4dqPbVls7Lpzn9wt3MwPZ
RbCLPLvBPJtlYtIt76JlqcjuJws3kd5hmX/1gny8Vy9RoNWt4y1ldde4+mJXGHoW
OY3CHj1vagkRE445czYT+ST8xeSxLKAyAEHis3U6Gb80uHbRknt/bUaogbibrl9N
3MyRX56cctVqpY8bJTi1PDKpSNcUHT+LMQ6rpPc2anKVqoUHT9Ye6hLSvNeBwJHs
LLWEWNRfmjjZvHs4hfzzaUVT0bP2IMkMBpxMCAOEargaJYhD1olFABEBAAGJAR8E
GAEIAAkFAlVnXGICGwwACgkQU8zC1joWJmTROAgA4RBWZww5CaBZ2ZbBijNRK8sa
swUrdxxcAkRzki2Z5KpBXESZEe6iPZt/rsGNw0F2XaORP+DRrzTGg+DSQlh5nT2z
LFVkNyeW3RJQjP2K2avikjRgoprryr/WVUOTpk4jK/MpBxUU0Htpvks2Jly2vYJD
Z9R2yW31RLEJXcVxOR/LcW6UfkjhOsH/RbKbcMx+HraxKk7jmrKZEglz8cO0BMGc
gemHpMb04W4YXOdKjqppm0kS+TDTEm85xnfAe14olr3ZsHn/ey8nc3JEb3aCBeuC
PjkMkIAW7BYX1ZKyV9z5EQVkqkz7zwyZYO1/tmdjQQH/x+mD0MwpeIF0E78YhA==
=m9io
-----END PGP PUBLIC KEY BLOCK-----
`,
// quay.io signing key
`-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2
mQENBFTT6doBCACkVncI+t4HASQdnByRlXCYkwjsPqGOlgTCgenop5I6vgTqFWhQ
PMNhtSaFdFECMt2WKQT4QGVbfVOmIH9CLV+Muqvk4iJIAn3Nh3qp/kfMhwjGaS6m
fWN2ARFCq4RIs9tboCNQOouaD5C26/FsQtIsoqyYcdX+YFaU1a+R1kp0fc2CABDI
k6Iq8oEJO+FOYvqQYIJNfd3c0NHICilMu2jO3yIsw80qzWoFAAblyb0zVq/hudWB
4vdVzPmJe1f4Ymk8l1R413bN65LcbCiOax3hmFWovJoxlkL7WoGTTMfaeb2QmaPL
qcu4Q94v1KG87gyxbkIo5uZdvMLdswQI7yQ7ABEBAAG0RFF1YXkuaW8gQUNJIENv
bnZlcnRlciAoQUNJIGNvbnZlcnNpb24gc2lnbmluZyBrZXkpIDxzdXBwb3J0QHF1
YXkuaW8+iQE5BBMBAgAjBQJU0+naAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgEC
F4AACgkQcqv19nmdM7zKzggAjGFqy7Hcx6TCFXn53/inl5iyKrTu8cuF4K547XuZ
12Dt8b6PgJ+b3z6UnMMTd0wXKGcfOmNeQ2R71xmVnviuo7xB5ZkZIBxHI4M/5uhK
I6GZKr84WJS2ec7ssH2ofFQ5u1l+es9jUwW0KbAoNmES0IcdDy28xfmJpkfOn3oI
P2Bzz4rGlIqJXEjq28Wk+qQu64kJRKYuPNXqiHncPDm+i5jMXUUN1D+pkDukp26x
oLbpol42/jIcM3fe2AFZnflittBCHYLIHjJ51NlpSHJZmf2pQZbdyeKElN2SCNe7
nDcol24zYIC+SX0K23w/LrLzlff4mzbO99ePt1bB9zAiVA==
=SBoV
-----END PGP PUBLIC KEY BLOCK-----
`,
// coreos.com/etcd
`-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
mQINBFTCnMQBEAC/49bGbStCpa3peej+/42mobfuGbTcdmcGGwYZmigP0Kl0TPZK
zcIxhVZOr3ITYuAx8T1WWJVb7/r/y4roUogDrUSTm2nAbLP8xp8Qn/N1zaXFyEtJ
WTaLuPI2mq643x8g7fAiJY19JRjFbYVVZLr5OMOvHrOdtYVN31ARZeSxmqP5yFNW
9DgoXG0/w80EOXIsWWoJgjaKLye15LHI86MjPthXyT5K212efxPffSk1hca04Dmk
I5vCMHC1Q2DbrlilhS0DTf+lSK2YgkaHPWiNSZb3XvjwbU8qQMzyfnQcQrQlfm4/
1fHLj2bWyASzNG/MOJCQ2JyEyIzbS2M4jKcfFxaKKuJA5PwdfjbRTkvxAKbFcdc5
ER7D3QoEOxgRDMppHaihKNI/T4dPIuqyUczq3ia9fGfrQFROAIxdAnBqzzBVaetv
FYFVjJlAhGsWWEhuO3P7qGwwR7CtPkWvvsMT8CYdHP2h7uOrOZioGCQ+09YBGpJ9
LzwCKHiV2s4/aBVfLhjttGqXG+PW/Kzg5rtwAjSdeooThKQLQk/ok1TtFydgNVNH
kSPNdhgiTWlNmK8Qj3C1zqZmcPzv+c6y6f79GTL0+Hz6gqnMGdIpFJtmbusU79/2
MkDqumBAslvwm7h85s0ccKwZCG1VelyhGLawVyxin0UhLWlzYd6SL5IuuQARAQAB
tCdDb3JlT1MgQUNJIEJ1aWxkZXIgPHJlbGVhc2VAY29yZW9zLmNvbT6JAjgEEwEC
ACIFAlTCnMQCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEFIQvYiIGCGQ
nxYP+wcVClXD1t5oT7mwvYZPfF9/+itOSHvN6++T4CCFkRVdIN7/G/Ou1wRb/fV+
P27Rc7gnK+jbQJqUa8aEsNSWZT/1A8VaQ51orQdV80ZROzrJPLBB0w4fkEsSESO+
Uuz9ZsiEOhZf0ATkafrF1jfepGXmoHJxLJ+bKS+KlAEhtceB1jiWAafGPy99XUAf
MBJ905F6bXvDqQov+9U3vyUGnwA6ymCCqKIoCVx3GdKOh5UaqC8pHaF7oI7xkv5b
5WMajzuXwKBy6KoduHTnW7Y5g1aoGwW5FDFoEq4LsBvcxeUI6OMVEWCVe502E+4S
lWx2gEvFa33wy77kYp2ZvHToY5tSjiIi8QocR0IgfLqE3P1ZMPe9YXk5EveEZH6Q
VtQ8z1ktuZCVQqrtTEeernEdSFsTVFSoWUsNJV1FMlgisZZ0ljoFJrH7/7GkYhK9
DT7OcrZnyZDUkEIiVaqWwjWw5Ing4IHExAq+PlXDwrA0QcH2UW9IurDCvPiXHpxi
D0V21oEbANUdGtYcOSDRBbZlsonINJZQ1Ad2XrY8kfZ2sZXAZuBZbH0+dEx6zmua
C0IGN3SLFseScqJZ5G1joYYqOKOUweErkzA/62Kaj31SVoQDpZyMqtwTjjZaFT8N
fMkBtaM3knaFonHZc19BD1FOishRThCCq2Ty8HUoN2Fk7w0l
=bYl7
-----END PGP PUBLIC KEY BLOCK-----`,
}
var sampleKeyFingerprints = []string{
"4706dc5d5c214bc3ad127c6d53ccc2d63a162664",
"bff313cdaa560b16a8987b8f72abf5f6799d33bc",
"8b86de38890ddb7291867b025210bd8888182190",
}
func asFile(args ...interface{}) (_ *os.File, erv error) {
if f, err := ioutil.TempFile("", "jetpack.test.keystore."); err != nil {
return nil, err
} else {
defer func() {
if erv != nil {
f.Close()
}
}()
if err := os.Remove(f.Name()); err != nil {
return nil, err
}
if _, err := fmt.Fprint(f, args...); err != nil {
return nil, err
}
if _, err := f.Seek(0, 0); err != nil {
return nil, err
}
return f, nil
}
}
var openedSampleKeys = make(map[int]*os.File)
func openSampleKey(i int) *os.File {
if f := openedSampleKeys[i]; f != nil {
if _, err := f.Seek(0, 0); err != nil {
panic(err)
}
return f
}
if f, err := asFile(sampleKeys[i]); err != nil {
panic(err)
} else {
openedSampleKeys[i] = f
return f
}
}
func closeSampleKeys() {
for i, f := range openedSampleKeys {
f.Close()
delete(openedSampleKeys, i)
}
}

42
keystore/entity.go

@ -1,42 +0,0 @@
package keystore
import (
"fmt"
"path/filepath"
"sort"
"strings"
"github.com/appc/spec/schema/types"
"golang.org/x/crypto/openpgp"
)
type Entity struct {
*openpgp.Entity
Path string
Prefix types.ACIdentifier
}
func (e *Entity) Fingerprint() string {
return filepath.Base(e.Path)
}
func (e *Entity) String() string {
identities := make([]string, 0, len(e.Entity.Identities))
for name := range e.Entity.Identities {
identities = append(identities, name)
}
sort.Strings(identities)
return fmt.Sprintf("%v\t%v\t%v", e.Prefix, e.Fingerprint(), strings.Join(identities, "; "))
}
type EntityList []Entity
// sort.Interface
func (ee EntityList) Len() int { return len(ee) }
func (ee EntityList) Less(i, j int) bool {
if ee[i].Prefix == ee[j].Prefix {
return ee[i].Path < ee[j].Path
}
return ee[i].Prefix.String() < ee[j].Prefix.String()
}
func (ee EntityList) Swap(i, j int) { ee[i], ee[j] = ee[j], ee[i] }

71
keystore/keyring.go

@ -1,71 +0,0 @@
package keystore
import (
"fmt"
"os"
"path/filepath"
"github.com/appc/spec/schema/types"
"golang.org/x/crypto/openpgp"
)
type Keyring struct {
openpgp.EntityList
paths []string
prefixes []types.ACIdentifier
}
func (kr *Keyring) loadFile(path string) error {
trustedKey, err := os.Open(path)
if err != nil {
return err
}
defer trustedKey.Close()
entityList, err := openpgp.ReadArmoredKeyRing(trustedKey)
if err != nil {
return err
}
if len(entityList) < 1 {
return fmt.Errorf("missing opengpg entity")
}
fingerprint := fingerprintToFilename(entityList[0].PrimaryKey.Fingerprint)
keyFile := filepath.Base(trustedKey.Name())
if fingerprint != keyFile {
return fmt.Errorf("fingerprint mismatch: %q:%q", keyFile, fingerprint)
}
prefix, err := pathToACIdentifier(path)
if err != nil {
return err
}
kr.EntityList = append(kr.EntityList, entityList[0])
kr.paths = append(kr.paths, path)
kr.prefixes = append(kr.prefixes, prefix)
return nil
}
func (kr *Keyring) Entities() EntityList {
rv := make(EntityList, len(kr.EntityList))
for i, e := range kr.EntityList {
rv[i] = Entity{e, kr.paths[i], kr.prefixes[i]}
}
return rv
}
// sort.Interface - sort by prefix, then by path
func (kr *Keyring) Len() int { return len(kr.EntityList) }
func (kr *Keyring) Less(i, j int) bool {
if kr.prefixes[i] == kr.prefixes[j] {
return kr.paths[i] < kr.paths[j]
}
return kr.prefixes[i].String() < kr.prefixes[j].String()
}
func (kr *Keyring) Swap(i, j int) {
kr.EntityList[i], kr.EntityList[j] = kr.EntityList[j], kr.EntityList[i]
kr.paths[i], kr.paths[j] = kr.paths[j], kr.paths[i]
kr.prefixes[i], kr.prefixes[j] = kr.prefixes[j], kr.prefixes[i]
}

409
keystore/keystore.go

@ -1,153 +1,390 @@
package keystore
// Heavily based on https://github.com/coreos/rkt/blob/master/pkg/keystore/keystore.go
// Copyright 2014 The rkt Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// We don't use rkt's keystore, because we want to escape ACIdentifier to
// avoid path traversal issues and not to worry about prefix
// collisions.
// Package keystore implements the ACI keystore.
package keystore
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"golang.org/x/crypto/openpgp"
"git.wegmueller.it/opencloud/opencloud/common"
"github.com/appc/spec/schema/types"
"golang.org/x/crypto/openpgp"
)
// Intentionally invalid ACIdentifier to mark root key
const Root = types.ACIdentifier("@")
// A Config structure is used to configure a Keystore.
type Config struct {
LocalRootPath string
LocalPrefixPath string
SystemRootPath string
SystemPrefixPath string
}
// A Keystore represents a repository of trusted public keys which can be
// used to verify PGP signatures.
type Keystore struct {
Path string
*Config
}
func New(path string) *Keystore {
return &Keystore{path}
// New returns a new Keystore based on config.
func New(config *Config) *Keystore {
if config == nil {
config = defaultConfig
}
return &Keystore{config}
}
func (ks *Keystore) prefixPath(prefix types.ACIdentifier) string {
if prefix.Empty() {
panic("Empty prefix!")
func NewConfig(systemPath, localPath string) *Config {
return &Config{
LocalRootPath: filepath.Join(localPath, "trustedkeys", "root.d"),
LocalPrefixPath: filepath.Join(localPath, "trustedkeys", "prefix.d"),
SystemRootPath: filepath.Join(systemPath, "trustedkeys", "root.d"),
SystemPrefixPath: filepath.Join(systemPath, "trustedkeys", "prefix.d"),
}
return filepath.Join(ks.Path, strings.Replace(string(prefix), "/", ",", -1))
}
func (ks *Keystore) StoreTrustedKey(prefix types.ACIdentifier, key *os.File, acceptFingerprint string) (string, error) {
if prefix.Empty() {
panic("Empty prefix!")
var defaultConfig = NewConfig(common.DefaultSystemConfigDir, common.DefaultLocalConfigDir)
// CheckSignature is a convenience method for creating a Keystore with a default
// configuration and invoking CheckSignature.
func CheckSignature(prefix string, signed, signature io.ReadSeeker) (*openpgp.Entity, error) {
ks := New(defaultConfig)
return checkSignature(ks, prefix, signed, signature)
}
// CheckSignature takes a signed file and a detached signature and returns the signer
// if the signature is signed by a trusted signer.
// If the signer is unknown or not trusted, opengpg.ErrUnknownIssuer is returned.
func (ks *Keystore) CheckSignature(prefix string, signed, signature io.ReadSeeker) (*openpgp.Entity, error) {
return checkSignature(ks, prefix, signed, signature)
}
func checkSignature(ks *Keystore, prefix string, signed, signature io.ReadSeeker) (*openpgp.Entity, error) {
acidentifier, err := types.NewACIdentifier(prefix)
if err != nil {
return nil, err
}
keyring, err := ks.loadKeyring(acidentifier.String())
if err != nil {
return nil, fmt.Errorf("keystore: error loading keyring: %s", err)
}
entities, err := openpgp.CheckArmoredDetachedSignature(keyring, signed, signature)
if err == io.EOF {
// When the signature is binary instead of armored, the error is io.EOF.
// Let's try with binary signatures as well
if _, err := signed.Seek(0, 0); err != nil {
return nil, fmt.Errorf("error seeking ACI file: %s", err)
}
if _, err := signature.Seek(0, 0); err != nil {
return nil, fmt.Errorf("error seeking signature file: %s", err)
}
entities, err = openpgp.CheckDetachedSignature(keyring, signed, signature)
}
if err == io.EOF {
// otherwise, the client failure is just "EOF", which is not helpful
return nil, fmt.Errorf("keystore: no valid signatures found in signature file")
}
return entities, err
}
if accepted, err := reviewKey(prefix, key, acceptFingerprint); err != nil {
return "", err
} else if !accepted {
return "", nil
// DeleteTrustedKeyPrefix deletes the prefix trusted key identified by fingerprint.
func (ks *Keystore) DeleteTrustedKeyPrefix(prefix, fingerprint string) error {
acidentifier, err := types.NewACIdentifier(prefix)
if err != nil {
return err
}
return os.Remove(path.Join(ks.LocalPrefixPath, acidentifier.String(), fingerprint))
}
pubkeyBytes, err := ioutil.ReadAll(key)
// MaskTrustedKeySystemPrefix masks the system prefix trusted key identified by fingerprint.
func (ks *Keystore) MaskTrustedKeySystemPrefix(prefix, fingerprint string) (string, error) {
acidentifier, err := types.NewACIdentifier(prefix)
if err != nil {
return "", err
}
dir := ks.prefixPath(prefix)
if err := os.MkdirAll(dir, 0750); err != nil {
dst := path.Join(ks.LocalPrefixPath, acidentifier.String(), fingerprint)
if err := ioutil.WriteFile(dst, []byte(""), 0644); err != nil {
return "", err
}
entityList, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(pubkeyBytes))
if err != nil {
if err := os.Chmod(dst, 0644); err != nil {
return "", err
}
return dst, nil
}
// FIXME: cargo cult from rkt
// FIXME: can we import more than one key here, and note only one?
// Maybe we should split and re-armor the entityList?
trustedKeyPath := filepath.Join(dir, fingerprintToFilename(entityList[0].PrimaryKey.Fingerprint))
// DeleteTrustedKeyRoot deletes the root trusted key identified by fingerprint.
func (ks *Keystore) DeleteTrustedKeyRoot(fingerprint string) error {
return os.Remove(path.Join(ks.LocalRootPath, fingerprint))
}
if err := ioutil.WriteFile(trustedKeyPath, pubkeyBytes, 0640); err != nil {
// MaskTrustedKeySystemRoot masks the system root trusted key identified by fingerprint.
func (ks *Keystore) MaskTrustedKeySystemRoot(fingerprint string) (string, error) {
dst := path.Join(ks.LocalRootPath, fingerprint)
if err := ioutil.WriteFile(dst, []byte(""), 0644); err != nil {
return "", err
}
return trustedKeyPath, nil
if err := os.Chmod(dst, 0644); err != nil {
return "", err
}
return dst, nil
}
func (ks *Keystore) UntrustKey(fingerprint string) (removed []types.ACIdentifier, err error) {
err = ks.walk("", func(prefix types.ACIdentifier, path string) error {
if filepath.Base(path) == fingerprint {
if err := os.Remove(path); err != nil {
return err
// TrustKeyPrefixExists returns whether or not there exists 1 or more trusted
// keys for a given prefix, or for any parent prefix.
func (ks *Keystore) TrustedKeyPrefixExists(prefix string) (bool, error) {
acidentifier, err := types.NewACIdentifier(prefix)
if err != nil {
return false, err
}
pathNamesPrefix := []string{
// example: /etc/rkt/trustedkeys/prefix.d/coreos.com/etcd
path.Join(ks.LocalPrefixPath, acidentifier.String()),
// example: /usr/lib/rkt/trustedkeys/prefix.d/coreos.com/etcd
path.Join(ks.SystemPrefixPath, acidentifier.String()),
}
for _, p := range pathNamesPrefix {
_, err := os.Stat(p)
if os.IsNotExist(err) {
continue
}
if err != nil {
return false, fmt.Errorf("cannot check dir %q: %s", p, err)
}
files, err := ioutil.ReadDir(p)
if err != nil {
return false, fmt.Errorf("cannot list files in dir %q: %s", p, err)
}
for _, f := range files {
if !f.IsDir() && f.Size() > 0 {
return true, nil
}
removed = append(removed, prefix)
}
return nil
})
return
}
parentPrefix, _ := path.Split(prefix)
parentPrefix = strings.Trim(parentPrefix, "/")
if parentPrefix != "" {
return ks.TrustedKeyPrefixExists(parentPrefix)
}
return false, nil
}
func (ks *Keystore) walk(name types.ACIdentifier, fn func(prefix types.ACIdentifier, path string) error) error {
var namePath string
if !name.Empty() {
namePath = ks.prefixPath(name)
// TrustedKeyPrefixWithFingerprintExists returns whether or not a trusted key with the fingerprint of the key accessible through r exists for the given prefix.
func (ks *Keystore) TrustedKeyPrefixWithFingerprintExists(prefix string, r io.ReadSeeker) (bool, error) {
defer r.Seek(0, io.SeekStart)
entityList, err := openpgp.ReadArmoredKeyRing(r)
if err != nil {
return false, err
}
if len(entityList) < 1 {
return false, errors.New("missing opengpg entity")
}
pubKey := entityList[0].PrimaryKey
fileName := fingerprintToFilename(pubKey.Fingerprint)
pathNamesRoot := []string{
// example: /etc/rkt/trustedkeys/root.d/8b86de38890ddb7291867b025210bd8888182190
path.Join(ks.LocalRootPath, fileName),
// example: /usr/lib/rkt/trustedkeys/root.d/8b86de38890ddb7291867b025210bd8888182190
path.Join(ks.SystemRootPath, fileName),
}
return filepath.Walk(ks.Path, func(path string, fi os.FileInfo, err error) error {
if err != nil && !os.IsNotExist(err) {
return err
var pathNamesPrefix []string
if prefix != "" {
acidentifier, err := types.NewACIdentifier(prefix)
if err != nil {
return false, err
}
if fi == nil {
return nil
pathNamesPrefix = []string{
// example: /etc/rkt/trustedkeys/prefix.d/coreos.com/etcd/8b86de38890ddb7291867b025210bd8888182190
path.Join(ks.LocalPrefixPath, acidentifier.String(), fileName),
// example: /usr/lib/rkt/trustedkeys/prefix.d/coreos.com/etcd/8b86de38890ddb7291867b025210bd8888182190
path.Join(ks.SystemPrefixPath, acidentifier.String(), fileName),
}
}
if fi.IsDir() {
if namePath == "" || strings.HasPrefix(namePath, path) || fi.Name() == "@" {
return nil
} else {
return filepath.SkipDir
}
pathNames := append(pathNamesRoot, pathNamesPrefix...)
for _, p := range pathNames {
_, err := os.Stat(p)
if err == nil {
return true, nil
} else if !os.IsNotExist(err) {
return false, fmt.Errorf("cannot check file %q: %s", p, err)
}
}
if prefix, err := pathToACIdentifier(path); err != nil {
return err
} else {
return fn(prefix, path)
}
})
return false, nil
}
func walkLoaderFn(kr *Keyring) func(types.ACIdentifier, string) error {
return func(_ types.ACIdentifier, path string) error {
return kr.loadFile(path)
// StoreTrustedKeyPrefix stores the contents of public key r as a prefix trusted key.
func (ks *Keystore) StoreTrustedKeyPrefix(prefix string, r io.Reader) (string, error) {
acidentifier, err := types.NewACIdentifier(prefix)
if err != nil {
return "", err
}
return storeTrustedKey(path.Join(ks.LocalPrefixPath, acidentifier.String()), r)
}
func (ks *Keystore) GetAllKeys() (*Keyring, error) {
kr := &Keyring{}
if err := ks.walk("", walkLoaderFn(kr)); err != nil {
return nil, err
// StoreTrustedKeyRoot stores the contents of public key r as a root trusted key.
func (ks *Keystore) StoreTrustedKeyRoot(r io.Reader) (string, error) {
return storeTrustedKey(ks.LocalRootPath, r)
}
func storeTrustedKey(dir string, r io.Reader) (string, error) {
pubkeyBytes, err := ioutil.ReadAll(r)
if err != nil {
return "", err
}
if err := os.MkdirAll(dir, 0755); err != nil {
return "", err
}
if err := os.Chmod(dir, 0755); err != nil {
return "", err
}
return kr, nil
entityList, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(pubkeyBytes))
if err != nil {
return "", err
}
if len(entityList) < 1 {
return "", errors.New("missing opengpg entity")
}
pubKey := entityList[0].PrimaryKey
trustedKeyPath := path.Join(dir, fingerprintToFilename(pubKey.Fingerprint))
if err := ioutil.WriteFile(trustedKeyPath, pubkeyBytes, 0644); err != nil {
return "", err
}
if err := os.Chmod(trustedKeyPath, 0644); err != nil {
return "", err
}
return trustedKeyPath, nil
}
func (ks *Keystore) GetKeysFor(name types.ACIdentifier) (*Keyring, error) {
kr := &Keyring{}
if err := ks.walk(name, walkLoaderFn(kr)); err != nil {
func entityFromFile(path string) (*openpgp.Entity, error) {
trustedKey, err := os.Open(path)
if err != nil {
return nil, err
}
defer trustedKey.Close()
entityList, err := openpgp.ReadArmoredKeyRing(trustedKey)
if err != nil {
return nil, err
}
return kr, nil
if len(entityList) < 1 {
return nil, errors.New("missing opengpg entity")
}
fingerprint := fingerprintToFilename(entityList[0].PrimaryKey.Fingerprint)
keyFile := filepath.Base(trustedKey.Name())
if fingerprint != keyFile {
return nil, fmt.Errorf("fingerprint mismatch: %q:%q", keyFile, fingerprint)
}
return entityList[0], nil
}
func (ks *Keystore) CheckSignature(name types.ACIdentifier, signed, signature io.Reader) (*openpgp.Entity, error) {
kr, err := ks.GetKeysFor(name)
func (ks *Keystore) loadKeyring(prefix string) (openpgp.KeyRing, error) {
acidentifier, err := types.NewACIdentifier(prefix)
if err != nil {
return nil, err
}
entities, err := openpgp.CheckArmoredDetachedSignature(kr, signed, signature)
if err == io.EOF {
err = fmt.Errorf("no signatures found")
var keyring openpgp.EntityList
trustedKeys := make(map[string]*openpgp.Entity)
prefixRoot := strings.Split(acidentifier.String(), "/")[0]
paths := []struct {
root string
fullPath string
}{
{ks.SystemRootPath, ks.SystemRootPath},
{ks.LocalRootPath, ks.LocalRootPath},
{path.Join(ks.SystemPrefixPath, prefixRoot), path.Join(ks.SystemPrefixPath, acidentifier.String())},
{path.Join(ks.LocalPrefixPath, prefixRoot), path.Join(ks.LocalPrefixPath, acidentifier.String())},
}
return entities, err
for _, p := range paths {
err := filepath.Walk(p.root, func(path string, info os.FileInfo, err error) error {
if err != nil && !os.IsNotExist(err) {
return err
}
if info == nil {
return nil
}
if info.IsDir() {
switch {
case strings.HasPrefix(p.fullPath, path):
return nil
default:
return filepath.SkipDir
}
}
// Remove trust for default keys.
if info.Size() == 0 {
delete(trustedKeys, info.Name())
return nil
}
entity, err := entityFromFile(path)
if err != nil {
return err
}
trustedKeys[fingerprintToFilename(entity.PrimaryKey.Fingerprint)] = entity
return nil
})
if err != nil {
return nil, err
}
}
for _, v := range trustedKeys {
keyring = append(keyring, v)
}
return keyring, nil
}
func fingerprintToFilename(fp [20]byte) string {
return fmt.Sprintf("%x", fp)
}
// NewTestKeystore creates a new KeyStore backed by a temp directory.
// NewTestKeystore returns a KeyStore, the path to the temp directory, and
// an error if any.
func NewTestKeystore() (*Keystore, string, error) {
dir, err := ioutil.TempDir("", "keystore-test")
if err != nil {
return nil, "", err
}
systemDir := filepath.Join(dir, common.DefaultSystemConfigDir)
localDir := filepath.Join(dir, common.DefaultLocalConfigDir)
c := NewConfig(systemDir, localDir)
for _, localPath := range []string{c.LocalRootPath, c.SystemRootPath, c.LocalPrefixPath, c.SystemPrefixPath} {
if err := os.MkdirAll(localPath, 0755); err != nil {
return nil, "", err
}
if err := os.Chmod(dir, 0755); err != nil {
return nil, "", err
}
}
return New(c), dir, nil
}

362
keystore/keystore_test.go

@ -1,273 +1,185 @@
// Copyright 2014 The rkt Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The keystore tests require opengpg keys from the keystoretest package (keystoretest.KeyMap).
// The opengpg keys are auto generated by running the keygen.go command.
// keygen.go should not be run by an automated process. keygen.go is a helper to generate
// the keystoretest/keymap.go source file.
//
// If additional opengpg keys are need for testing, please use the following process:
// * add a new key name to keygen.go
// * cd keystore/keystoretest
// * go run keygen.go
// * check in the results
package keystore
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"sort"
"testing"
"github.com/appc/spec/schema/types"
"git.wegmueller.it/opencloud/opencloud/keystore/keystoretest"
"golang.org/x/crypto/openpgp/errors"
)
func newStore() *Keystore {
storePath, err := ioutil.TempDir(".", "test.store.")
func TestStoreTrustedKey(t *testing.T) {
ks, ksPath, err := NewTestKeystore()
if err != nil {
panic(err)
t.Errorf("unexpected error %v", err)
}
defer os.RemoveAll(ksPath)
return New(storePath)
}
armoredPublicKey := keystoretest.KeyMap["example.com"].ArmoredPublicKey
fingerprint := keystoretest.KeyMap["example.com"].Fingerprint
func testImport(t *testing.T, prefix types.ACIdentifier, subdir string) {
// Redirect stdout (how to DRY?)
origStdout := os.Stdout
defer func() { os.Stdout = origStdout }()
if devnull, err := os.Create("/dev/null"); err != nil {
panic(err)
} else {
os.Stdout = devnull
defer devnull.Close()
output, err := ks.StoreTrustedKeyPrefix("example.com/foo", bytes.NewBufferString(armoredPublicKey