securememory

package module
v0.1.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 30, 2023 License: MIT Imports: 2 Imported by: 2

README

Secure Memory Go Edition

GoDoc

This package provides a way for applications to keep secret information (like cryptographic keys) in an area of memory that is secure in the described ways.

Currently supported / tested platforms

  • MacOS x86-64
  • Linux x86-64

Guarantees

Any implementation must have the following guarantees in so far as secret information stored in secure memory

  • Values stored will not show up in core dumps
  • Values stored will not be swapped
  • Values stored will be securely / explicitly zeroed out when no longer in use

Protected Memory Implementation

The protected memory implementation of secure memory:

  • Uses mlock to lock the pages to prevent swapping
  • Uses mprotect to mark the pages no-access until needed
  • Uses setrlimit to disable core dumps entirely

In addition, we have also provided an implementation of the io.Reader that can be used to read the secret bytes.

Usage
package main

import (
    "fmt"

    "github.com/godaddy/asherah/go/securememory"
    "github.com/godaddy/asherah/go/securememory/protectedmemory"
)

func main() {
    factory := new(protectedmemory.SecretFactory)

    secret, err := factory.New(getSecretFromStore())
    if err != nil {
        panic("unexpected error!")
    }
    defer secret.Close()

    err = secret.WithBytes(func(b []byte) error {
        doSomethingWithSecretBytes(b)
        return nil
    })
    if err != nil {
        panic("unexpected error!")
    }
}

Memguard Implementation

The memguard-based implementation has identical guarantees as the protected memory implementation. It also makes use of guard pages and canary data to add further protections. Note the user of the guard pages will add an additional 2 pages of unmanaged memory being used per secret (as of this writing).

In addition, we have included the no-access support that we have provided in our other language implementations. We have also provided an implementation of the io.Reader that can be used to read the secret bytes.

The memguard based implementation:

  • Uses mlock to lock the pages to prevent swapping
  • Uses mprotect to mark the pages no-access until needed
  • Uses setrlimit to disable core dumps entirely
Usage
package main

import (
    "fmt"

    "github.com/godaddy/asherah/go/securememory"
    "github.com/godaddy/asherah/go/securememory/memguard"
)

func main() {
    factory := new(memguard.SecretFactory)

    secret, err := factory.New(getSecretFromStore())
    if err != nil {
        panic("unexpected error!")
    }
    defer secret.Close()

    err = secret.WithBytes(func(b []byte) error {
        doSomethingWithSecretBytes(b)
        return nil
    })
    if err != nil {
        panic("unexpected error!")
    }
}

Documentation

securememory package: See the godocs for api documentation.

TODO

  • Add unit tests that generate core dumps and scan them for secrets (need to extract gcore source)
  • If the operating system supports it, uses madvise to request that mapped pages be zeroed on exit
  • If the operating system supports it, uses madvise to disable core dumps for the data region instead of globally

Documentation

Overview

Package securememory provides a way for applications to keep secret information (like cryptographic keys) in an area of memory that is secure.

package main

import (
	"fmt"

	"github.com/godaddy/asherah/go/securememory/protectedmemory"
)

func main() {
	factory := new(protectedmemory.SecretFactory)

	secret, err := factory.New(getSecretFromStore())
	if err != nil {
		panic("unexpected error!")
	}
	defer secret.Close()

	err = secret.WithBytes(func(b []byte) error {
		doSomethingWithSecretBytes(b)
		return nil
	})
	if err != nil {
		panic("unexpected error!")
	}
}

Index

Constants

This section is empty.

Variables

View Source
var (
	// AllocCounter is used to track cumulative secret allocations.
	//
	// AllocCounter increases as secret objects are allocated, but unlike
	// InUseCounter, it does not decrease as secrets are released.
	AllocCounter = metrics.GetOrRegisterCounter("secret.allocated", nil)

	// InUseCounter is used to track the number of secret objects currently in use.
	//
	// InUseCounter increases as secret objects are allocated and decreases
	// as secrets are released.
	InUseCounter = metrics.GetOrRegisterCounter("secret.inuse", nil)
)

Functions

This section is empty.

Types

type Secret

type Secret interface {
	// WithBytes makes the underlying bytes readable and passes them to the function action.
	// It returns the error returned by action.
	//
	// Calling WithBytes on a closed secret is an error.
	//
	// In the event of multiple errors, e.g., action returns a non-nil error and WithBytes encounters
	// an error when modifying the protection state of the underlying byte slice, the errors will be
	// wrapped in a single error and the new composite error is returned.
	//
	// A reference MUST not be kept to the bytes passed to the function as the underlying array will no
	// longer be readable after the function exits.
	WithBytes(action func([]byte) error) error

	// WithBytesFunc makes the underlying bytes readable and passes them to the function action. It
	// returns the byte slice returned by action.
	//
	// See the WithBytes documentation for details on how errors are handled.
	//
	// A reference MUST not be kept to the bytes passed to the function as the underlying array will no
	// longer be readable after the function exits.
	WithBytesFunc(action func([]byte) ([]byte, error)) ([]byte, error)

	// IsClosed returns true if the underlying data container has already been closed.
	IsClosed() bool

	// Close closes the data container and frees any associated memory.
	Close() error

	// NewReader returns a new io.Reader reading from the underlying Secret.
	NewReader() io.Reader
}

Secret contains sensitive memory and stores data in protected page(s) in memory. Always call close after use to avoid memory leaks.

type SecretFactory

type SecretFactory interface {
	// New takes in a byte slice and returns a Secret containing that data.
	New(b []byte) (Secret, error)

	// CreateRandom returns a Secret that contains a random byte slice of the specified size.
	CreateRandom(size int) (Secret, error)
}

SecretFactory is the interface for creating specific implementations of a Secret.

Directories

Path Synopsis
internal
Package log implements simple logging functionality with a focus on debug level logging.
Package log implements simple logging functionality with a focus on debug level logging.
Package memguard implements memguard backed secrets.
Package memguard implements memguard backed secrets.
Package protectedmemory implements protected memory backed secrets.
Package protectedmemory implements protected memory backed secrets.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL