crypto11

package module
v0.0.0-...-bfaf6ca Latest Latest
Warning

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

Go to latest
Published: Aug 24, 2017 License: MIT Imports: 18 Imported by: 0

README

Crypto11

This is an implementation of the standard Golang hardware crypto interface that uses PKCS#11 as a backend. The supported features are:

  • Generation and retrieval of RSA, DSA and ECDSA keys.
  • PKCS#1 v1.5 signing.
  • PKCS#1 PSS signing.
  • PKCS#1 v1.5 decryption
  • PKCS#1 OAEP decryption
  • ECDSA signing.
  • DSA signing.
  • Random number generation.

Signing is done through the crypto.Signer interface and decryption through crypto.Decrypter.

To verify signatures or encrypt messages, retrieve the public key and do it in software.

See the documentation for details of various limitations.

There are some rudimentary tests.

There is a demo web server in the demo directory, which publishes the contents of /usr/share/doc.

Installation

(If you don't have one already) create a standard Go workspace and set the GOPATH environment variable to point to the workspace root.

crypto11 manages it's dependencies via dep. To Install dep run:

go get -u github.com/golang/dep/cmd/dep

Clone, ensure deps, and build:

go get github.com/thalesignite/crypto11
cd $GOPATH/src/github.com/thalesignite/crypto11
dep ensure
go build

Edit config to taste, and then run the test program:

go test

Testing Guidance

Testing with nShield

In all cases, it's worth enabling nShield PKCS#11 log output:

export CKNFAST_DEBUG=2

To protect keys with a 1/N operator cardset:

$ cat config
{
  "Path" : "/opt/nfast/toolkits/pkcs11/libcknfast.so",
  "TokenLabel": "rjk",
  "Pin" : "password"
}

You can also identify the token by serial number, which in this case means the first 16 hex digits of the operator cardset's token hash:

$ cat config
{
  "Path" : "/opt/nfast/toolkits/pkcs11/libcknfast.so",
  "TokenSerial": "1d42780caa22efd5",
  "Pin" : "password"
}

A card from the cardset must be in the slot when you run go test.

To protect keys with the module only, use the 'accelerator' token:

$ cat config
{
  "Path" : "/opt/nfast/toolkits/pkcs11/libcknfast.so",
  "TokenLabel": "accelerator",
  "Pin" : "password"
}

Testing with SoftHSM

While the aim of the exercise is to use an HSM, it can be convenient to test with a software-only provider.

To set up a slot:

$ cat softhsm.conf
0:softhsm0.db
$ export SOFTHSM_CONF=`pwd`/softhsm.conf
$ softhsm --init-token --slot 0 --label test
The SO PIN must have a length between 4 and 255 characters.
Enter SO PIN:
The user PIN must have a length between 4 and 255 characters.
Enter user PIN:
The token has been initialized.

Configure as follows:

$ cat config
{
  "Path" : "/usr/lib/softhsm/libsofthsm.so",
  "TokenLabel": "test",
  "Pin" : "password"
}

DSA, ECDSA, PSS and OAEP aren't supported, so expect test failures.

Testing with SoftHSM2

To set up a slot:

$ cat softhsm2.conf
directories.tokendir = /home/rjk/go/src/github.com/thalesignite/crypto11/tokens
objectstore.backend = file
log.level = INFO
$ mkdir tokens
$ export SOFTHSM2_CONF=`pwd`/softhsm2.conf
$ softhsm2-util --init-token --slot 0 --label test
=== SO PIN (4-255 characters) ===
Please enter SO PIN: ********
Please reenter SO PIN: ********
=== User PIN (4-255 characters) ===
Please enter user PIN: ********
Please reenter user PIN: ********
The token has been initialized.

The configuration looks like this:

$ cat config
{
  "Path" : "/usr/lib/softhsm/libsofthsm2.so",
  "TokenLabel": "test",
  "Pin" : "password"
}

(At time of writing) PSS and OAEP aren't supported so expect test failures.

Wishlist

  • Full test instructions for additional PKCS#11 implementations.
  • A pony.

MIT License.

Copyright 2016, 2017 Thales e-Security, Inc

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Documentation

Overview

Access cryptographic keys from PKCS#11 using Go crypto API.

For simple use:

1. Either write a configuration file (see ConfigureFromFile) or define a configuration in your application (see PKCS11Config and Configure). This will identify the PKCS#11 library and token to use, and contain the password (or "PIN" in PKCS#11 terminology) to use if the token requires login.

2. Create keys with GenerateDSAKeyPair, GenerateRSAKeyPair and GenerateECDSAKeyPair. The keys you get back implement the standard Go crypto.Signer interface (and crypto.Decrypter, for RSA). They are automatically persisted under random a randomly generated label and ID (use the Identify method to discover them).

3. Retrieve existing keys with FindKeyPair. The return value is a Go crypto.PrivateKey; it may be converted either to crypto.Signer or to *PKCS11PrivateKeyDSA, *PKCS11PrivateKeyECDSA or *PKCS11PrivateKeyRSA.

Sessions and concurrency:

Note that PKCS#11 session handles must not be used concurrently from multiple threads. Consumers of the Signer interface know nothing of this and expect to be able to sign from multiple threads without constraint. We address this as follows.

1. PKCS11Object captures both the object handle and the slot ID for an object.

2. For each slot we maintain a pool of read-write sessions. The pool expands dynamically up to an (undocumented) limit.

3. Each operation transiently takes a session from the pool. They have exclusive use of the session, meeting PKCS#11's concurrency requirements.

The details are, partially, exposed in the API; since the target use case is PKCS#11-unaware operation it may be that the API as it stands isn't good enough for PKCS#11-aware applications. Feedback welcome.

See also https://golang.org/pkg/crypto/

Index

Constants

This section is empty.

Variables

View Source
var ErrCannotGetRandomData = errors.New("crypto11: cannot get random data from PKCS#11")

ErrCannotGetRandomData is returned when the PKCS#11 library fails to return enough random data

View Source
var ErrCannotOpenPKCS11 = errors.New("crypto11: could not open PKCS#11")

ErrCannotOpenPKCS11 is returned when the PKCS#11 library cannot be opened

View Source
var ErrKeyNotFound = errors.New("crypto11: could not find PKCS#11 key")

ErrKeyNotFound represents the failure to find the requested PKCS#11 key

View Source
var ErrMalformedDER = errors.New("crypto11: malformed DER message")

ErrMalformedDER represents a failure to decode an ASN.1-encoded message

View Source
var ErrMalformedPoint = errors.New("crypto11/ecdsa: malformed elliptic curve point")

ErrMalformedPoint is returned when crypto.elliptic.Unmarshal cannot decode a point.

View Source
var ErrMalformedRSAKey = errors.New("crypto11/rsa: malformed RSA key")

ErrMalformedRSAKey is returned when an RSA key is not in a suitable form.

Currently this means that the public exponent is either bigger than 32 bits, or less than 2.

View Source
var ErrMalformedSignature = errors.New("crypto11xo: malformed signature")

ErrMalformedDER represents a failure to decode a signature. This means the PKCS#11 library has returned an empty or odd-length byte string.

View Source
var ErrNotConfigured = errors.New("crypto11: PKCS#11 not yet configured")

ErrNotConfigured is returned when the PKCS#11 library is not configured

View Source
var ErrTokenNotFound = errors.New("crypto11: could not find PKCS#11 token")

ErrTokenNotFound represents the failure to find the requested PKCS#11 token

View Source
var ErrUnrecognizedRSAOptions = errors.New("crypto11/rsa: unrecognized RSA options type")

ErrUnrecognizedRSAOptions is returned when unrecognized options structures are pased to Sign or Decrypt.

View Source
var ErrUnsupportedEllipticCurve = errors.New("crypto11/ecdsa: unsupported elliptic curve")

ErrUnsupportedEllipticCurve is returned when an elliptic curve unsupported by crypto11 is specified. Note that the error behavior for an elliptic curve unsupported by the underlying PKCS#11 implementation will be different.

View Source
var ErrUnsupportedKeyType = errors.New("crypto11: unrecognized key type")

ErrUnsupportedKeyType is returned when the PKCS#11 library returns a key type that isn't supported

View Source
var ErrUnsupportedRSAOptions = errors.New("crypto11/rsa: unsupported RSA option value")

ErrUnsupportedRSAOptions is returned when an unsupported RSA option is requested.

Currently this means a nontrivial SessionKeyLen when decrypting; or an unsupported hash function; or crypto.rsa.PSSSaltLengthAuto was requested.

Functions

func Configure

func Configure(config *PKCS11Config) (*pkcs11.Ctx, error)

Configure configures PKCS#11 from a PKCS11Config.

The PKCS#11 library context is returned, allowing a PKCS#11-aware application to make use of it. Non-aware appliations may ignore it.

Unsually, these values may be present even if the error is non-nil. This corresponds to the case that the library has already been configured. Note that it is NOT reconfigured so if you supply a different configuration the second time, it will be ignored in favor of the first configuration.

If config is nil, and the library has already been configured, the context from the first configuration is returned (and the error will be nil in this case).

func ConfigureFromFile

func ConfigureFromFile(configLocation string) (*pkcs11.Ctx, error)

ConfigureFromFile configures PKCS#11 from a name configuration file.

Configuration files are a JSON representation of the PKCSConfig object. The return value is as for Configure().

Note that if CRYPTO11_CONFIG_PATH is set in the environment, configuration will be read from that file, overriding any later runtime configuration.

func FindKeyPair

func FindKeyPair(id []byte, label []byte) (crypto.PrivateKey, error)

FindKeyPair retrieves a previously created asymmetric key.

Either (but not both) of id and label may be nil, in which case they are ignored.

func FindKeyPairOnSession

func FindKeyPairOnSession(session pkcs11.SessionHandle, slot uint, id []byte, label []byte) (crypto.PrivateKey, error)

FindKeyPairOnSession retrieves a previously created asymmetric key, using a specified session.

Either (but not both) of id and label may be nil, in which case they are ignored.

func FindKeyPairOnSlot

func FindKeyPairOnSlot(slot uint, id []byte, label []byte) (crypto.PrivateKey, error)

FindKeyPairOnSession retrieves a previously created asymmetric key, using a specified slot.

Either (but not both) of id and label may be nil, in which case they are ignored.

Types

type PKCS11Config

type PKCS11Config struct {
	// Full path to PKCS#11 library
	Path string

	// Token serial number
	TokenSerial string

	// Token label
	TokenLabel string

	// User PIN (password)
	Pin string
}

PKCS11Config holds PKCS#11 configuration information.

A token may be identified either by serial number or label. If both are specified then the first match wins.

Supply this to Configure(), or alternatively use ConfigureFromFile().

type PKCS11Object

type PKCS11Object struct {
	// The PKCS#11 object handle.
	Handle pkcs11.ObjectHandle

	// The PKCS#11 slot number.
	//
	// This is used internally to find a session handle that can
	// access this object.
	Slot uint
}

PKCS11Object contains a reference to a loaded PKCS#11 object.

func (*PKCS11Object) Identify

func (object *PKCS11Object) Identify() (id []byte, label []byte, err error)

Identify returns the ID and label for a PKCS#11 object.

Either of these values may be used to retrieve the key for later use.

type PKCS11PrivateKey

type PKCS11PrivateKey struct {
	PKCS11Object

	// The corresponding public key
	PubKey crypto.PublicKey
}

PKCS11PrivateKey contains a reference to a loaded PKCS#11 private key object.

func (PKCS11PrivateKey) Public

func (signer PKCS11PrivateKey) Public() crypto.PublicKey

Public returns the public half of a private key.

This partially implements the go.crypto.Signer and go.crypto.Decrypter interfaces for PKCS11PrivateKey. (The remains of the implementation is in the key-specific types.)

type PKCS11PrivateKeyDSA

type PKCS11PrivateKeyDSA struct {
	PKCS11PrivateKey
}

PKCS11PrivateKeyDSA contains a reference to a loaded PKCS#11 DSA private key object.

func GenerateDSAKeyPair

func GenerateDSAKeyPair(params *dsa.Parameters) (*PKCS11PrivateKeyDSA, error)

GenerateDSAKeyPair creates a DSA private key on the default slot

The key will have a random label and ID.

func GenerateDSAKeyPairOnSession

func GenerateDSAKeyPairOnSession(session pkcs11.SessionHandle, slot uint, id []byte, label []byte, params *dsa.Parameters) (*PKCS11PrivateKeyDSA, error)

GenerateDSAKeyPairOnSession creates a DSA private key using a specified session

Either or both label and/or id can be nil, in which case a random values will be generated.

func GenerateDSAKeyPairOnSlot

func GenerateDSAKeyPairOnSlot(slot uint, id []byte, label []byte, params *dsa.Parameters) (*PKCS11PrivateKeyDSA, error)

GenerateDSAKeyPairOnSession creates a DSA private key on a specified slot

Either or both label and/or id can be nil, in which case a random values will be generated.

func (*PKCS11PrivateKeyDSA) Sign

func (signer *PKCS11PrivateKeyDSA) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error)

