...

Source file src/github.com/miekg/pkcs11/types.go

Documentation: github.com/miekg/pkcs11

     1  // Copyright 2013 Miek Gieben. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package pkcs11
     6  
     7  /*
     8  #include <stdlib.h>
     9  #include <string.h>
    10  #include "pkcs11go.h"
    11  
    12  CK_ULONG Index(CK_ULONG_PTR array, CK_ULONG i)
    13  {
    14  	return array[i];
    15  }
    16  
    17  static inline void putAttributePval(CK_ATTRIBUTE_PTR a, CK_VOID_PTR pValue)
    18  {
    19  	a->pValue = pValue;
    20  }
    21  
    22  static inline void putMechanismParam(CK_MECHANISM_PTR m, CK_VOID_PTR pParameter)
    23  {
    24  	m->pParameter = pParameter;
    25  }
    26  */
    27  import "C"
    28  
    29  import (
    30  	"fmt"
    31  	"time"
    32  	"unsafe"
    33  )
    34  
    35  type arena []unsafe.Pointer
    36  
    37  func (a *arena) Allocate(obj []byte) (C.CK_VOID_PTR, C.CK_ULONG) {
    38  	cobj := C.calloc(C.size_t(len(obj)), 1)
    39  	*a = append(*a, cobj)
    40  	C.memmove(cobj, unsafe.Pointer(&obj[0]), C.size_t(len(obj)))
    41  	return C.CK_VOID_PTR(cobj), C.CK_ULONG(len(obj))
    42  }
    43  
    44  func (a arena) Free() {
    45  	for _, p := range a {
    46  		C.free(p)
    47  	}
    48  }
    49  
    50  // toList converts from a C style array to a []uint.
    51  func toList(clist C.CK_ULONG_PTR, size C.CK_ULONG) []uint {
    52  	l := make([]uint, int(size))
    53  	for i := 0; i < len(l); i++ {
    54  		l[i] = uint(C.Index(clist, C.CK_ULONG(i)))
    55  	}
    56  	defer C.free(unsafe.Pointer(clist))
    57  	return l
    58  }
    59  
    60  // cBBool converts a bool to a CK_BBOOL.
    61  func cBBool(x bool) C.CK_BBOOL {
    62  	if x {
    63  		return C.CK_BBOOL(C.CK_TRUE)
    64  	}
    65  	return C.CK_BBOOL(C.CK_FALSE)
    66  }
    67  
    68  func uintToBytes(x uint64) []byte {
    69  	ul := C.CK_ULONG(x)
    70  	return C.GoBytes(unsafe.Pointer(&ul), C.int(unsafe.Sizeof(ul)))
    71  }
    72  
    73  // Error represents an PKCS#11 error.
    74  type Error uint
    75  
    76  func (e Error) Error() string {
    77  	return fmt.Sprintf("pkcs11: 0x%X: %s", uint(e), strerror[uint(e)])
    78  }
    79  
    80  func toError(e C.CK_RV) error {
    81  	if e == C.CKR_OK {
    82  		return nil
    83  	}
    84  	return Error(e)
    85  }
    86  
    87  // SessionHandle is a Cryptoki-assigned value that identifies a session.
    88  type SessionHandle uint
    89  
    90  // ObjectHandle is a token-specific identifier for an object.
    91  type ObjectHandle uint
    92  
    93  // Version represents any version information from the library.
    94  type Version struct {
    95  	Major byte
    96  	Minor byte
    97  }
    98  
    99  func toVersion(version C.CK_VERSION) Version {
   100  	return Version{byte(version.major), byte(version.minor)}
   101  }
   102  
   103  // SlotEvent holds the SlotID which for which an slot event (token insertion,
   104  // removal, etc.) occurred.
   105  type SlotEvent struct {
   106  	SlotID uint
   107  }
   108  
   109  // Info provides information about the library and hardware used.
   110  type Info struct {
   111  	CryptokiVersion    Version
   112  	ManufacturerID     string
   113  	Flags              uint
   114  	LibraryDescription string
   115  	LibraryVersion     Version
   116  }
   117  
   118  // SlotInfo provides information about a slot.
   119  type SlotInfo struct {
   120  	SlotDescription string // 64 bytes.
   121  	ManufacturerID  string // 32 bytes.
   122  	Flags           uint
   123  	HardwareVersion Version
   124  	FirmwareVersion Version
   125  }
   126  
   127  // TokenInfo provides information about a token.
   128  type TokenInfo struct {
   129  	Label              string
   130  	ManufacturerID     string
   131  	Model              string
   132  	SerialNumber       string
   133  	Flags              uint
   134  	MaxSessionCount    uint
   135  	SessionCount       uint
   136  	MaxRwSessionCount  uint
   137  	RwSessionCount     uint
   138  	MaxPinLen          uint
   139  	MinPinLen          uint
   140  	TotalPublicMemory  uint
   141  	FreePublicMemory   uint
   142  	TotalPrivateMemory uint
   143  	FreePrivateMemory  uint
   144  	HardwareVersion    Version
   145  	FirmwareVersion    Version
   146  	UTCTime            string
   147  }
   148  
   149  // SessionInfo provides information about a session.
   150  type SessionInfo struct {
   151  	SlotID      uint
   152  	State       uint
   153  	Flags       uint
   154  	DeviceError uint
   155  }
   156  
   157  // Attribute holds an attribute type/value combination.
   158  type Attribute struct {
   159  	Type  uint
   160  	Value []byte
   161  }
   162  
   163  // NewAttribute allocates a Attribute and returns a pointer to it.
   164  // Note that this is merely a convenience function, as values returned
   165  // from the HSM are not converted back to Go values, those are just raw
   166  // byte slices.
   167  func NewAttribute(typ uint, x interface{}) *Attribute {
   168  	// This function nicely transforms *to* an attribute, but there is
   169  	// no corresponding function that transform back *from* an attribute,
   170  	// which in PKCS#11 is just an byte array.
   171  	a := new(Attribute)
   172  	a.Type = typ
   173  	if x == nil {
   174  		return a
   175  	}
   176  	switch v := x.(type) {
   177  	case bool:
   178  		if v {
   179  			a.Value = []byte{1}
   180  		} else {
   181  			a.Value = []byte{0}
   182  		}
   183  	case int:
   184  		a.Value = uintToBytes(uint64(v))
   185  	case int16:
   186  		a.Value = uintToBytes(uint64(v))
   187  	case int32:
   188  		a.Value = uintToBytes(uint64(v))
   189  	case int64:
   190  		a.Value = uintToBytes(uint64(v))
   191  	case uint:
   192  		a.Value = uintToBytes(uint64(v))
   193  	case uint16:
   194  		a.Value = uintToBytes(uint64(v))
   195  	case uint32:
   196  		a.Value = uintToBytes(uint64(v))
   197  	case uint64:
   198  		a.Value = uintToBytes(uint64(v))
   199  	case string:
   200  		a.Value = []byte(v)
   201  	case []byte:
   202  		a.Value = v
   203  	case time.Time: // for CKA_DATE
   204  		a.Value = cDate(v)
   205  	default:
   206  		panic("pkcs11: unhandled attribute type")
   207  	}
   208  	return a
   209  }
   210  
   211  // cAttribute returns the start address and the length of an attribute list.
   212  func cAttributeList(a []*Attribute) (arena, C.CK_ATTRIBUTE_PTR, C.CK_ULONG) {
   213  	var arena arena
   214  	if len(a) == 0 {
   215  		return nil, nil, 0
   216  	}
   217  	pa := make([]C.CK_ATTRIBUTE, len(a))
   218  	for i, attr := range a {
   219  		pa[i]._type = C.CK_ATTRIBUTE_TYPE(attr.Type)
   220  		if len(attr.Value) != 0 {
   221  			buf, len := arena.Allocate(attr.Value)
   222  			// field is unaligned on windows so this has to call into C
   223  			C.putAttributePval(&pa[i], buf)
   224  			pa[i].ulValueLen = len
   225  		}
   226  	}
   227  	return arena, &pa[0], C.CK_ULONG(len(a))
   228  }
   229  
   230  func cDate(t time.Time) []byte {
   231  	b := make([]byte, 8)
   232  	year, month, day := t.Date()
   233  	y := fmt.Sprintf("%4d", year)
   234  	m := fmt.Sprintf("%02d", month)
   235  	d1 := fmt.Sprintf("%02d", day)
   236  	b[0], b[1], b[2], b[3] = y[0], y[1], y[2], y[3]
   237  	b[4], b[5] = m[0], m[1]
   238  	b[6], b[7] = d1[0], d1[1]
   239  	return b
   240  }
   241  
   242  // Mechanism holds an mechanism type/value combination.
   243  type Mechanism struct {
   244  	Mechanism uint
   245  	Parameter []byte
   246  	generator interface{}
   247  }
   248  
   249  // NewMechanism returns a pointer to an initialized Mechanism.
   250  func NewMechanism(mech uint, x interface{}) *Mechanism {
   251  	m := new(Mechanism)
   252  	m.Mechanism = mech
   253  	if x == nil {
   254  		return m
   255  	}
   256  
   257  	switch p := x.(type) {
   258  	case *GCMParams, *OAEPParams, *ECDH1DeriveParams:
   259  		// contains pointers; defer serialization until cMechanism
   260  		m.generator = p
   261  	case []byte:
   262  		m.Parameter = p
   263  	default:
   264  		panic("parameter must be one of type: []byte, *GCMParams, *OAEPParams, *ECDH1DeriveParams")
   265  	}
   266  
   267  	return m
   268  }
   269  
   270  func cMechanism(mechList []*Mechanism) (arena, *C.CK_MECHANISM) {
   271  	if len(mechList) != 1 {
   272  		panic("expected exactly one mechanism")
   273  	}
   274  	mech := mechList[0]
   275  	cmech := &C.CK_MECHANISM{mechanism: C.CK_MECHANISM_TYPE(mech.Mechanism)}
   276  	// params that contain pointers are allocated here
   277  	param := mech.Parameter
   278  	var arena arena
   279  	switch p := mech.generator.(type) {
   280  	case *GCMParams:
   281  		// uses its own arena because it has to outlive this function call (yuck)
   282  		param = cGCMParams(p)
   283  	case *OAEPParams:
   284  		param, arena = cOAEPParams(p, arena)
   285  	case *ECDH1DeriveParams:
   286  		param, arena = cECDH1DeriveParams(p, arena)
   287  	}
   288  	if len(param) != 0 {
   289  		buf, len := arena.Allocate(param)
   290  		// field is unaligned on windows so this has to call into C
   291  		C.putMechanismParam(cmech, buf)
   292  		cmech.ulParameterLen = len
   293  	}
   294  	return arena, cmech
   295  }
   296  
   297  // MechanismInfo provides information about a particular mechanism.
   298  type MechanismInfo struct {
   299  	MinKeySize uint
   300  	MaxKeySize uint
   301  	Flags      uint
   302  }
   303  
   304  // stubData is a persistent nonempty byte array used by cMessage.
   305  var stubData = []byte{0}
   306  
   307  // cMessage returns the pointer/length pair corresponding to data.
   308  func cMessage(data []byte) (dataPtr C.CK_BYTE_PTR) {
   309  	l := len(data)
   310  	if l == 0 {
   311  		// &data[0] is forbidden in this case, so use a nontrivial array instead.
   312  		data = stubData
   313  	}
   314  	return C.CK_BYTE_PTR(unsafe.Pointer(&data[0]))
   315  }
   316  

View as plain text