mirror of https://github.com/docker/docs.git
updating miekg/pkcs11 for go 1.6
Signed-off-by: David Lawrence <david.lawrence@docker.com> (github: endophage)
This commit is contained in:
parent
332fc35dc5
commit
9db2ae3ed6
|
@ -171,6 +171,10 @@
|
||||||
"ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil",
|
"ImportPath": "github.com/matttproud/golang_protobuf_extensions/pbutil",
|
||||||
"Rev": "d0c3fe89de86839aecf2e0579c40ba3bb336a453"
|
"Rev": "d0c3fe89de86839aecf2e0579c40ba3bb336a453"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/miekg/pkcs11",
|
||||||
|
"Rev": "df8ae6ca730422dba20c768ff38ef7d79077a59f"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/mitchellh/go-homedir",
|
"ImportPath": "github.com/mitchellh/go-homedir",
|
||||||
"Rev": "df55a15e5ce646808815381b3db47a8c66ea62f4"
|
"Rev": "df55a15e5ce646808815381b3db47a8c66ea62f4"
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
# PKCS#11
|
# PKCS#11 [](https://travis-ci.org/miekg/pkcs11)
|
||||||
|
|
||||||
This is a Go implementation of the PKCS#11 API. It wraps the library closely, but uses Go idiom
|
This is a Go implementation of the PKCS#11 API. It wraps the library closely, but uses Go idiom
|
||||||
were it makes sense. It has been tested with SoftHSM.
|
were it makes sense. It has been tested with SoftHSM.
|
||||||
|
|
||||||
## SoftHSM
|
## SoftHSM
|
||||||
|
|
||||||
* Make it use a custom configuration file
|
* Make it use a custom configuration file `export SOFTHSM_CONF=$PWD/softhsm.conf`
|
||||||
|
|
||||||
export SOFTHSM_CONF=$PWD/softhsm.conf
|
|
||||||
|
|
||||||
* Then use `softhsm` to init it
|
* Then use `softhsm` to init it
|
||||||
|
|
||||||
|
@ -22,16 +20,37 @@ were it makes sense. It has been tested with SoftHSM.
|
||||||
A skeleton program would look somewhat like this (yes, pkcs#11 is verbose):
|
A skeleton program would look somewhat like this (yes, pkcs#11 is verbose):
|
||||||
|
|
||||||
p := pkcs11.New("/usr/lib/softhsm/libsofthsm.so")
|
p := pkcs11.New("/usr/lib/softhsm/libsofthsm.so")
|
||||||
p.Initialize()
|
err := p.Initialize()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
defer p.Destroy()
|
defer p.Destroy()
|
||||||
defer p.Finalize()
|
defer p.Finalize()
|
||||||
slots, _ := p.GetSlotList(true)
|
|
||||||
session, _ := p.OpenSession(slots[0], pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION)
|
slots, err := p.GetSlotList(true)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
session, err := p.OpenSession(slots[0], pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
defer p.CloseSession(session)
|
defer p.CloseSession(session)
|
||||||
p.Login(session, pkcs11.CKU_USER, "1234")
|
|
||||||
|
err = p.Login(session, pkcs11.CKU_USER, "1234")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
defer p.Logout(session)
|
defer p.Logout(session)
|
||||||
|
|
||||||
p.DigestInit(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_SHA_1, nil)})
|
p.DigestInit(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_SHA_1, nil)})
|
||||||
hash, err := p.Digest(session, []byte("this is a string"))
|
hash, err := p.Digest(session, []byte("this is a string"))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
for _, d := range hash {
|
for _, d := range hash {
|
||||||
fmt.Printf("%x", d)
|
fmt.Printf("%x", d)
|
||||||
}
|
}
|
||||||
|
@ -41,8 +60,5 @@ Further examples are included in the tests.
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
* Fix/double check endian stuff, see types.go NewAttribute();
|
* Fix/double check endian stuff, see types.go NewAttribute()
|
||||||
* Kill C.Sizeof in that same function.
|
* Look at the memory copying in fast functions (sign, hash etc)
|
||||||
* Look at the memory copying in fast functions (sign, hash etc).
|
|
||||||
* Fix inconsistencies in naming?
|
|
||||||
* Add tests -- there are way too few
|
|
||||||
|
|
|
@ -23,9 +23,9 @@ const (
|
||||||
CKO_VENDOR_DEFINED uint = 0x80000000
|
CKO_VENDOR_DEFINED uint = 0x80000000
|
||||||
)
|
)
|
||||||
|
|
||||||
// Generated with: awk '/#define CK[AFKMR]/{ print $2 "=" $3 }' pkcs11t.h
|
// Generated with: awk '/#define CK[AFKMRC]/{ print $2 "=" $3 }' pkcs11t.h
|
||||||
|
|
||||||
// All the flag (CKF_), attribute (CKA_), error code (CKR_), key type (CKK_) and
|
// All the flag (CKF_), attribute (CKA_), error code (CKR_), key type (CKK_), certificate type (CKC_) and
|
||||||
// mechanism (CKM_) constants as defined in PKCS#11.
|
// mechanism (CKM_) constants as defined in PKCS#11.
|
||||||
const (
|
const (
|
||||||
CKF_TOKEN_PRESENT = 0x00000001
|
CKF_TOKEN_PRESENT = 0x00000001
|
||||||
|
@ -83,6 +83,10 @@ const (
|
||||||
CKK_CAMELLIA = 0x00000025
|
CKK_CAMELLIA = 0x00000025
|
||||||
CKK_ARIA = 0x00000026
|
CKK_ARIA = 0x00000026
|
||||||
CKK_VENDOR_DEFINED = 0x80000000
|
CKK_VENDOR_DEFINED = 0x80000000
|
||||||
|
CKC_X_509 = 0x00000000
|
||||||
|
CKC_X_509_ATTR_CERT = 0x00000001
|
||||||
|
CKC_WTLS = 0x00000002
|
||||||
|
CKC_VENDOR_DEFINED = 0x80000000
|
||||||
CKF_ARRAY_ATTRIBUTE = 0x40000000
|
CKF_ARRAY_ATTRIBUTE = 0x40000000
|
||||||
CKA_CLASS = 0x00000000
|
CKA_CLASS = 0x00000000
|
||||||
CKA_TOKEN = 0x00000001
|
CKA_TOKEN = 0x00000001
|
||||||
|
@ -117,11 +121,11 @@ const (
|
||||||
CKA_VERIFY = 0x0000010A
|
CKA_VERIFY = 0x0000010A
|
||||||
CKA_VERIFY_RECOVER = 0x0000010B
|
CKA_VERIFY_RECOVER = 0x0000010B
|
||||||
CKA_DERIVE = 0x0000010C
|
CKA_DERIVE = 0x0000010C
|
||||||
CKA_START_DATE = 0x00000110 // Use time.Time as a value.
|
CKA_START_DATE = 0x00000110
|
||||||
CKA_END_DATE = 0x00000111 // Use time.Time as a value.
|
CKA_END_DATE = 0x00000111
|
||||||
CKA_MODULUS = 0x00000120
|
CKA_MODULUS = 0x00000120
|
||||||
CKA_MODULUS_BITS = 0x00000121
|
CKA_MODULUS_BITS = 0x00000121
|
||||||
CKA_PUBLIC_EXPONENT = 0x00000122 // Use []byte slice as a value.
|
CKA_PUBLIC_EXPONENT = 0x00000122
|
||||||
CKA_PRIVATE_EXPONENT = 0x00000123
|
CKA_PRIVATE_EXPONENT = 0x00000123
|
||||||
CKA_PRIME_1 = 0x00000124
|
CKA_PRIME_1 = 0x00000124
|
||||||
CKA_PRIME_2 = 0x00000125
|
CKA_PRIME_2 = 0x00000125
|
||||||
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
package pkcs11
|
||||||
|
|
||||||
|
// A test of using several pkcs11 sessions in parallel for signing across
|
||||||
|
// multiple goroutines. Access to the PKCS11 module is thread-safe because of
|
||||||
|
// the C.CKF_OS_LOCKING_OK param and nil mutex functions that the pkcs11
|
||||||
|
// package passes to C.Initialize, which indicate that the module should use OS
|
||||||
|
// locking primitives on its own.
|
||||||
|
//
|
||||||
|
// Note that while access to the module is thread-safe, sessions are not thread
|
||||||
|
// safe, and each session must be protected from simultaneous use by some
|
||||||
|
// synchronization mechanism. In this case we use a cache of sessions (as
|
||||||
|
// embodied by the `signer` struct), protected by a condition variable. So long
|
||||||
|
// as there is an available signer in the cache, it is popped off and used. If
|
||||||
|
// there are no signers available, the caller blocks until there is one
|
||||||
|
// available.
|
||||||
|
//
|
||||||
|
// Please set the appropiate env variables. See the init function.
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
module = "/usr/lib/softhsm/libsofthsm.so"
|
||||||
|
tokenLabel = "softhsm token"
|
||||||
|
privateKeyLabel = "my key"
|
||||||
|
pin = "1234"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if x := os.Getenv("SOFTHSM_LIB"); x != "" {
|
||||||
|
module = x
|
||||||
|
}
|
||||||
|
if x := os.Getenv("SOFTHSM_TOKENLABEL"); x != "" {
|
||||||
|
tokenLabel = x
|
||||||
|
}
|
||||||
|
if x := os.Getenv("SOFTHSM_PRIVKEYLABEL"); x != "" {
|
||||||
|
privateKeyLabel = x
|
||||||
|
}
|
||||||
|
if x := os.Getenv("SOFTHSM_PIN"); x != "" {
|
||||||
|
pin = x
|
||||||
|
}
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
os.Setenv("SOFTHSM_CONF", wd+"/softhsm.conf")
|
||||||
|
}
|
||||||
|
|
||||||
|
func initPKCS11Context(modulePath string) (*Ctx, error) {
|
||||||
|
context := New(modulePath)
|
||||||
|
|
||||||
|
if context == nil {
|
||||||
|
return nil, fmt.Errorf("unable to load PKCS#11 module")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := context.Initialize()
|
||||||
|
return context, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSlot(p *Ctx, label string) (uint, error) {
|
||||||
|
slots, err := p.GetSlotList(true)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
for _, slot := range slots {
|
||||||
|
_, err := p.GetSlotInfo(slot)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
tokenInfo, err := p.GetTokenInfo(slot)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if tokenInfo.Label == label {
|
||||||
|
return slot, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("Slot not found: %s", label)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPrivateKey(context *Ctx, session SessionHandle, label string) (ObjectHandle, error) {
|
||||||
|
var noKey ObjectHandle
|
||||||
|
template := []*Attribute{
|
||||||
|
NewAttribute(CKA_CLASS, CKO_PRIVATE_KEY),
|
||||||
|
NewAttribute(CKA_LABEL, label),
|
||||||
|
}
|
||||||
|
if err := context.FindObjectsInit(session, template); err != nil {
|
||||||
|
return noKey, err
|
||||||
|
}
|
||||||
|
objs, _, err := context.FindObjects(session, 2)
|
||||||
|
if err != nil {
|
||||||
|
return noKey, err
|
||||||
|
}
|
||||||
|
if err = context.FindObjectsFinal(session); err != nil {
|
||||||
|
return noKey, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(objs) == 0 {
|
||||||
|
err = fmt.Errorf("private key not found")
|
||||||
|
return noKey, err
|
||||||
|
}
|
||||||
|
return objs[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type signer struct {
|
||||||
|
context *Ctx
|
||||||
|
session SessionHandle
|
||||||
|
privateKey ObjectHandle
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSigner(context *Ctx) (*signer, error) {
|
||||||
|
slot, err := getSlot(context, tokenLabel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
session, err := context.OpenSession(slot, CKF_SERIAL_SESSION)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = context.Login(session, CKU_USER, pin); err != nil {
|
||||||
|
context.CloseSession(session)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKey, err := getPrivateKey(context, session, privateKeyLabel)
|
||||||
|
if err != nil {
|
||||||
|
context.CloseSession(session)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &signer{context, session, privateKey}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *signer) sign(input []byte) ([]byte, error) {
|
||||||
|
mechanism := []*Mechanism{NewMechanism(CKM_RSA_PKCS, nil)}
|
||||||
|
if err := s.context.SignInit(s.session, mechanism, s.privateKey); err != nil {
|
||||||
|
log.Fatalf("SignInit: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
signed, err := s.context.Sign(s.session, input)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Sign: %s", err)
|
||||||
|
}
|
||||||
|
return signed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type cache struct {
|
||||||
|
signers []*signer
|
||||||
|
// this variable signals the condition that there are signers available to be
|
||||||
|
// used.
|
||||||
|
cond *sync.Cond
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCache(signers []*signer) cache {
|
||||||
|
var mutex sync.Mutex
|
||||||
|
return cache{
|
||||||
|
signers: signers,
|
||||||
|
cond: sync.NewCond(&mutex),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache) get() *signer {
|
||||||
|
c.cond.L.Lock()
|
||||||
|
for len(c.signers) == 0 {
|
||||||
|
c.cond.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
instance := c.signers[len(c.signers)-1]
|
||||||
|
c.signers = c.signers[:len(c.signers)-1]
|
||||||
|
c.cond.L.Unlock()
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache) put(instance *signer) {
|
||||||
|
c.cond.L.Lock()
|
||||||
|
c.signers = append(c.signers, instance)
|
||||||
|
c.cond.Signal()
|
||||||
|
c.cond.L.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache) sign(input []byte) ([]byte, error) {
|
||||||
|
instance := c.get()
|
||||||
|
defer c.put(instance)
|
||||||
|
return instance.sign(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(miek): disabled for now. Fill out the correct values in hsm.db so we can use it.
|
||||||
|
func testParallel(t *testing.T) {
|
||||||
|
if module == "" || tokenLabel == "" || pin == "" || privateKeyLabel == "" {
|
||||||
|
t.Fatal("Must pass all flags: module, tokenLabel, pin, and privateKeyLabel")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
context, err := initPKCS11Context(module)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
context.Finalize()
|
||||||
|
context.Destroy()
|
||||||
|
}()
|
||||||
|
|
||||||
|
const nSigners = 100
|
||||||
|
const nSignatures = 1000
|
||||||
|
signers := make([]*signer, nSigners)
|
||||||
|
for i := 0; i < nSigners; i++ {
|
||||||
|
signers[i], err = makeSigner(context)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Problem making signer: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pool := newCache(signers)
|
||||||
|
|
||||||
|
output := make(chan []byte, nSignatures)
|
||||||
|
for i := 0; i < nSignatures; i++ {
|
||||||
|
go func() {
|
||||||
|
result, err := pool.sign([]byte("hi"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
output <- result
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < nSignatures; i++ {
|
||||||
|
// Consume the output of the signers, but do nothing with it.
|
||||||
|
<-output
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < nSigners; i++ {
|
||||||
|
// Note: It is not necessary to call context.Logout. Closing the last
|
||||||
|
// session will automatically log out, per PKCS#11 API.
|
||||||
|
context.CloseSession(signers[i].session)
|
||||||
|
}
|
||||||
|
}
|
|
@ -207,6 +207,9 @@ CK_RV SetOperationState(struct ctx * c, CK_SESSION_HANDLE session,
|
||||||
CK_RV Login(struct ctx *c, CK_SESSION_HANDLE session, CK_USER_TYPE userType,
|
CK_RV Login(struct ctx *c, CK_SESSION_HANDLE session, CK_USER_TYPE userType,
|
||||||
char *pin, CK_ULONG pinLen)
|
char *pin, CK_ULONG pinLen)
|
||||||
{
|
{
|
||||||
|
if (pinLen == 0) {
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
CK_RV e =
|
CK_RV e =
|
||||||
c->sym->C_Login(session, userType, (CK_UTF8CHAR_PTR) pin, pinLen);
|
c->sym->C_Login(session, userType, (CK_UTF8CHAR_PTR) pin, pinLen);
|
||||||
return e;
|
return e;
|
||||||
|
@ -997,7 +1000,8 @@ func (c *Ctx) Logout(sh SessionHandle) error {
|
||||||
/* CreateObject creates a new object. */
|
/* CreateObject creates a new object. */
|
||||||
func (c *Ctx) CreateObject(sh SessionHandle, temp []*Attribute) (ObjectHandle, error) {
|
func (c *Ctx) CreateObject(sh SessionHandle, temp []*Attribute) (ObjectHandle, error) {
|
||||||
var obj C.CK_OBJECT_HANDLE
|
var obj C.CK_OBJECT_HANDLE
|
||||||
t, tcount := cAttributeList(temp)
|
arena, t, tcount := cAttributeList(temp)
|
||||||
|
defer arena.Free()
|
||||||
e := C.CreateObject(c.ctx, C.CK_SESSION_HANDLE(sh), t, tcount, C.CK_OBJECT_HANDLE_PTR(&obj))
|
e := C.CreateObject(c.ctx, C.CK_SESSION_HANDLE(sh), t, tcount, C.CK_OBJECT_HANDLE_PTR(&obj))
|
||||||
e1 := toError(e)
|
e1 := toError(e)
|
||||||
if e1 == nil {
|
if e1 == nil {
|
||||||
|
@ -1009,7 +1013,8 @@ func (c *Ctx) CreateObject(sh SessionHandle, temp []*Attribute) (ObjectHandle, e
|
||||||
/* CopyObject copies an object, creating a new object for the copy. */
|
/* CopyObject copies an object, creating a new object for the copy. */
|
||||||
func (c *Ctx) CopyObject(sh SessionHandle, o ObjectHandle, temp []*Attribute) (ObjectHandle, error) {
|
func (c *Ctx) CopyObject(sh SessionHandle, o ObjectHandle, temp []*Attribute) (ObjectHandle, error) {
|
||||||
var obj C.CK_OBJECT_HANDLE
|
var obj C.CK_OBJECT_HANDLE
|
||||||
t, tcount := cAttributeList(temp)
|
arena, t, tcount := cAttributeList(temp)
|
||||||
|
defer arena.Free()
|
||||||
|
|
||||||
e := C.CopyObject(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_OBJECT_HANDLE(o), t, tcount, C.CK_OBJECT_HANDLE_PTR(&obj))
|
e := C.CopyObject(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_OBJECT_HANDLE(o), t, tcount, C.CK_OBJECT_HANDLE_PTR(&obj))
|
||||||
e1 := toError(e)
|
e1 := toError(e)
|
||||||
|
@ -1059,7 +1064,8 @@ func (c *Ctx) GetAttributeValue(sh SessionHandle, o ObjectHandle, a []*Attribute
|
||||||
|
|
||||||
/* SetAttributeValue modifies the value of one or more object attributes */
|
/* SetAttributeValue modifies the value of one or more object attributes */
|
||||||
func (c *Ctx) SetAttributeValue(sh SessionHandle, o ObjectHandle, a []*Attribute) error {
|
func (c *Ctx) SetAttributeValue(sh SessionHandle, o ObjectHandle, a []*Attribute) error {
|
||||||
pa, palen := cAttributeList(a)
|
arena, pa, palen := cAttributeList(a)
|
||||||
|
defer arena.Free()
|
||||||
e := C.SetAttributeValue(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_OBJECT_HANDLE(o), pa, palen)
|
e := C.SetAttributeValue(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_OBJECT_HANDLE(o), pa, palen)
|
||||||
return toError(e)
|
return toError(e)
|
||||||
}
|
}
|
||||||
|
@ -1067,7 +1073,8 @@ func (c *Ctx) SetAttributeValue(sh SessionHandle, o ObjectHandle, a []*Attribute
|
||||||
// FindObjectsInit initializes a search for token and session
|
// FindObjectsInit initializes a search for token and session
|
||||||
// objects that match a template.
|
// objects that match a template.
|
||||||
func (c *Ctx) FindObjectsInit(sh SessionHandle, temp []*Attribute) error {
|
func (c *Ctx) FindObjectsInit(sh SessionHandle, temp []*Attribute) error {
|
||||||
t, tcount := cAttributeList(temp)
|
arena, t, tcount := cAttributeList(temp)
|
||||||
|
defer arena.Free()
|
||||||
e := C.FindObjectsInit(c.ctx, C.CK_SESSION_HANDLE(sh), t, tcount)
|
e := C.FindObjectsInit(c.ctx, C.CK_SESSION_HANDLE(sh), t, tcount)
|
||||||
return toError(e)
|
return toError(e)
|
||||||
}
|
}
|
||||||
|
@ -1103,7 +1110,8 @@ func (c *Ctx) FindObjectsFinal(sh SessionHandle) error {
|
||||||
|
|
||||||
/* EncryptInit initializes an encryption operation. */
|
/* EncryptInit initializes an encryption operation. */
|
||||||
func (c *Ctx) EncryptInit(sh SessionHandle, m []*Mechanism, o ObjectHandle) error {
|
func (c *Ctx) EncryptInit(sh SessionHandle, m []*Mechanism, o ObjectHandle) error {
|
||||||
mech, _ := cMechanismList(m)
|
arena, mech, _ := cMechanismList(m)
|
||||||
|
defer arena.Free()
|
||||||
e := C.EncryptInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(o))
|
e := C.EncryptInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(o))
|
||||||
return toError(e)
|
return toError(e)
|
||||||
}
|
}
|
||||||
|
@ -1155,7 +1163,8 @@ func (c *Ctx) EncryptFinal(sh SessionHandle) ([]byte, error) {
|
||||||
|
|
||||||
/* DecryptInit initializes a decryption operation. */
|
/* DecryptInit initializes a decryption operation. */
|
||||||
func (c *Ctx) DecryptInit(sh SessionHandle, m []*Mechanism, o ObjectHandle) error {
|
func (c *Ctx) DecryptInit(sh SessionHandle, m []*Mechanism, o ObjectHandle) error {
|
||||||
mech, _ := cMechanismList(m)
|
arena, mech, _ := cMechanismList(m)
|
||||||
|
defer arena.Free()
|
||||||
e := C.DecryptInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(o))
|
e := C.DecryptInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(o))
|
||||||
return toError(e)
|
return toError(e)
|
||||||
}
|
}
|
||||||
|
@ -1207,7 +1216,8 @@ func (c *Ctx) DecryptFinal(sh SessionHandle) ([]byte, error) {
|
||||||
|
|
||||||
/* DigestInit initializes a message-digesting operation. */
|
/* DigestInit initializes a message-digesting operation. */
|
||||||
func (c *Ctx) DigestInit(sh SessionHandle, m []*Mechanism) error {
|
func (c *Ctx) DigestInit(sh SessionHandle, m []*Mechanism) error {
|
||||||
mech, _ := cMechanismList(m)
|
arena, mech, _ := cMechanismList(m)
|
||||||
|
defer arena.Free()
|
||||||
e := C.DigestInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech)
|
e := C.DigestInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech)
|
||||||
return toError(e)
|
return toError(e)
|
||||||
}
|
}
|
||||||
|
@ -1267,7 +1277,8 @@ func (c *Ctx) DigestFinal(sh SessionHandle) ([]byte, error) {
|
||||||
// the data, and plaintext cannot be recovered from the
|
// the data, and plaintext cannot be recovered from the
|
||||||
// signature.
|
// signature.
|
||||||
func (c *Ctx) SignInit(sh SessionHandle, m []*Mechanism, o ObjectHandle) error {
|
func (c *Ctx) SignInit(sh SessionHandle, m []*Mechanism, o ObjectHandle) error {
|
||||||
mech, _ := cMechanismList(m) // Only the first is used, but still use a list.
|
arena, mech, _ := cMechanismList(m) // Only the first is used, but still use a list.
|
||||||
|
defer arena.Free()
|
||||||
e := C.SignInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(o))
|
e := C.SignInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(o))
|
||||||
return toError(e)
|
return toError(e)
|
||||||
}
|
}
|
||||||
|
@ -1314,7 +1325,8 @@ func (c *Ctx) SignFinal(sh SessionHandle) ([]byte, error) {
|
||||||
// SignRecoverInit initializes a signature operation, where
|
// SignRecoverInit initializes a signature operation, where
|
||||||
// the data can be recovered from the signature.
|
// the data can be recovered from the signature.
|
||||||
func (c *Ctx) SignRecoverInit(sh SessionHandle, m []*Mechanism, key ObjectHandle) error {
|
func (c *Ctx) SignRecoverInit(sh SessionHandle, m []*Mechanism, key ObjectHandle) error {
|
||||||
mech, _ := cMechanismList(m)
|
arena, mech, _ := cMechanismList(m)
|
||||||
|
defer arena.Free()
|
||||||
e := C.SignRecoverInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(key))
|
e := C.SignRecoverInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(key))
|
||||||
return toError(e)
|
return toError(e)
|
||||||
}
|
}
|
||||||
|
@ -1339,7 +1351,8 @@ func (c *Ctx) SignRecover(sh SessionHandle, data []byte) ([]byte, error) {
|
||||||
// signature is an appendix to the data, and plaintext cannot
|
// signature is an appendix to the data, and plaintext cannot
|
||||||
// be recovered from the signature (e.g. DSA).
|
// be recovered from the signature (e.g. DSA).
|
||||||
func (c *Ctx) VerifyInit(sh SessionHandle, m []*Mechanism, key ObjectHandle) error {
|
func (c *Ctx) VerifyInit(sh SessionHandle, m []*Mechanism, key ObjectHandle) error {
|
||||||
mech, _ := cMechanismList(m) // only use one here
|
arena, mech, _ := cMechanismList(m) // only use one here
|
||||||
|
defer arena.Free()
|
||||||
e := C.VerifyInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(key))
|
e := C.VerifyInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(key))
|
||||||
return toError(e)
|
return toError(e)
|
||||||
}
|
}
|
||||||
|
@ -1370,7 +1383,8 @@ func (c *Ctx) VerifyFinal(sh SessionHandle, signature []byte) error {
|
||||||
// VerifyRecoverInit initializes a signature verification
|
// VerifyRecoverInit initializes a signature verification
|
||||||
// operation, where the data is recovered from the signature.
|
// operation, where the data is recovered from the signature.
|
||||||
func (c *Ctx) VerifyRecoverInit(sh SessionHandle, m []*Mechanism, key ObjectHandle) error {
|
func (c *Ctx) VerifyRecoverInit(sh SessionHandle, m []*Mechanism, key ObjectHandle) error {
|
||||||
mech, _ := cMechanismList(m)
|
arena, mech, _ := cMechanismList(m)
|
||||||
|
defer arena.Free()
|
||||||
e := C.VerifyRecoverInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(key))
|
e := C.VerifyRecoverInit(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(key))
|
||||||
return toError(e)
|
return toError(e)
|
||||||
}
|
}
|
||||||
|
@ -1455,8 +1469,10 @@ func (c *Ctx) DecryptVerifyUpdate(sh SessionHandle, cipher []byte) ([]byte, erro
|
||||||
/* GenerateKey generates a secret key, creating a new key object. */
|
/* GenerateKey generates a secret key, creating a new key object. */
|
||||||
func (c *Ctx) GenerateKey(sh SessionHandle, m []*Mechanism, temp []*Attribute) (ObjectHandle, error) {
|
func (c *Ctx) GenerateKey(sh SessionHandle, m []*Mechanism, temp []*Attribute) (ObjectHandle, error) {
|
||||||
var key C.CK_OBJECT_HANDLE
|
var key C.CK_OBJECT_HANDLE
|
||||||
t, tcount := cAttributeList(temp)
|
attrarena, t, tcount := cAttributeList(temp)
|
||||||
mech, _ := cMechanismList(m)
|
defer attrarena.Free()
|
||||||
|
mecharena, mech, _ := cMechanismList(m)
|
||||||
|
defer mecharena.Free()
|
||||||
e := C.GenerateKey(c.ctx, C.CK_SESSION_HANDLE(sh), mech, t, tcount, C.CK_OBJECT_HANDLE_PTR(&key))
|
e := C.GenerateKey(c.ctx, C.CK_SESSION_HANDLE(sh), mech, t, tcount, C.CK_OBJECT_HANDLE_PTR(&key))
|
||||||
e1 := toError(e)
|
e1 := toError(e)
|
||||||
if e1 == nil {
|
if e1 == nil {
|
||||||
|
@ -1471,9 +1487,12 @@ func (c *Ctx) GenerateKeyPair(sh SessionHandle, m []*Mechanism, public, private
|
||||||
pubkey C.CK_OBJECT_HANDLE
|
pubkey C.CK_OBJECT_HANDLE
|
||||||
privkey C.CK_OBJECT_HANDLE
|
privkey C.CK_OBJECT_HANDLE
|
||||||
)
|
)
|
||||||
pub, pubcount := cAttributeList(public)
|
pubarena, pub, pubcount := cAttributeList(public)
|
||||||
priv, privcount := cAttributeList(private)
|
defer pubarena.Free()
|
||||||
mech, _ := cMechanismList(m)
|
privarena, priv, privcount := cAttributeList(private)
|
||||||
|
defer privarena.Free()
|
||||||
|
mecharena, mech, _ := cMechanismList(m)
|
||||||
|
defer mecharena.Free()
|
||||||
e := C.GenerateKeyPair(c.ctx, C.CK_SESSION_HANDLE(sh), mech, pub, pubcount, priv, privcount, C.CK_OBJECT_HANDLE_PTR(&pubkey), C.CK_OBJECT_HANDLE_PTR(&privkey))
|
e := C.GenerateKeyPair(c.ctx, C.CK_SESSION_HANDLE(sh), mech, pub, pubcount, priv, privcount, C.CK_OBJECT_HANDLE_PTR(&pubkey), C.CK_OBJECT_HANDLE_PTR(&privkey))
|
||||||
e1 := toError(e)
|
e1 := toError(e)
|
||||||
if e1 == nil {
|
if e1 == nil {
|
||||||
|
@ -1488,7 +1507,8 @@ func (c *Ctx) WrapKey(sh SessionHandle, m []*Mechanism, wrappingkey, key ObjectH
|
||||||
wrappedkey C.CK_BYTE_PTR
|
wrappedkey C.CK_BYTE_PTR
|
||||||
wrappedkeylen C.CK_ULONG
|
wrappedkeylen C.CK_ULONG
|
||||||
)
|
)
|
||||||
mech, _ := cMechanismList(m)
|
arena, mech, _ := cMechanismList(m)
|
||||||
|
defer arena.Free()
|
||||||
e := C.WrapKey(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(wrappingkey), C.CK_OBJECT_HANDLE(key), &wrappedkey, &wrappedkeylen)
|
e := C.WrapKey(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(wrappingkey), C.CK_OBJECT_HANDLE(key), &wrappedkey, &wrappedkeylen)
|
||||||
if toError(e) != nil {
|
if toError(e) != nil {
|
||||||
return nil, toError(e)
|
return nil, toError(e)
|
||||||
|
@ -1501,8 +1521,10 @@ func (c *Ctx) WrapKey(sh SessionHandle, m []*Mechanism, wrappingkey, key ObjectH
|
||||||
/* UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object. */
|
/* UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object. */
|
||||||
func (c *Ctx) UnwrapKey(sh SessionHandle, m []*Mechanism, unwrappingkey ObjectHandle, wrappedkey []byte, a []*Attribute) (ObjectHandle, error) {
|
func (c *Ctx) UnwrapKey(sh SessionHandle, m []*Mechanism, unwrappingkey ObjectHandle, wrappedkey []byte, a []*Attribute) (ObjectHandle, error) {
|
||||||
var key C.CK_OBJECT_HANDLE
|
var key C.CK_OBJECT_HANDLE
|
||||||
ac, aclen := cAttributeList(a)
|
attrarena, ac, aclen := cAttributeList(a)
|
||||||
mech, _ := cMechanismList(m)
|
defer attrarena.Free()
|
||||||
|
mecharena, mech, _ := cMechanismList(m)
|
||||||
|
defer mecharena.Free()
|
||||||
e := C.UnwrapKey(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(unwrappingkey), C.CK_BYTE_PTR(unsafe.Pointer(&wrappedkey[0])), C.CK_ULONG(len(wrappedkey)), ac, aclen, &key)
|
e := C.UnwrapKey(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(unwrappingkey), C.CK_BYTE_PTR(unsafe.Pointer(&wrappedkey[0])), C.CK_ULONG(len(wrappedkey)), ac, aclen, &key)
|
||||||
return ObjectHandle(key), toError(e)
|
return ObjectHandle(key), toError(e)
|
||||||
}
|
}
|
||||||
|
@ -1510,8 +1532,10 @@ func (c *Ctx) UnwrapKey(sh SessionHandle, m []*Mechanism, unwrappingkey ObjectHa
|
||||||
// DeriveKey derives a key from a base key, creating a new key object. */
|
// DeriveKey derives a key from a base key, creating a new key object. */
|
||||||
func (c *Ctx) DeriveKey(sh SessionHandle, m []*Mechanism, basekey ObjectHandle, a []*Attribute) (ObjectHandle, error) {
|
func (c *Ctx) DeriveKey(sh SessionHandle, m []*Mechanism, basekey ObjectHandle, a []*Attribute) (ObjectHandle, error) {
|
||||||
var key C.CK_OBJECT_HANDLE
|
var key C.CK_OBJECT_HANDLE
|
||||||
ac, aclen := cAttributeList(a)
|
attrarena, ac, aclen := cAttributeList(a)
|
||||||
mech, _ := cMechanismList(m)
|
defer attrarena.Free()
|
||||||
|
mecharena, mech, _ := cMechanismList(m)
|
||||||
|
defer mecharena.Free()
|
||||||
e := C.DeriveKey(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(basekey), ac, aclen, &key)
|
e := C.DeriveKey(c.ctx, C.CK_SESSION_HANDLE(sh), mech, C.CK_OBJECT_HANDLE(basekey), ac, aclen, &key)
|
||||||
return ObjectHandle(key), toError(e)
|
return ObjectHandle(key), toError(e)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,49 +9,91 @@ package pkcs11
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
This test supports the following environment variables:
|
||||||
|
|
||||||
|
* SOFTHSM_LIB: complete path to libsofthsm.so
|
||||||
|
* SOFTHSM_TOKENLABEL
|
||||||
|
* SOFTHSM_PRIVKEYLABEL
|
||||||
|
* SOFTHSM_PIN
|
||||||
|
*/
|
||||||
|
|
||||||
func setenv(t *testing.T) *Ctx {
|
func setenv(t *testing.T) *Ctx {
|
||||||
wd, _ := os.Getwd()
|
lib := "/usr/lib/softhsm/libsofthsm.so"
|
||||||
os.Setenv("SOFTHSM_CONF", wd+"/softhsm.conf")
|
if x := os.Getenv("SOFTHSM_LIB"); x != "" {
|
||||||
p := New("/usr/lib/softhsm/libsofthsm.so") //p := New("/home/miek/libsofthsm.so")
|
lib = x
|
||||||
|
}
|
||||||
|
t.Logf("loading %s", lib)
|
||||||
|
p := New(lib)
|
||||||
if p == nil {
|
if p == nil {
|
||||||
t.Fatal("Failed to init lib")
|
t.Fatal("Failed to init lib")
|
||||||
}
|
}
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetenv(t *testing.T) {
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
os.Setenv("SOFTHSM_CONF", wd+"/softhsm.conf")
|
||||||
|
|
||||||
|
lib := "/usr/lib/softhsm/libsofthsm.so"
|
||||||
|
if x := os.Getenv("SOFTHSM_LIB"); x != "" {
|
||||||
|
lib = x
|
||||||
|
}
|
||||||
|
p := New(lib)
|
||||||
|
if p == nil {
|
||||||
|
t.Fatal("Failed to init pkcs11")
|
||||||
|
}
|
||||||
|
p.Destroy()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func getSession(p *Ctx, t *testing.T) SessionHandle {
|
func getSession(p *Ctx, t *testing.T) SessionHandle {
|
||||||
if e := p.Initialize(); e != nil {
|
if e := p.Initialize(); e != nil {
|
||||||
t.Fatalf("init error %s\n", e.Error())
|
t.Fatalf("init error %s\n", e)
|
||||||
}
|
}
|
||||||
slots, e := p.GetSlotList(true)
|
slots, e := p.GetSlotList(true)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
t.Fatalf("slots %s\n", e.Error())
|
t.Fatalf("slots %s\n", e)
|
||||||
}
|
}
|
||||||
session, e := p.OpenSession(slots[0], CKF_SERIAL_SESSION)
|
session, e := p.OpenSession(slots[0], CKF_SERIAL_SESSION)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
t.Fatalf("session %s\n", e.Error())
|
t.Fatalf("session %s\n", e)
|
||||||
}
|
}
|
||||||
if e := p.Login(session, CKU_USER, "1234"); e != nil {
|
if e := p.Login(session, CKU_USER, pin); e != nil {
|
||||||
t.Fatal("user pin %s\n", e.Error())
|
t.Fatalf("user pin %s\n", e)
|
||||||
}
|
}
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInitialize(t *testing.T) {
|
||||||
|
p := setenv(t)
|
||||||
|
if e := p.Initialize(); e != nil {
|
||||||
|
t.Fatalf("init error %s\n", e)
|
||||||
|
}
|
||||||
|
p.Finalize()
|
||||||
|
p.Destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
func finishSession(p *Ctx, session SessionHandle) {
|
||||||
|
p.Logout(session)
|
||||||
|
p.CloseSession(session)
|
||||||
|
p.Finalize()
|
||||||
|
p.Destroy()
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetInfo(t *testing.T) {
|
func TestGetInfo(t *testing.T) {
|
||||||
p := setenv(t)
|
p := setenv(t)
|
||||||
session := getSession(p, t)
|
session := getSession(p, t)
|
||||||
defer p.Logout(session)
|
defer finishSession(p, session)
|
||||||
defer p.CloseSession(session)
|
|
||||||
defer p.Finalize()
|
|
||||||
defer p.Destroy()
|
|
||||||
info, err := p.GetInfo()
|
info, err := p.GetInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Non zero error %s\n", err.Error())
|
t.Fatalf("non zero error %s\n", err)
|
||||||
}
|
}
|
||||||
if info.ManufacturerID != "SoftHSM" {
|
if info.ManufacturerID != "SoftHSM" {
|
||||||
t.Fatal("ID should be SoftHSM")
|
t.Fatal("ID should be SoftHSM")
|
||||||
|
@ -62,21 +104,18 @@ func TestGetInfo(t *testing.T) {
|
||||||
func TestFindObject(t *testing.T) {
|
func TestFindObject(t *testing.T) {
|
||||||
p := setenv(t)
|
p := setenv(t)
|
||||||
session := getSession(p, t)
|
session := getSession(p, t)
|
||||||
defer p.Logout(session)
|
defer finishSession(p, session)
|
||||||
defer p.CloseSession(session)
|
|
||||||
defer p.Finalize()
|
|
||||||
defer p.Destroy()
|
|
||||||
// There are 2 keys in the db with this tag
|
// There are 2 keys in the db with this tag
|
||||||
template := []*Attribute{NewAttribute(CKA_LABEL, "MyFirstKey")}
|
template := []*Attribute{NewAttribute(CKA_LABEL, "MyFirstKey")}
|
||||||
if e := p.FindObjectsInit(session, template); e != nil {
|
if e := p.FindObjectsInit(session, template); e != nil {
|
||||||
t.Fatalf("Failed to init: %s\n", e.Error())
|
t.Fatalf("failed to init: %s\n", e)
|
||||||
}
|
}
|
||||||
obj, b, e := p.FindObjects(session, 2)
|
obj, b, e := p.FindObjects(session, 2)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
t.Fatalf("Failed to find: %s %v\n", e.Error(), b)
|
t.Fatalf("failed to find: %s %v\n", e, b)
|
||||||
}
|
}
|
||||||
if e := p.FindObjectsFinal(session); e != nil {
|
if e := p.FindObjectsFinal(session); e != nil {
|
||||||
t.Fatalf("Failed to finalize: %s\n", e.Error())
|
t.Fatalf("failed to finalize: %s\n", e)
|
||||||
}
|
}
|
||||||
if len(obj) != 2 {
|
if len(obj) != 2 {
|
||||||
t.Fatal("should have found two objects")
|
t.Fatal("should have found two objects")
|
||||||
|
@ -86,10 +125,7 @@ func TestFindObject(t *testing.T) {
|
||||||
func TestGetAttributeValue(t *testing.T) {
|
func TestGetAttributeValue(t *testing.T) {
|
||||||
p := setenv(t)
|
p := setenv(t)
|
||||||
session := getSession(p, t)
|
session := getSession(p, t)
|
||||||
defer p.Logout(session)
|
defer finishSession(p, session)
|
||||||
defer p.Destroy()
|
|
||||||
defer p.Finalize()
|
|
||||||
defer p.CloseSession(session)
|
|
||||||
// There are at least two RSA keys in the hsm.db, objecthandle 1 and 2.
|
// There are at least two RSA keys in the hsm.db, objecthandle 1 and 2.
|
||||||
template := []*Attribute{
|
template := []*Attribute{
|
||||||
NewAttribute(CKA_PUBLIC_EXPONENT, nil),
|
NewAttribute(CKA_PUBLIC_EXPONENT, nil),
|
||||||
|
@ -100,14 +136,14 @@ func TestGetAttributeValue(t *testing.T) {
|
||||||
// ObjectHandle two is the public key
|
// ObjectHandle two is the public key
|
||||||
attr, err := p.GetAttributeValue(session, ObjectHandle(2), template)
|
attr, err := p.GetAttributeValue(session, ObjectHandle(2), template)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err %s\n", err.Error())
|
t.Fatalf("err %s\n", err)
|
||||||
}
|
}
|
||||||
for i, a := range attr {
|
for i, a := range attr {
|
||||||
t.Logf("Attr %d, type %d, valuelen %d", i, a.Type, len(a.Value))
|
t.Logf("attr %d, type %d, valuelen %d", i, a.Type, len(a.Value))
|
||||||
if a.Type == CKA_MODULUS {
|
if a.Type == CKA_MODULUS {
|
||||||
mod := big.NewInt(0)
|
mod := big.NewInt(0)
|
||||||
mod.SetBytes(a.Value)
|
mod.SetBytes(a.Value)
|
||||||
t.Logf("Modulus %s\n", mod.String())
|
t.Logf("modulus %s\n", mod.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,18 +151,15 @@ func TestGetAttributeValue(t *testing.T) {
|
||||||
func TestDigest(t *testing.T) {
|
func TestDigest(t *testing.T) {
|
||||||
p := setenv(t)
|
p := setenv(t)
|
||||||
session := getSession(p, t)
|
session := getSession(p, t)
|
||||||
defer p.Logout(session)
|
defer finishSession(p, session)
|
||||||
defer p.CloseSession(session)
|
|
||||||
defer p.Finalize()
|
|
||||||
defer p.Destroy()
|
|
||||||
e := p.DigestInit(session, []*Mechanism{NewMechanism(CKM_SHA_1, nil)})
|
e := p.DigestInit(session, []*Mechanism{NewMechanism(CKM_SHA_1, nil)})
|
||||||
if e != nil {
|
if e != nil {
|
||||||
t.Fatalf("DigestInit: %s\n", e.Error())
|
t.Fatalf("DigestInit: %s\n", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
hash, e := p.Digest(session, []byte("this is a string"))
|
hash, e := p.Digest(session, []byte("this is a string"))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
t.Fatalf("Digest: %s\n", e.Error())
|
t.Fatalf("digest: %s\n", e)
|
||||||
}
|
}
|
||||||
hex := ""
|
hex := ""
|
||||||
for _, d := range hash {
|
for _, d := range hash {
|
||||||
|
@ -141,22 +174,19 @@ func TestDigest(t *testing.T) {
|
||||||
func TestDigestUpdate(t *testing.T) {
|
func TestDigestUpdate(t *testing.T) {
|
||||||
p := setenv(t)
|
p := setenv(t)
|
||||||
session := getSession(p, t)
|
session := getSession(p, t)
|
||||||
defer p.Logout(session)
|
defer finishSession(p, session)
|
||||||
defer p.CloseSession(session)
|
|
||||||
defer p.Finalize()
|
|
||||||
defer p.Destroy()
|
|
||||||
if e := p.DigestInit(session, []*Mechanism{NewMechanism(CKM_SHA_1, nil)}); e != nil {
|
if e := p.DigestInit(session, []*Mechanism{NewMechanism(CKM_SHA_1, nil)}); e != nil {
|
||||||
t.Fatalf("DigestInit: %s\n", e.Error())
|
t.Fatalf("DigestInit: %s\n", e)
|
||||||
}
|
}
|
||||||
if e := p.DigestUpdate(session, []byte("this is ")); e != nil {
|
if e := p.DigestUpdate(session, []byte("this is ")); e != nil {
|
||||||
t.Fatalf("DigestUpdate: %s\n", e.Error())
|
t.Fatalf("DigestUpdate: %s\n", e)
|
||||||
}
|
}
|
||||||
if e := p.DigestUpdate(session, []byte("a string")); e != nil {
|
if e := p.DigestUpdate(session, []byte("a string")); e != nil {
|
||||||
t.Fatalf("DigestUpdate: %s\n", e.Error())
|
t.Fatalf("DigestUpdate: %s\n", e)
|
||||||
}
|
}
|
||||||
hash, e := p.DigestFinal(session)
|
hash, e := p.DigestFinal(session)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
t.Fatalf("DigestFinal: %s\n", e.Error())
|
t.Fatalf("DigestFinal: %s\n", e)
|
||||||
}
|
}
|
||||||
hex := ""
|
hex := ""
|
||||||
for _, d := range hash {
|
for _, d := range hash {
|
||||||
|
@ -166,47 +196,95 @@ func TestDigestUpdate(t *testing.T) {
|
||||||
if hex != "517592df8fec3ad146a79a9af153db2a4d784ec5" {
|
if hex != "517592df8fec3ad146a79a9af153db2a4d784ec5" {
|
||||||
t.Fatalf("wrong digest: %s", hex)
|
t.Fatalf("wrong digest: %s", hex)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateRSAKeyPair(t *testing.T, p *Ctx, session SessionHandle) (ObjectHandle, ObjectHandle) {
|
||||||
|
publicKeyTemplate := []*Attribute{
|
||||||
|
NewAttribute(CKA_KEY_TYPE, CKO_PUBLIC_KEY),
|
||||||
|
NewAttribute(CKA_TOKEN, false),
|
||||||
|
NewAttribute(CKA_VERIFY, true),
|
||||||
|
NewAttribute(CKA_PUBLIC_EXPONENT, []byte{1, 0, 1}),
|
||||||
|
NewAttribute(CKA_MODULUS_BITS, 2048),
|
||||||
|
NewAttribute(CKA_LABEL, "TestPbk"),
|
||||||
|
}
|
||||||
|
privateKeyTemplate := []*Attribute{
|
||||||
|
NewAttribute(CKA_TOKEN, false),
|
||||||
|
NewAttribute(CKA_SIGN, true),
|
||||||
|
NewAttribute(CKA_LABEL, "TestPvk"),
|
||||||
|
NewAttribute(CKA_SENSITIVE, true),
|
||||||
|
NewAttribute(CKA_EXTRACTABLE, true),
|
||||||
|
}
|
||||||
|
pbk, pvk, e := p.GenerateKeyPair(session,
|
||||||
|
[]*Mechanism{NewMechanism(CKM_RSA_PKCS_KEY_PAIR_GEN, nil)},
|
||||||
|
publicKeyTemplate, privateKeyTemplate)
|
||||||
|
if e != nil {
|
||||||
|
t.Fatalf("failed to generate keypair: %s\n", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pbk, pvk
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateKeyPair(t *testing.T) {
|
||||||
|
p := setenv(t)
|
||||||
|
session := getSession(p, t)
|
||||||
|
defer finishSession(p, session)
|
||||||
|
generateRSAKeyPair(t, p, session)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSign(t *testing.T) {
|
||||||
|
p := setenv(t)
|
||||||
|
session := getSession(p, t)
|
||||||
|
defer finishSession(p, session)
|
||||||
|
_, pvk := generateRSAKeyPair(t, p, session)
|
||||||
|
|
||||||
|
p.SignInit(session, []*Mechanism{NewMechanism(CKM_SHA1_RSA_PKCS, nil)}, pvk)
|
||||||
|
_, e := p.Sign(session, []byte("Sign me!"))
|
||||||
|
if e != nil {
|
||||||
|
t.Fatalf("failed to sign: %s\n", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDestroyObject(t *testing.T) {
|
func testDestroyObject(t *testing.T) {
|
||||||
p := setenv(t)
|
p := setenv(t)
|
||||||
session := getSession(p, t)
|
session := getSession(p, t)
|
||||||
defer p.Logout(session)
|
defer finishSession(p, session)
|
||||||
defer p.CloseSession(session)
|
|
||||||
defer p.Finalize()
|
|
||||||
defer p.Destroy()
|
|
||||||
|
|
||||||
p.Logout(session) // log out the normal user
|
p.Logout(session) // log out the normal user
|
||||||
if e := p.Login(session, CKU_SO, "1234"); e != nil {
|
if e := p.Login(session, CKU_SO, "1234"); e != nil {
|
||||||
t.Fatal("security officer pin %s\n", e.Error())
|
t.Fatalf("security officer pin %s\n", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Looking the int values is tricky because they are stored in 64 bits in hsm.db,
|
|
||||||
// this means looking up stuff on 32 bits will not found them.
|
|
||||||
template := []*Attribute{
|
template := []*Attribute{
|
||||||
NewAttribute(CKA_LABEL, "MyFirstKey")}
|
NewAttribute(CKA_LABEL, "MyFirstKey")}
|
||||||
|
|
||||||
if e := p.FindObjectsInit(session, template); e != nil {
|
if e := p.FindObjectsInit(session, template); e != nil {
|
||||||
t.Fatalf("Failed to init: %s\n", e.Error())
|
t.Fatalf("failed to init: %s\n", e)
|
||||||
}
|
}
|
||||||
obj, _, e := p.FindObjects(session, 1)
|
obj, _, e := p.FindObjects(session, 1)
|
||||||
if e != nil || len(obj) == 0 {
|
if e != nil || len(obj) == 0 {
|
||||||
t.Fatalf("Failed to find objects\n")
|
t.Fatalf("failed to find objects\n")
|
||||||
}
|
}
|
||||||
if e := p.FindObjectsFinal(session); e != nil {
|
if e := p.FindObjectsFinal(session); e != nil {
|
||||||
t.Fatalf("Failed to finalize: %s\n", e.Error())
|
t.Fatalf("failed to finalize: %s\n", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.DestroyObject(session, obj[0]); err != nil {
|
if e := p.DestroyObject(session, obj[0]); e != nil {
|
||||||
t.Fatal("DestroyObject failed" + err.Error())
|
t.Fatal("DestroyObject failed: %s\n", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExampleSign show how to sign some data with a private key.
|
// ExampleSign shows how to sign some data with a private key.
|
||||||
// Note: error correction is not implemented in this function.
|
// Note: error correction is not implemented in this example.
|
||||||
func ExampleSign() {
|
func ExampleSign() {
|
||||||
p := setenv(nil)
|
lib := "/usr/lib/softhsm/libsofthsm.so"
|
||||||
|
if x := os.Getenv("SOFTHSM_LIB"); x != "" {
|
||||||
|
lib = x
|
||||||
|
}
|
||||||
|
p := New(lib)
|
||||||
|
if p == nil {
|
||||||
|
log.Fatal("Failed to init lib")
|
||||||
|
}
|
||||||
|
|
||||||
p.Initialize()
|
p.Initialize()
|
||||||
defer p.Destroy()
|
defer p.Destroy()
|
||||||
defer p.Finalize()
|
defer p.Finalize()
|
||||||
|
@ -217,7 +295,7 @@ func ExampleSign() {
|
||||||
defer p.Logout(session)
|
defer p.Logout(session)
|
||||||
publicKeyTemplate := []*Attribute{
|
publicKeyTemplate := []*Attribute{
|
||||||
NewAttribute(CKA_KEY_TYPE, CKO_PUBLIC_KEY),
|
NewAttribute(CKA_KEY_TYPE, CKO_PUBLIC_KEY),
|
||||||
NewAttribute(CKA_TOKEN, true),
|
NewAttribute(CKA_TOKEN, false),
|
||||||
NewAttribute(CKA_ENCRYPT, true),
|
NewAttribute(CKA_ENCRYPT, true),
|
||||||
NewAttribute(CKA_PUBLIC_EXPONENT, []byte{3}),
|
NewAttribute(CKA_PUBLIC_EXPONENT, []byte{3}),
|
||||||
NewAttribute(CKA_MODULUS_BITS, 1024),
|
NewAttribute(CKA_MODULUS_BITS, 1024),
|
||||||
|
@ -225,18 +303,26 @@ func ExampleSign() {
|
||||||
}
|
}
|
||||||
privateKeyTemplate := []*Attribute{
|
privateKeyTemplate := []*Attribute{
|
||||||
NewAttribute(CKA_KEY_TYPE, CKO_PRIVATE_KEY),
|
NewAttribute(CKA_KEY_TYPE, CKO_PRIVATE_KEY),
|
||||||
NewAttribute(CKA_TOKEN, true),
|
NewAttribute(CKA_TOKEN, false),
|
||||||
NewAttribute(CKA_PRIVATE, true),
|
NewAttribute(CKA_PRIVATE, true),
|
||||||
NewAttribute(CKA_SIGN, true),
|
NewAttribute(CKA_SIGN, true),
|
||||||
NewAttribute(CKA_LABEL, "MyFirstKey"),
|
NewAttribute(CKA_LABEL, "MyFirstKey"),
|
||||||
}
|
}
|
||||||
pub, priv, _ := p.GenerateKeyPair(session,
|
_, priv, err := p.GenerateKeyPair(session,
|
||||||
[]*Mechanism{NewMechanism(CKM_RSA_PKCS_KEY_PAIR_GEN, nil)},
|
[]*Mechanism{NewMechanism(CKM_RSA_PKCS_KEY_PAIR_GEN, nil)},
|
||||||
publicKeyTemplate, privateKeyTemplate)
|
publicKeyTemplate, privateKeyTemplate)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
p.SignInit(session, []*Mechanism{NewMechanism(CKM_SHA1_RSA_PKCS, nil)}, priv)
|
p.SignInit(session, []*Mechanism{NewMechanism(CKM_SHA1_RSA_PKCS, nil)}, priv)
|
||||||
// Sign something with the private key.
|
// Sign something with the private key.
|
||||||
data := []byte("Lets sign this data")
|
data := []byte("Lets sign this data")
|
||||||
|
|
||||||
sig, _ := p.Sign(session, data)
|
_, err = p.Sign(session, data)
|
||||||
fmt.Printf("%v validate with %v\n", sig, pub)
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("It works!")
|
||||||
|
// Output: It works!
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,17 +15,13 @@ package pkcs11
|
||||||
#define CK_CALLBACK_FUNCTION(returnType, name) returnType (* name)
|
#define CK_CALLBACK_FUNCTION(returnType, name) returnType (* name)
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include "pkcs11.h"
|
#include "pkcs11.h"
|
||||||
|
|
||||||
CK_ULONG Index(CK_ULONG_PTR array, CK_ULONG i)
|
CK_ULONG Index(CK_ULONG_PTR array, CK_ULONG i)
|
||||||
{
|
{
|
||||||
return array[i];
|
return array[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
CK_ULONG Sizeof()
|
|
||||||
{
|
|
||||||
return sizeof(CK_ULONG);
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
|
@ -35,6 +31,21 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type arena []unsafe.Pointer
|
||||||
|
|
||||||
|
func (a *arena) Allocate(obj []byte) (C.CK_VOID_PTR, C.CK_ULONG) {
|
||||||
|
cobj := C.calloc(C.size_t(len(obj)), 1)
|
||||||
|
*a = append(*a, cobj)
|
||||||
|
C.memmove(cobj, unsafe.Pointer(&obj[0]), C.size_t(len(obj)))
|
||||||
|
return C.CK_VOID_PTR(cobj), C.CK_ULONG(len(obj))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a arena) Free() {
|
||||||
|
for _, p := range a {
|
||||||
|
C.free(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// toList converts from a C style array to a []uint.
|
// toList converts from a C style array to a []uint.
|
||||||
func toList(clist C.CK_ULONG_PTR, size C.CK_ULONG) []uint {
|
func toList(clist C.CK_ULONG_PTR, size C.CK_ULONG) []uint {
|
||||||
l := make([]uint, int(size))
|
l := make([]uint, int(size))
|
||||||
|
@ -53,6 +64,11 @@ func cBBool(x bool) C.CK_BBOOL {
|
||||||
return C.CK_BBOOL(C.CK_FALSE)
|
return C.CK_BBOOL(C.CK_FALSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func uintToBytes(x uint64) []byte {
|
||||||
|
ul := C.CK_ULONG(x)
|
||||||
|
return C.GoBytes(unsafe.Pointer(&ul), C.int(unsafe.Sizeof(ul)))
|
||||||
|
}
|
||||||
|
|
||||||
// Error represents an PKCS#11 error.
|
// Error represents an PKCS#11 error.
|
||||||
type Error uint
|
type Error uint
|
||||||
|
|
||||||
|
@ -156,46 +172,23 @@ func NewAttribute(typ uint, x interface{}) *Attribute {
|
||||||
if x == nil {
|
if x == nil {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
switch x.(type) {
|
switch v := x.(type) {
|
||||||
case bool: // create bbool
|
case bool:
|
||||||
if x.(bool) {
|
if v {
|
||||||
a.Value = []byte{1}
|
a.Value = []byte{1}
|
||||||
break
|
} else {
|
||||||
}
|
a.Value = []byte{0}
|
||||||
a.Value = []byte{0}
|
|
||||||
case uint, int:
|
|
||||||
var y uint
|
|
||||||
if _, ok := x.(int); ok {
|
|
||||||
y = uint(x.(int))
|
|
||||||
}
|
|
||||||
if _, ok := x.(uint); ok {
|
|
||||||
y = x.(uint)
|
|
||||||
}
|
|
||||||
// TODO(miek): ugly!
|
|
||||||
switch int(C.Sizeof()) {
|
|
||||||
case 4:
|
|
||||||
a.Value = make([]byte, 4)
|
|
||||||
a.Value[0] = byte(y)
|
|
||||||
a.Value[1] = byte(y >> 8)
|
|
||||||
a.Value[2] = byte(y >> 16)
|
|
||||||
a.Value[3] = byte(y >> 24)
|
|
||||||
case 8:
|
|
||||||
a.Value = make([]byte, 8)
|
|
||||||
a.Value[0] = byte(y)
|
|
||||||
a.Value[1] = byte(y >> 8)
|
|
||||||
a.Value[2] = byte(y >> 16)
|
|
||||||
a.Value[3] = byte(y >> 24)
|
|
||||||
a.Value[4] = byte(y >> 32)
|
|
||||||
a.Value[5] = byte(y >> 40)
|
|
||||||
a.Value[6] = byte(y >> 48)
|
|
||||||
a.Value[7] = byte(y >> 56)
|
|
||||||
}
|
}
|
||||||
|
case int:
|
||||||
|
a.Value = uintToBytes(uint64(v))
|
||||||
|
case uint:
|
||||||
|
a.Value = uintToBytes(uint64(v))
|
||||||
case string:
|
case string:
|
||||||
a.Value = []byte(x.(string))
|
a.Value = []byte(v)
|
||||||
case []byte: // just copy
|
case []byte:
|
||||||
a.Value = x.([]byte)
|
a.Value = v
|
||||||
case time.Time: // for CKA_DATE
|
case time.Time: // for CKA_DATE
|
||||||
a.Value = cDate(x.(time.Time))
|
a.Value = cDate(v)
|
||||||
default:
|
default:
|
||||||
panic("pkcs11: unhandled attribute type")
|
panic("pkcs11: unhandled attribute type")
|
||||||
}
|
}
|
||||||
|
@ -203,9 +196,10 @@ func NewAttribute(typ uint, x interface{}) *Attribute {
|
||||||
}
|
}
|
||||||
|
|
||||||
// cAttribute returns the start address and the length of an attribute list.
|
// cAttribute returns the start address and the length of an attribute list.
|
||||||
func cAttributeList(a []*Attribute) (C.CK_ATTRIBUTE_PTR, C.CK_ULONG) {
|
func cAttributeList(a []*Attribute) (arena, C.CK_ATTRIBUTE_PTR, C.CK_ULONG) {
|
||||||
|
var arena arena
|
||||||
if len(a) == 0 {
|
if len(a) == 0 {
|
||||||
return nil, 0
|
return nil, nil, 0
|
||||||
}
|
}
|
||||||
pa := make([]C.CK_ATTRIBUTE, len(a))
|
pa := make([]C.CK_ATTRIBUTE, len(a))
|
||||||
for i := 0; i < len(a); i++ {
|
for i := 0; i < len(a); i++ {
|
||||||
|
@ -213,10 +207,9 @@ func cAttributeList(a []*Attribute) (C.CK_ATTRIBUTE_PTR, C.CK_ULONG) {
|
||||||
if a[i].Value == nil {
|
if a[i].Value == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pa[i].pValue = C.CK_VOID_PTR((&a[i].Value[0]))
|
pa[i].pValue, pa[i].ulValueLen = arena.Allocate(a[i].Value)
|
||||||
pa[i].ulValueLen = C.CK_ULONG(len(a[i].Value))
|
|
||||||
}
|
}
|
||||||
return C.CK_ATTRIBUTE_PTR(&pa[0]), C.CK_ULONG(len(a))
|
return arena, C.CK_ATTRIBUTE_PTR(&pa[0]), C.CK_ULONG(len(a))
|
||||||
}
|
}
|
||||||
|
|
||||||
func cDate(t time.Time) []byte {
|
func cDate(t time.Time) []byte {
|
||||||
|
@ -250,9 +243,10 @@ func NewMechanism(mech uint, x interface{}) *Mechanism {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func cMechanismList(m []*Mechanism) (C.CK_MECHANISM_PTR, C.CK_ULONG) {
|
func cMechanismList(m []*Mechanism) (arena, C.CK_MECHANISM_PTR, C.CK_ULONG) {
|
||||||
|
var arena arena
|
||||||
if len(m) == 0 {
|
if len(m) == 0 {
|
||||||
return nil, 0
|
return nil, nil, 0
|
||||||
}
|
}
|
||||||
pm := make([]C.CK_MECHANISM, len(m))
|
pm := make([]C.CK_MECHANISM, len(m))
|
||||||
for i := 0; i < len(m); i++ {
|
for i := 0; i < len(m); i++ {
|
||||||
|
@ -260,10 +254,9 @@ func cMechanismList(m []*Mechanism) (C.CK_MECHANISM_PTR, C.CK_ULONG) {
|
||||||
if m[i].Parameter == nil {
|
if m[i].Parameter == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pm[i].pParameter = C.CK_VOID_PTR(&(m[i].Parameter[0]))
|
pm[i].pParameter, pm[i].ulParameterLen = arena.Allocate(m[i].Parameter)
|
||||||
pm[i].ulParameterLen = C.CK_ULONG(len(m[i].Parameter))
|
|
||||||
}
|
}
|
||||||
return C.CK_MECHANISM_PTR(&pm[0]), C.CK_ULONG(len(m))
|
return arena, C.CK_MECHANISM_PTR(&pm[0]), C.CK_ULONG(len(m))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MechanismInfo provides information about a particular mechanism.
|
// MechanismInfo provides information about a particular mechanism.
|
||||||
|
|
Loading…
Reference in New Issue