Sign signs a message using a DSA key.

This completes the implemention of crypto.Signer for PKCS11PrivateKeyDSA.

PKCS#11 expects to pick its own random data for signatures, so the rand argument is ignored.

The return value is a DER-encoded byteblock.

type PKCS11PrivateKeyECDSA

type PKCS11PrivateKeyECDSA struct {
	PKCS11PrivateKey
}

PKCS11PrivateKeyECDSA contains a reference to a loaded PKCS#11 ECDSA private key object.

func GenerateECDSAKeyPair

func GenerateECDSAKeyPair(c elliptic.Curve) (*PKCS11PrivateKeyECDSA, error)

GenerateECDSAKeyPair creates an ECDSA private key using curve c.

The key will have a random label and ID.

Only a limited set of named elliptic curves are supported. The underlying PKCS#11 implementation may impose further restrictions.

func GenerateECDSAKeyPairOnSession

func GenerateECDSAKeyPairOnSession(session pkcs11.SessionHandle, slot uint, id []byte, label []byte, c elliptic.Curve) (*PKCS11PrivateKeyECDSA, error)

GenerateECDSAKeyPairOnSession creates an ECDSA private key using curve c, using a specified session.

label and/or id can be nil, in which case a random values will be generated.

Only a limited set of named elliptic curves are supported. The underlying PKCS#11 implementation may impose further restrictions.

