Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correct conflicts and unit test failures in v3 branch #179

Open
wants to merge 21 commits into
base: v3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
74b2912
Also allow CK_ constants (#150)
miekg Jan 5, 2022
f348191
Release 1.1.1
miekg Jan 5, 2022
30f14c6
More complete parsing of pkcs11t.h (#151)
miekg Jan 5, 2022
7d14beb
Test the const generation (#152)
miekg Jan 6, 2022
0d6b531
Remove unnecessary defer from toList() function. (#153)
ansiwen Jan 16, 2022
ae8b125
Add the p11 PrivateKey.Derive() function (#128)
kula Jan 18, 2022
9a05b23
Remove unnecessary memory copies by C.GoBytes() calls (#154)
ansiwen Jan 26, 2022
8bb176f
p11: Add Mechanism.Type() and Mechanism.Parameter() (#160)
JeremyRand Sep 2, 2022
3e7a4ed
Add NSS vendor attributes from Mozilla Bug 1465613 (#163)
JeremyRand Nov 12, 2022
869c407
add KeyDerivationStringDataParams handling for Symmetric key derivation
pdtgct Nov 14, 2022
5434247
Call Finalize on Module destroy (#164)
op Nov 15, 2022
36266ad
Merge branch 'miekg:master' into master
pdtgct Dec 3, 2022
e93055c
Add RSA AES key wrap mechanism parameters (#166)
varder Feb 3, 2023
6953d31
Merge remote-tracking branch 'upstream/master'
pdtgct Apr 2, 2023
e678cf5
update to newer Go versions in workflow (#167)
miekg Jun 21, 2023
888df6a
Merge remote-tracking branch 'upstream/master'
Jul 28, 2023
40141f3
Merge branch 'master' of https://github.com/pdtgct/pkcs11
Jul 28, 2023
9078ad6
const_generate: hardcode CK_TRUE/CK_FALSE to golang bool values (#176)
stlaz Nov 15, 2023
0d7a868
Merge branch 'miekg:master' into master
pdtgct Nov 27, 2023
d1838b7
Merge branch 'master' into v3
Apr 6, 2024
bc123cc
fix test failure by regenerating zconst.go; update README.md
Apr 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go: [ 1.16.x, 1.17.x ]
go: [ 1.19.x, 1.20.x ]
steps:

- name: Set up Go
Expand Down
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# PKCS#11

This is a Go implementation of the PKCS#11 API. It wraps the library closely, but uses Go idiom where
it makes sense. It has been tested with SoftHSM.
This is a Go implementation of the PKCS#11 API. It wraps the library closely, but uses Go idioms where
they make sense. It has been tested with SoftHSM.

The version used is "PKCS #11 Cryptographic Token Interface Base Specification Version 3.0", see
<http://docs.oasis-open.org/pkcs11/pkcs11-base/v3.0/pkcs11-base-v3.0.html>. Note that the header
files listed there are *broken*, the fixed ones live in a [github repo](https://github.com/oasis-tcs/pkcs11/tree/master/working/headers).
From that repo commit 188b0b1024403f1907b6cf5fedc0bc148c2221a2 was pulled into this repository.
files listed there are *broken*, the fixed ones live in a [github repo](https://github.com/oasis-tcs/pkcs11/tree/pkcs11-3.00/published/3-00).
From that repo commit d8d3a0b7c47d7cc129063004f1fce6553bc70839 was pulled into this repository.

## SoftHSM

Expand All @@ -15,7 +15,7 @@ From that repo commit 188b0b1024403f1907b6cf5fedc0bc148c2221a2 was pulled into t
* Then use `softhsm` to init it

~~~
softhsm --init-token --slot 0 --label test --pin 1234
softhsm2-util --init-token --slot 0 --label test --pin 1234
~~~

* Then use `libsofthsm2.so` as the pkcs11 module:
Expand All @@ -24,6 +24,16 @@ From that repo commit 188b0b1024403f1907b6cf5fedc0bc148c2221a2 was pulled into t
p := pkcs11.New("/usr/lib/softhsm/libsofthsm2.so")
~~~

### Mac OS X

* If installing `softhsm` via `homebrew`, set the environment variable
`SOFTHSM_LIB` to the location of the homebrew installation:

~~~
export SOFTHSM_LIB=/opt/homebrew/Cellar/softhsm/2.6.1/lib/softhsm/libsofthsm2.so
~~~


## Examples

A skeleton program would look somewhat like this (yes, pkcs#11 is verbose):
Expand Down
84 changes: 71 additions & 13 deletions const_generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,35 +28,82 @@ func main() {

scanner := bufio.NewScanner(file)
fmt.Fprintln(out, "const (")
comment := ""
prevpre := ""
count := 0
for scanner.Scan() {
// Fairly simple parsing, any line starting with '#define' will output
// $2 = $3 and drop any UL (unsigned long) suffixes
// $2 = $3 and drop any UL (unsigned long) suffixes.
// Some care is taken to add any comments and make the outputted file
// have some decent godoc.
fields := strings.Fields(scanner.Text())
if len(fields) < 1 {
continue
}
if fields[0] == "/*" || fields[0] == "*" {
comment += "//" + scanner.Text()[2:]
comment = strings.TrimSuffix(comment, "*/")
comment += "\n"
continue
}

if len(fields) < 3 {
continue
}

if fields[0] != "#define" {
comment = ""
continue
}
if strings.HasPrefix(fields[1], "CK_") {
continue

if fields[1] == "_PKCS11T_H_" { // clear accumulated comments from the top of the file
comment = ""
}

// fields[1] (const name) needs to be 3 chars, starting with CK
if !strings.HasPrefix(fields[1], "CK") {
continue
}
value := strings.TrimSuffix(fields[2], "UL")
// special case for things like: (CKF_ARRAY_ATTRIBUTE|0x00000211UL)
if strings.HasSuffix(value, "UL)") {
value = strings.Replace(value, "UL)", ")", 1)

if x := fields[1][:3]; x != prevpre { // prefix change, insert a newline
fmt.Fprintln(out)
prevpre = x
}
// check for /* deprecated */ comment
if len(fields) == 6 && fields[4] == "Deprecated" {
fmt.Fprintln(out, fields[1], " = ", value, "// Deprecated")
continue

var value string
switch fields[1] {
case "CK_TRUE":
value = "true"
case "CK_FALSE":
value = "false"
default:
value = strings.TrimSuffix(fields[2], "UL")
// special case for things like: (CKF_ARRAY_ATTRIBUTE|0x00000211UL)
if strings.HasSuffix(value, "UL)") {
value = strings.Replace(value, "UL)", ")", 1)
}
// CK_UNAVAILABLE_INFORMATION is encoded as (~0) (with UL) removed, this needs to be ^uint(0) in Go.
// Special case that here.
if value == "(~0)" {
value = "^uint(0)"
}
}

if comment != "" {
fmt.Fprintln(out) // newline before comment
fmt.Fprint(out, comment)
comment = ""
}

fmt.Fprintln(out, fields[1], " = ", value)
// check for /* ... */ comments
linecomment := ""
if len(fields) >= 6 && fields[3] == "/*" {
linecomment = "// " + strings.Join(fields[4:], " ")
linecomment = strings.TrimSuffix(linecomment, "*/") // there is not always a space before */ so fields might not have all elements
}

fmt.Fprintln(out, fields[1], " = ", value, linecomment)
count++
}

if err := scanner.Err(); err != nil {
Expand All @@ -74,6 +121,18 @@ func main() {
}
f.Write(res)

// Used to double check what we generate. This prints (for 2.40 spec):
//
// "2022/01/05 12:50:28 Wrote 756 constants to zconst.go"
//
// A grep confirms this correct:
//
// % grep '^#define CK' pkcs11t.h |wc
// 756 2362 38807
//
// Also see const_test.go where we test this.
log.Printf("Wrote %d constants to zconst.go", count)

}

const header = `// Copyright 2013 Miek Gieben. All rights reserved.
Expand All @@ -82,7 +141,6 @@ const header = `// Copyright 2013 Miek Gieben. All rights reserved.

// Code generated by "go run const_generate.go"; DO NOT EDIT.


package pkcs11

`
43 changes: 43 additions & 0 deletions const_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package pkcs11

import (
"bytes"
"go/ast"
"go/parser"
"go/token"
"os/exec"
"testing"
)

func TestConstCouunt(t *testing.T) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "zconst.go", nil, 0)
if err != nil {
t.Fatal(err)
}

count := 0
// Range through declarations:
for _, dd := range f.Decls {
if gd, ok := dd.(*ast.GenDecl); ok {
if gd.Tok == token.CONST {
for range gd.Specs {
count++
}
}
}
}

// Now to validate, run a shell pipeline to get the number in a different way from pkcs11t.h .
grep := exec.Command("grep", "^#define CK", "pkcs11t.h")
out, err := grep.Output()
if err != nil {
t.Fatal(err)
}
newline := []byte{'\n'}
defines := bytes.Count(out, newline)

if count != defines {
t.Fatalf("Got %d constants from zconst.go, but %d #defines from pkcs11t.h", count, defines)
}
}
31 changes: 31 additions & 0 deletions p11/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,37 @@ func (priv PrivateKey) Sign(mechanism pkcs11.Mechanism, message []byte) ([]byte,
return out, nil
}

func (priv PrivateKey) deriveInner(mechanism pkcs11.Mechanism, attributes []*pkcs11.Attribute) (*Object, error) {
s := priv.session
s.Lock()
defer s.Unlock()
objectHandle, err := s.ctx.DeriveKey(s.handle, []*pkcs11.Mechanism{&mechanism}, priv.objectHandle, attributes)
if err != nil {
return nil, err
}

obj := Object{
session: s,
objectHandle: objectHandle,
}
return &obj, nil
}

// Derive derives a shared secret with a given mechanism.
func (priv PrivateKey) Derive(mechanism pkcs11.Mechanism, attributes []*pkcs11.Attribute) ([]byte, error) {
sharedObj, err := priv.deriveInner(mechanism, attributes)
if err != nil {
return nil, err
}

sharedSecret, err := sharedObj.Value()
if err != nil {
return nil, err
}

return sharedSecret, nil
}

// Verify verifies a signature over a message with a given mechanism.
func (pub PublicKey) Verify(mechanism pkcs11.Mechanism, message, signature []byte) error {
s := pub.session
Expand Down
28 changes: 23 additions & 5 deletions p11/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ var modulesMu sync.Mutex
// OpenModule loads a PKCS#11 module (a .so file or dynamically loaded library).
// It's an error to load a PKCS#11 module multiple times, so this package
// will return a previously loaded Module for the same path if possible.
// Note that there is no facility to unload a module ("finalize" in PKCS#11
// parlance). In general, modules will be unloaded at the end of the process.
// The only place where you are likely to need to explicitly unload a module is
// if you fork your process. If you need to fork, you may want to use the
// lower-level `pkcs11` package.
//
// In general, modules will be unloaded at the end of the process. The only
// place where you are likely to need to explicitly unload a module is if you
// fork your process. If you need to fork, you may want to use the lower-level
// `pkcs11` package.
func OpenModule(path string) (Module, error) {
modulesMu.Lock()
defer modulesMu.Unlock()
Expand Down Expand Up @@ -125,6 +125,24 @@ func (m Module) Slots() ([]Slot, error) {
}

// Destroy unloads the module/library.
//
// Once called, any code which uses this module might crash the application.
func (m Module) Destroy() {
modulesMu.Lock()
defer modulesMu.Unlock()

// Find initialized module based on ctx
var path string
for k, v := range modules {
if v.ctx == m.ctx {
path = k
break
}
}
if path != "" {
delete(modules, path)
}

_ = m.ctx.Finalize()
m.ctx.Destroy()
}
10 changes: 10 additions & 0 deletions p11/slot.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ type Mechanism struct {
slot Slot
}

// Type returns the type of mechanism.
func (m *Mechanism) Type() uint {
return m.mechanism.Mechanism
}

// Parameter returns any parameters required by the mechanism.
func (m *Mechanism) Parameter() []byte {
return m.mechanism.Parameter
}

// Info returns information about this mechanism.
func (m *Mechanism) Info() (pkcs11.MechanismInfo, error) {
return m.slot.ctx.GetMechanismInfo(m.slot.id, []*pkcs11.Mechanism{m.mechanism})
Expand Down
Loading
Loading