func main() { // Generate client key. clientKey, err := libtrust.GenerateECP256PrivateKey() if err != nil { log.Fatal(err) } // Add a comment for the client key. clientKey.AddExtendedField("comment", "TLS Demo Client") // Save the client key, public and private versions. err = libtrust.SaveKey("client_data/private_key.pem", clientKey) if err != nil { log.Fatal(err) } err = libtrust.SavePublicKey("client_data/public_key.pem", clientKey.PublicKey()) if err != nil { log.Fatal(err) } // Generate server key. serverKey, err := libtrust.GenerateECP256PrivateKey() if err != nil { log.Fatal(err) } // Set the list of addresses to use for the server. serverKey.AddExtendedField("hosts", []string{"localhost", "docker.example.com"}) // Save the server key, public and private versions. err = libtrust.SaveKey("server_data/private_key.pem", serverKey) if err != nil { log.Fatal(err) } err = libtrust.SavePublicKey("server_data/public_key.pem", serverKey.PublicKey()) if err != nil { log.Fatal(err) } // Generate Authorized Keys file for server. err = libtrust.AddKeySetFile("server_data/trusted_clients.pem", clientKey.PublicKey()) if err != nil { log.Fatal(err) } // Generate Known Host Keys file for client. err = libtrust.AddKeySetFile("client_data/trusted_hosts.pem", serverKey.PublicKey()) if err != nil { log.Fatal(err) } }
func newTestEnvWithConfig(t *testing.T, config *configuration.Configuration) *testEnv { ctx := context.Background() app := NewApp(ctx, *config) server := httptest.NewServer(handlers.CombinedLoggingHandler(os.Stderr, app)) builder, err := v2.NewURLBuilderFromString(server.URL + config.HTTP.Prefix) if err != nil { t.Fatalf("error creating url builder: %v", err) } pk, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatalf("unexpected error generating private key: %v", err) } return &testEnv{ pk: pk, ctx: ctx, config: *config, app: app, server: server, builder: builder, } }
func (s *DockerDaemonSuite) TestDaemonKeyMigration(c *check.C) { // TODO: skip or update for Windows daemon os.Remove("/etc/docker/key.json") k1, err := libtrust.GenerateECP256PrivateKey() if err != nil { c.Fatalf("Error generating private key: %s", err) } if err := os.MkdirAll(filepath.Join(os.Getenv("HOME"), ".docker"), 0755); err != nil { c.Fatalf("Error creating .docker directory: %s", err) } if err := libtrust.SaveKey(filepath.Join(os.Getenv("HOME"), ".docker", "key.json"), k1); err != nil { c.Fatalf("Error saving private key: %s", err) } if err := s.d.Start(); err != nil { c.Fatalf("Could not start daemon: %v", err) } s.d.Stop() k2, err := libtrust.LoadKeyFile("/etc/docker/key.json") if err != nil { c.Fatalf("Error opening key file") } if k1.KeyID() != k2.KeyID() { c.Fatalf("Key not migrated") } }
func TestManifestStorageDisabledSignatures(t *testing.T) { k, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatal(err) } testManifestStorage(t, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect, DisableSchema1Signatures, Schema1SigningKey(k)) }
func newRandomSchemaV1Manifest(name reference.Named, tag string, blobCount int) (*schema1.SignedManifest, digest.Digest, []byte) { blobs := make([]schema1.FSLayer, blobCount) history := make([]schema1.History, blobCount) for i := 0; i < blobCount; i++ { dgst, blob := newRandomBlob((i % 5) * 16) blobs[i] = schema1.FSLayer{BlobSum: dgst} history[i] = schema1.History{V1Compatibility: fmt.Sprintf("{\"Hex\": \"%x\"}", blob)} } m := schema1.Manifest{ Name: name.String(), Tag: tag, Architecture: "x86", FSLayers: blobs, History: history, Versioned: manifest.Versioned{ SchemaVersion: 1, }, } pk, err := libtrust.GenerateECP256PrivateKey() if err != nil { panic(err) } sm, err := schema1.Sign(&m, pk) if err != nil { panic(err) } return sm, digest.FromBytes(sm.Canonical), sm.Canonical }
func genEnv(t *testing.T) *testEnv { pk, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatalf("error generating test key: %v", err) } name, tag := "foo/bar", "test" m := Manifest{ Versioned: SchemaVersion, Name: name, Tag: tag, FSLayers: []FSLayer{ { BlobSum: "asdf", }, { BlobSum: "qwer", }, }, } sm, err := Sign(&m, pk) if err != nil { t.Fatalf("error signing manifest: %v", err) } return &testEnv{ name: name, tag: tag, manifest: &m, signed: sm, pk: pk, } }
func makeSigningKeyWithChain(rootKey libtrust.PrivateKey, depth int) (libtrust.PrivateKey, error) { if depth == 0 { // Don't need to build a chain. return rootKey, nil } var ( x5c = make([]string, depth) parentKey = rootKey key libtrust.PrivateKey cert *x509.Certificate err error ) for depth > 0 { if key, err = libtrust.GenerateECP256PrivateKey(); err != nil { return nil, err } if cert, err = libtrust.GenerateCACert(parentKey, key); err != nil { return nil, err } depth-- x5c[depth] = base64.StdEncoding.EncodeToString(cert.Raw) parentKey = key } key.AddExtendedField("x5c", x5c) return key, nil }
// MakeSchema1Manifest constructs a schema 1 manifest from a given list of digests and returns // the digest of the manifest func MakeSchema1Manifest(digests []digest.Digest) (distribution.Manifest, error) { manifest := schema1.Manifest{ Versioned: manifest.Versioned{ SchemaVersion: 1, }, Name: "who", Tag: "cares", } for _, digest := range digests { manifest.FSLayers = append(manifest.FSLayers, schema1.FSLayer{BlobSum: digest}) manifest.History = append(manifest.History, schema1.History{V1Compatibility: ""}) } pk, err := libtrust.GenerateECP256PrivateKey() if err != nil { return nil, fmt.Errorf("unexpected error generating private key: %v", err) } signedManifest, err := schema1.Sign(&manifest, pk) if err != nil { return nil, fmt.Errorf("error signing manifest: %v", err) } return signedManifest, nil }
func genEnv(t *testing.T) *testEnv { pk, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatalf("error generating test key: %v", err) } name, tag := "foo/bar", "test" invalid := Manifest{ Versioned: SchemaVersion, Name: name, Tag: tag, FSLayers: []FSLayer{ { BlobSum: "asdf", }, { BlobSum: "qwer", }, }, } valid := Manifest{ Versioned: SchemaVersion, Name: name, Tag: tag, FSLayers: []FSLayer{ { BlobSum: "asdf", }, }, History: []History{ { V1Compatibility: "", }, }, } sm, err := Sign(&valid, pk) if err != nil { t.Fatalf("error signing manifest: %v", err) } invalidSigned, err := Sign(&invalid, pk) if err != nil { t.Fatalf("error signing manifest: %v", err) } return &testEnv{ name: name, tag: tag, invalidSigned: invalidSigned, signed: sm, pk: pk, } }
func main() { if pk, err := trust.GenerateECP256PrivateKey(); err != nil { fmt.Printf("error generating private key: %s\n", err.Error()) } else { if buf, err := pk.MarshalJSON(); err != nil { fmt.Printf("error marshalling private key: %s\n", err.Error()) } else { io.Copy(os.Stdout, bytes.NewReader(buf)) } } }
func populateRepo(t *testing.T, ctx context.Context, repository distribution.Repository, name, tag string) (digest.Digest, error) { m := schema1.Manifest{ Versioned: manifest.Versioned{ SchemaVersion: 1, }, Name: name, Tag: tag, } for i := 0; i < 2; i++ { wr, err := repository.Blobs(ctx).Create(ctx) if err != nil { t.Fatalf("unexpected error creating test upload: %v", err) } rs, ts, err := testutil.CreateRandomTarFile() if err != nil { t.Fatalf("unexpected error generating test layer file") } dgst := digest.Digest(ts) if _, err := io.Copy(wr, rs); err != nil { t.Fatalf("unexpected error copying to upload: %v", err) } if _, err := wr.Commit(ctx, distribution.Descriptor{Digest: dgst}); err != nil { t.Fatalf("unexpected error finishing upload: %v", err) } } pk, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatalf("unexpected error generating private key: %v", err) } sm, err := schema1.Sign(&m, pk) if err != nil { t.Fatalf("error signing manifest: %v", err) } ms, err := repository.Manifests(ctx) if err != nil { t.Fatalf(err.Error()) } ms.Put(sm) if err != nil { t.Fatalf("unexpected errors putting manifest: %v", err) } pl, err := sm.Payload() if err != nil { t.Fatal(err) } return digest.FromBytes(pl) }
// TestRunDetach checks attaching and detaching with the escape sequence. func TestRunDetach(t *testing.T) { stdout, stdoutPipe := io.Pipe() cpty, tty, err := pty.Open() if err != nil { t.Fatal(err) } key, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatal(err) } cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, key, testDaemonProto, testDaemonAddr, nil) defer cleanup(globalEngine, t) ch := make(chan struct{}) go func() { defer close(ch) cli.CmdRun("-i", "-t", unitTestImageID, "cat") }() container := waitContainerStart(t, 10*time.Second) state := setRaw(t, container) defer unsetRaw(t, container, state) setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() { if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil { t.Fatal(err) } }) setTimeout(t, "Escape sequence timeout", 5*time.Second, func() { cpty.Write([]byte{16}) time.Sleep(100 * time.Millisecond) cpty.Write([]byte{17}) }) // wait for CmdRun to return setTimeout(t, "Waiting for CmdRun timed out", 15*time.Second, func() { <-ch }) closeWrap(cpty, stdout, stdoutPipe) time.Sleep(500 * time.Millisecond) if !container.IsRunning() { t.Fatal("The detached container should be still running") } setTimeout(t, "Waiting for container to die timed out", 20*time.Second, func() { container.Kill() }) }
func createRegistry(t *testing.T, driver driver.StorageDriver) distribution.Namespace { ctx := context.Background() k, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatal(err) } registry, err := NewRegistry(ctx, driver, EnableDelete, Schema1SigningKey(k)) if err != nil { t.Fatalf("Failed to construct namespace") } return registry }
// Expected behaviour: the process stay alive when the client disconnects // but the client detaches. func TestRunDisconnectTty(t *testing.T) { stdin, stdinPipe := io.Pipe() stdout, stdoutPipe := io.Pipe() key, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatal(err) } cli := client.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, key, testDaemonProto, testDaemonAddr, nil) defer cleanup(globalEngine, t) c1 := make(chan struct{}) go func() { defer close(c1) // We're simulating a disconnect so the return value doesn't matter. What matters is the // fact that CmdRun returns. if err := cli.CmdRun("-i", "-t", unitTestImageID, "/bin/cat"); err != nil { log.Debugf("Error CmdRun: %s", err) } }() container := waitContainerStart(t, 10*time.Second) state := setRaw(t, container) defer unsetRaw(t, container, state) // Client disconnect after run -i should keep stdin out in TTY mode setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() { if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 150); err != nil { t.Fatal(err) } }) // Close pipes (simulate disconnect) if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil { t.Fatal(err) } // wait for CmdRun to return setTimeout(t, "Waiting for CmdRun timed out", 5*time.Second, func() { <-c1 }) // In tty mode, we expect the process to stay alive even after client's stdin closes. // Give some time to monitor to do his thing container.WaitStop(500 * time.Millisecond) if !container.IsRunning() { t.Fatalf("/bin/cat should still be running after closing stdin (tty mode)") } }
func generateTrustChain(t *testing.T, chainLen int) (libtrust.PrivateKey, *x509.CertPool, []*x509.Certificate) { caKey, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatalf("Error generating key: %s", err) } ca, err := testutil.GenerateTrustCA(caKey.CryptoPublicKey(), caKey.CryptoPrivateKey()) if err != nil { t.Fatalf("Error generating ca: %s", err) } parent := ca parentKey := caKey chain := make([]*x509.Certificate, chainLen) for i := chainLen - 1; i > 0; i-- { intermediatekey, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatalf("Error generate key: %s", err) } chain[i], err = testutil.GenerateIntermediate(intermediatekey.CryptoPublicKey(), parentKey.CryptoPrivateKey(), parent) if err != nil { t.Fatalf("Error generating intermdiate certificate: %s", err) } parent = chain[i] parentKey = intermediatekey } trustKey, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatalf("Error generate key: %s", err) } chain[0], err = testutil.GenerateTrustCert(trustKey.CryptoPublicKey(), parentKey.CryptoPrivateKey(), parent) if err != nil { t.Fatalf("Error generate trust cert: %s", err) } caPool := x509.NewCertPool() caPool.AddCert(ca) return trustKey, caPool, chain }
func makeRootKeys(numKeys int) ([]libtrust.PrivateKey, error) { keys := make([]libtrust.PrivateKey, 0, numKeys) for i := 0; i < numKeys; i++ { key, err := libtrust.GenerateECP256PrivateKey() if err != nil { return nil, err } keys = append(keys, key) } return keys, nil }
func init() { flag.StringVar(&listenAddr, "l", "localhost:6000", "Address to listen on") flag.StringVar(®istryAddr, "r", "http://localhost:5000", "Upstream registry to connect to") flag.StringVar(¬aryAddr, "n", "http://localhost:4443", "Upstream notary server to connect to") flag.StringVar(&cert, "c", "", "TLS certificate") flag.StringVar(&certKey, "k", "", "TLS certificate key") var err error key, err = libtrust.GenerateECP256PrivateKey() if err != nil { logrus.Fatalf("Error generating key: %s", err) } }
// TestHttpsInfo connects via two-way authenticated HTTPS to the info endpoint func TestHttpsInfo(t *testing.T) { key, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatal(err) } cli := client.NewDockerCli(nil, ioutil.Discard, ioutil.Discard, key, testDaemonProto, testDaemonHttpsAddr, getTlsConfig("client-cert.pem", "client-key.pem", t)) setTimeout(t, "Reading command output time out", 10*time.Second, func() { if err := cli.CmdInfo(); err != nil { t.Fatal(err) } }) }
// AddDummyV2S1Signature adds an JWS signature with a temporary key (i.e. useless) to a v2s1 manifest. // This is useful to make the manifest acceptable to a Docker Registry (even though nothing needs or wants the JWS signature). func AddDummyV2S1Signature(manifest []byte) ([]byte, error) { key, err := libtrust.GenerateECP256PrivateKey() if err != nil { return nil, err // Coverage: This can fail only if rand.Reader fails. } js, err := libtrust.NewJSONSignature(manifest) if err != nil { return nil, err } if err := js.Sign(key); err != nil { // Coverage: This can fail basically only if rand.Reader fails. return nil, err } return js.PrettySignature("signatures") }
func createTestEnv(t *testing.T, fn testSinkFn) Listener { pk, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatalf("error generating private key: %v", err) } sm, err = schema1.Sign(&m, pk) if err != nil { t.Fatalf("error signing manifest: %v", err) } payload = sm.Canonical dgst = digest.FromBytes(payload) return NewBridge(ub, source, actor, request, fn) }
// Expected behaviour: the process dies when the client disconnects func TestRunDisconnect(t *testing.T) { stdin, stdinPipe := io.Pipe() stdout, stdoutPipe := io.Pipe() key, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatal(err) } cli := client.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, key, testDaemonProto, testDaemonAddr, nil) defer cleanup(globalEngine, t) c1 := make(chan struct{}) go func() { // We're simulating a disconnect so the return value doesn't matter. What matters is the // fact that CmdRun returns. cli.CmdRun("-i", unitTestImageID, "/bin/cat") close(c1) }() setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() { if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 150); err != nil { t.Fatal(err) } }) // Close pipes (simulate disconnect) if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil { t.Fatal(err) } // as the pipes are close, we expect the process to die, // therefore CmdRun to unblock. Wait for CmdRun setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() { <-c1 }) // Client disconnect after run -i should cause stdin to be closed, which should // cause /bin/cat to exit. setTimeout(t, "Waiting for /bin/cat to exit timed out", 2*time.Second, func() { container := globalDaemon.List()[0] container.WaitStop(-1 * time.Second) if container.IsRunning() { t.Fatalf("/bin/cat is still running after closing stdin") } }) }
func signedManifest(name string) ([]byte, digest.Digest, error) { key, err := libtrust.GenerateECP256PrivateKey() if err != nil { return []byte{}, "", fmt.Errorf("error generating EC key: %s", err) } mappingManifest := manifest.Manifest{ Versioned: manifest.Versioned{ SchemaVersion: 1, }, Name: name, Tag: imageapi.DefaultImageTag, Architecture: "amd64", History: []manifest.History{ { V1Compatibility: `{"id": "foo"}`, }, }, } manifestBytes, err := json.MarshalIndent(mappingManifest, "", " ") if err != nil { return []byte{}, "", fmt.Errorf("error marshaling manifest: %s", err) } dgst, err := digest.FromBytes(manifestBytes) if err != nil { return []byte{}, "", fmt.Errorf("error calculating manifest digest: %s", err) } jsonSignature, err := libtrust.NewJSONSignature(manifestBytes) if err != nil { return []byte{}, "", fmt.Errorf("error creating json signature: %s", err) } if err = jsonSignature.Sign(key); err != nil { return []byte{}, "", fmt.Errorf("error signing manifest: %s", err) } signedBytes, err := jsonSignature.PrettySignature("signatures") if err != nil { return []byte{}, "", fmt.Errorf("error invoking PrettySignature: %s", err) } return signedBytes, dgst, nil }
func createTestKeysAndGrants(count int) ([]*Grant, []libtrust.PrivateKey) { grants := make([]*Grant, count) keys := make([]libtrust.PrivateKey, count) for i := 0; i < count; i++ { pk, err := libtrust.GenerateECP256PrivateKey() if err != nil { panic(err) } grant := &Grant{ Subject: fmt.Sprintf("/user-%d", i+1), Permission: 0x0f, Grantee: pk.KeyID(), } keys[i] = pk grants[i] = grant } return grants, keys }
// TestHttpsInfoRogueCert connects via two-way authenticated HTTPS to the info endpoint // by using a rogue client certificate and checks that it fails with the expected error. func TestHttpsInfoRogueCert(t *testing.T) { key, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatal(err) } cli := client.NewDockerCli(nil, ioutil.Discard, ioutil.Discard, key, testDaemonProto, testDaemonHttpsAddr, getTlsConfig("client-rogue-cert.pem", "client-rogue-key.pem", t)) setTimeout(t, "Reading command output time out", 10*time.Second, func() { err := cli.CmdInfo() if err == nil { t.Fatal("Expected error but got nil") } if !strings.Contains(err.Error(), errBadCertificate) { t.Fatalf("Expected error: %s, got instead: %s", errBadCertificate, err) } }) }
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path, // otherwise generates a new one func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700) if err != nil { return nil, err } trustKey, err := libtrust.LoadKeyFile(trustKeyPath) if err == libtrust.ErrKeyFileDoesNotExist { trustKey, err = libtrust.GenerateECP256PrivateKey() if err != nil { return nil, fmt.Errorf("Error generating key: %s", err) } if err := libtrust.SaveKey(trustKeyPath, trustKey); err != nil { return nil, fmt.Errorf("Error saving key file: %s", err) } } else if err != nil { return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err) } return trustKey, nil }
// Expected behaviour: container gets deleted automatically after exit func TestRunAutoRemove(t *testing.T) { t.Skip("Fixme. Skipping test for now, race condition") stdout, stdoutPipe := io.Pipe() key, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatal(err) } cli := client.NewDockerCli(nil, stdoutPipe, ioutil.Discard, key, testDaemonProto, testDaemonAddr, nil) defer cleanup(globalEngine, t) c := make(chan struct{}) go func() { defer close(c) if err := cli.CmdRun("--rm", unitTestImageID, "hostname"); err != nil { t.Fatal(err) } }() var temporaryContainerID string setTimeout(t, "Reading command output time out", 2*time.Second, func() { cmdOutput, err := bufio.NewReader(stdout).ReadString('\n') if err != nil { t.Fatal(err) } temporaryContainerID = cmdOutput if err := closeWrap(stdout, stdoutPipe); err != nil { t.Fatal(err) } }) setTimeout(t, "CmdRun timed out", 10*time.Second, func() { <-c }) time.Sleep(500 * time.Millisecond) if len(globalDaemon.List()) > 0 { t.Fatalf("failed to remove container automatically: container %s still exists", temporaryContainerID) } }
func TestListener(t *testing.T) { ctx := context.Background() k, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatal(err) } registry, err := storage.NewRegistry(ctx, inmemory.New(), storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), storage.EnableDelete, storage.EnableRedirect, storage.Schema1SigningKey(k)) if err != nil { t.Fatalf("error creating registry: %v", err) } tl := &testListener{ ops: make(map[string]int), } repoRef, _ := reference.ParseNamed("foo/bar") repository, err := registry.Repository(ctx, repoRef) if err != nil { t.Fatalf("unexpected error getting repo: %v", err) } repository = Listen(repository, tl) // Now take the registry through a number of operations checkExerciseRepository(t, repository) expectedOps := map[string]int{ "manifest:push": 1, "manifest:pull": 1, "manifest:delete": 1, "layer:push": 2, "layer:pull": 2, "layer:delete": 2, } if !reflect.DeepEqual(tl.ops, expectedOps) { t.Fatalf("counts do not match:\n%v\n !=\n%v", tl.ops, expectedOps) } }
// Expected behaviour: error out when attempting to bind mount non-existing source paths func TestRunErrorBindNonExistingSource(t *testing.T) { key, err := libtrust.GenerateECP256PrivateKey() if err != nil { t.Fatal(err) } cli := client.NewDockerCli(nil, nil, ioutil.Discard, key, testDaemonProto, testDaemonAddr, nil) defer cleanup(globalEngine, t) c := make(chan struct{}) go func() { defer close(c) // This check is made at runtime, can't be "unit tested" if err := cli.CmdRun("-v", "/i/dont/exist:/tmp", unitTestImageID, "echo 'should fail'"); err == nil { t.Fatal("should have failed to run when using /i/dont/exist as a source for the bind mount") } }() setTimeout(t, "CmdRun timed out", 5*time.Second, func() { <-c }) }
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path, // otherwise generates a new one func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700) if err != nil { return nil, err } trustKey, err := libtrust.LoadKeyFile(trustKeyPath) if err == libtrust.ErrKeyFileDoesNotExist { trustKey, err = libtrust.GenerateECP256PrivateKey() if err != nil { return nil, fmt.Errorf("Error generating key: %s", err) } encodedKey, err := serializePrivateKey(trustKey, filepath.Ext(trustKeyPath)) if err != nil { return nil, fmt.Errorf("Error serializing key: %s", err) } if err := ioutils.AtomicWriteFile(trustKeyPath, encodedKey, os.FileMode(0600)); err != nil { return nil, fmt.Errorf("Error saving key file: %s", err) } } else if err != nil { return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err) } return trustKey, nil }
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path, // otherwise generates a new one func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) { err := os.MkdirAll(path.Dir(trustKeyPath), 0700) if err != nil { return nil, err } trustKey, err := libtrust.LoadKeyFile(trustKeyPath) if err == libtrust.ErrKeyFileDoesNotExist { trustKey, err = libtrust.GenerateECP256PrivateKey() if err != nil { return nil, fmt.Errorf("Error generating key: %s", err) } if err := libtrust.SaveKey(trustKeyPath, trustKey); err != nil { return nil, fmt.Errorf("Error saving key file: %s", err) } dir, file := path.Split(trustKeyPath) // Save public key if err := libtrust.SavePublicKey(path.Join(dir, "public-"+file), trustKey.PublicKey()); err != nil { return nil, fmt.Errorf("Error saving public key file: %s", err) } } else if err != nil { return nil, fmt.Errorf("Error loading key file: %s", err) } return trustKey, nil }