func GenerateECDSAKeyPairOnSlot

func GenerateECDSAKeyPairOnSlot(slot uint, id []byte, label []byte, c elliptic.Curve) (*PKCS11PrivateKeyECDSA, error)

GenerateECDSAKeyPairOnSession creates an ECDSA private key using curve c, on a specified slot.

label and/or id can be nil, in which case a random values will be generated.

Only a limited set of named elliptic curves are supported. The underlying PKCS#11 implementation may impose further restrictions.

func (*PKCS11PrivateKeyECDSA) Sign

func (signer *PKCS11PrivateKeyECDSA) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error)

Sign signs a message using an ECDSA key.

This completes the implemention of crypto.Signer for PKCS11PrivateKeyECDSA.

PKCS#11 expects to pick its own random data where necessary for signatures, so the rand argument is ignored.

The return value is a DER-encoded byteblock.

type PKCS11PrivateKeyRSA

type PKCS11PrivateKeyRSA struct {
	PKCS11PrivateKey
}

PKCS11PrivateKeyRSA contains a reference to a loaded PKCS#11 RSA private key object.

func GenerateRSAKeyPair

func GenerateRSAKeyPair(bits int) (*PKCS11PrivateKeyRSA, error)

GenerateRSAKeyPair creates an RSA private key of given length.

The key will have a random label and ID.

RSA private keys are generated with both sign and decrypt permissions, and a public exponent of 65537.

func GenerateRSAKeyPairOnSession

func GenerateRSAKeyPairOnSession(session pkcs11.SessionHandle, slot uint, id []byte, label []byte, bits int) (*PKCS11PrivateKeyRSA, error)

GenerateRSAKeyPairOnSession creates an RSA private key of given length, on a specified session.

Either or both label and/or id can be nil, in which case a random values will be generated.

RSA private keys are generated with both sign and decrypt permissions, and a public exponent of 65537.

func GenerateRSAKeyPairOnSlot

func GenerateRSAKeyPairOnSlot(slot uint, id []byte, label []byte, bits int) (*PKCS11PrivateKeyRSA, error)

GenerateRSAKeyPairOnSession creates a RSA private key on a specified slot

Either or both label and/or id can be nil, in which case a random values will be generated.

func (*PKCS11PrivateKeyRSA) Decrypt

func (decrypter *PKCS11PrivateKeyRSA) Decrypt(rand io.Reader, ciphertext []byte, options crypto.DecrypterOpts) (plaintext []byte, err error)

Decrypt decrypt a message using a RSA key.

This completes the implemention of crypto.Decrypter for PKCS11PrivateKeyRSA.

Note that the SessionKeyLen option (for PKCS#1v1.5 decryption) is not supported.

The underlying PKCS#11 implementation may impose further restrictions.

func (*PKCS11PrivateKeyRSA) Sign

func (signer *PKCS11PrivateKeyRSA) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error)

Sign signs a message using a RSA key.

This completes the implemention of crypto.Signer for PKCS11PrivateKeyRSA.

PKCS#11 expects to pick its own random data where necessary for signatures, so the rand argument is ignored.

Note that (at present) the crypto.rsa.PSSSaltLengthAuto option is not supported. The caller must either use crypto.rsa.PSSSaltLengthEqualsHash (recommended) or pass an explicit salt length. Moreover the underlying PKCS#11 implementation may impose further restrictions.

func (*PKCS11PrivateKeyRSA) Validate

func (priv *PKCS11PrivateKeyRSA) Validate() error

Validate checks an RSA key.

Since the private key material is not normally available only very limited validation is possible. (The underlying PKCS#11 implementation may perform stricter checking.)

type PKCS11RandReader

type PKCS11RandReader struct {
}

A random number reader that uses PKCS#11.

func (PKCS11RandReader) Read

func (reader PKCS11RandReader) Read(data []byte) (n int, err error)

Read fills data with random bytes generated via PKCS#11 using the default slot.

This implements the Reader interface for PKCS11RandReader.

Directories

Path Synopsis
A demo program using a PKCS#11-protected key to authenticate a web server.
A demo program using a PKCS#11-protected key to authenticate a web server.

Jump to

Keyboard shortcuts

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