/* SetPIN modifies the PIN of the user who is logged in. */ func (c *Ctx) SetPIN(sh SessionHandle, oldpin string, newpin string) error { old := C.CString(oldpin) defer C.free(unsafe.Pointer(old)) new := C.CString(newpin) defer C.free(unsafe.Pointer(new)) e := C.SetPIN(c.ctx, C.CK_SESSION_HANDLE(sh), old, C.CK_ULONG(len(oldpin)), new, C.CK_ULONG(len(newpin))) return toError(e) }
// InitToken initializes a token. The label must be 32 characters // long, it is blank padded if it is not. If it is longer it is capped // to 32 characters. func (c *Ctx) InitToken(slotID uint, pin string, label string) error { p := C.CString(pin) defer C.free(unsafe.Pointer(p)) ll := len(label) for ll < 32 { label += " " ll++ } l := C.CString(label[:32]) defer C.free(unsafe.Pointer(l)) e := C.InitToken(c.ctx, C.CK_ULONG(slotID), p, C.CK_ULONG(len(pin)), l) return toError(e) }
func cMechanismList(m []*Mechanism) (C.CK_MECHANISM_PTR, C.CK_ULONG) { if len(m) == 0 { return nil, 0 } pm := make([]C.CK_MECHANISM, len(m)) for i := 0; i < len(m); i++ { pm[i].mechanism = C.CK_MECHANISM_TYPE(m[i].Mechanism) if m[i].Parameter == nil { continue } pm[i].pParameter = C.CK_VOID_PTR(&(m[i].Parameter[0])) pm[i].ulParameterLen = C.CK_ULONG(len(m[i].Parameter)) } return C.CK_MECHANISM_PTR(&pm[0]), C.CK_ULONG(len(m)) }
// cAttribute returns the start address and the length of an attribute list. func cAttributeList(a []*Attribute) (C.CK_ATTRIBUTE_PTR, C.CK_ULONG) { if len(a) == 0 { return nil, 0 } pa := make([]C.CK_ATTRIBUTE, len(a)) for i := 0; i < len(a); i++ { pa[i]._type = C.CK_ATTRIBUTE_TYPE(a[i].Type) if a[i].Value == nil { continue } pa[i].pValue = C.CK_VOID_PTR((&a[i].Value[0])) pa[i].ulValueLen = C.CK_ULONG(len(a[i].Value)) } return C.CK_ATTRIBUTE_PTR(&pa[0]), C.CK_ULONG(len(a)) }
/* CloseAllSessions closes all sessions with a token. */ func (c *Ctx) CloseAllSessions(slotID uint) error { if c.ctx == nil { return toError(CKR_CRYPTOKI_NOT_INITIALIZED) } e := C.CloseAllSessions(c.ctx, C.CK_ULONG(slotID)) return toError(e) }
// GetTokenInfo obtains information about a particular token // in the system. func (c *Ctx) GetTokenInfo(slotID uint) (TokenInfo, error) { var cti C.CK_TOKEN_INFO e := C.GetTokenInfo(c.ctx, C.CK_ULONG(slotID), &cti) s := TokenInfo{ Label: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&cti.label[0]), 32)), " "), ManufacturerID: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&cti.manufacturerID[0]), 32)), " "), Model: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&cti.model[0]), 16)), " "), SerialNumber: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&cti.serialNumber[0]), 16)), " "), Flags: uint(cti.flags), MaxSessionCount: uint(cti.ulMaxSessionCount), SessionCount: uint(cti.ulSessionCount), MaxRwSessionCount: uint(cti.ulMaxRwSessionCount), RwSessionCount: uint(cti.ulRwSessionCount), MaxPinLen: uint(cti.ulMaxPinLen), MinPinLen: uint(cti.ulMinPinLen), TotalPublicMemory: uint(cti.ulTotalPublicMemory), FreePublicMemory: uint(cti.ulFreePublicMemory), TotalPrivateMemory: uint(cti.ulTotalPrivateMemory), FreePrivateMemory: uint(cti.ulFreePrivateMemory), HardwareVersion: toVersion(cti.hardwareVersion), FirmwareVersion: toVersion(cti.firmwareVersion), UTCTime: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&cti.utcTime[0]), 16)), " "), } return s, toError(e) }
// toList converts from a C style array to a []uint. func toList(clist C.CK_ULONG_PTR, size C.CK_ULONG) []uint { l := make([]uint, int(size)) for i := 0; i < len(l); i++ { l[i] = uint(C.Index(clist, C.CK_ULONG(i))) } defer C.free(unsafe.Pointer(clist)) return l }
// FindObjects continues a search for token and session // objects that match a template, obtaining additional object // handles. The returned boolean indicates if the list would // have been larger than max. func (c *Ctx) FindObjects(sh SessionHandle, max int) ([]ObjectHandle, bool, error) { var ( objectList C.CK_OBJECT_HANDLE_PTR ulCount C.CK_ULONG ) e := C.FindObjects(c.ctx, C.CK_SESSION_HANDLE(sh), &objectList, C.CK_ULONG(max), &ulCount) if toError(e) != nil { return nil, false, toError(e) } l := toList(C.CK_ULONG_PTR(unsafe.Pointer(objectList)), ulCount) // Make again a new list of the correct type. // This is copying data, but this is not an often used function. o := make([]ObjectHandle, len(l)) for i, v := range l { o[i] = ObjectHandle(v) } return o, ulCount > C.CK_ULONG(max), nil }
/* GenerateRandom generates random data. */ func (c *Ctx) GenerateRandom(sh SessionHandle, length int) ([]byte, error) { var rand C.CK_BYTE_PTR e := C.GenerateRandom(c.ctx, C.CK_SESSION_HANDLE(sh), &rand, C.CK_ULONG(length)) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(rand), C.int(length)) C.free(unsafe.Pointer(rand)) return h, nil }
// GetMechanismInfo obtains information about a particular // mechanism possibly supported by a token. func (c *Ctx) GetMechanismInfo(slotID uint, m []*Mechanism) (MechanismInfo, error) { var cm C.CK_MECHANISM_INFO e := C.GetMechanismInfo(c.ctx, C.CK_ULONG(slotID), C.CK_MECHANISM_TYPE(m[0].Mechanism), C.CK_MECHANISM_INFO_PTR(&cm)) mi := MechanismInfo{ MinKeySize: uint(cm.ulMinKeySize), MaxKeySize: uint(cm.ulMaxKeySize), Flags: uint(cm.flags), } return mi, toError(e) }
/* GetSlotInfo obtains information about a particular slot in the system. */ func (c *Ctx) GetSlotInfo(slotID uint) (SlotInfo, error) { var csi C.CK_SLOT_INFO e := C.GetSlotInfo(c.ctx, C.CK_ULONG(slotID), &csi) s := SlotInfo{ SlotDescription: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&csi.slotDescription[0]), 64)), " "), ManufacturerID: strings.TrimRight(string(C.GoBytes(unsafe.Pointer(&csi.manufacturerID[0]), 32)), " "), Flags: uint(csi.flags), HardwareVersion: toVersion(csi.hardwareVersion), FirmwareVersion: toVersion(csi.firmwareVersion), } return s, toError(e) }
func cMechanismList(m []*Mechanism) (arena, C.CK_MECHANISM_PTR, C.CK_ULONG) { var arena arena if len(m) == 0 { return nil, nil, 0 } pm := make([]C.CK_MECHANISM, len(m)) for i := 0; i < len(m); i++ { pm[i].mechanism = C.CK_MECHANISM_TYPE(m[i].Mechanism) if m[i].Parameter == nil { continue } pm[i].pParameter, pm[i].ulParameterLen = arena.Allocate(m[i].Parameter) } return arena, C.CK_MECHANISM_PTR(&pm[0]), C.CK_ULONG(len(m)) }
// cAttribute returns the start address and the length of an attribute list. func cAttributeList(a []*Attribute) (arena, C.CK_ATTRIBUTE_PTR, C.CK_ULONG) { var arena arena if len(a) == 0 { return nil, nil, 0 } pa := make([]C.CK_ATTRIBUTE, len(a)) for i := 0; i < len(a); i++ { pa[i]._type = C.CK_ATTRIBUTE_TYPE(a[i].Type) if a[i].Value == nil { continue } pa[i].pValue, pa[i].ulValueLen = arena.Allocate(a[i].Value) } return arena, C.CK_ATTRIBUTE_PTR(&pa[0]), C.CK_ULONG(len(a)) }
/* GetMechanismList obtains a list of mechanism types supported by a token. */ func (c *Ctx) GetMechanismList(slotID uint) ([]*Mechanism, error) { var ( mech C.CK_ULONG_PTR // in pkcs#11 we're all CK_ULONGs \o/ mechlen C.CK_ULONG ) e := C.GetMechanismList(c.ctx, C.CK_ULONG(slotID), &mech, &mechlen) if toError(e) != nil { return nil, toError(e) } // Although the function returns only type, cast them back into real // attributes as this is used in other functions. m := make([]*Mechanism, int(mechlen)) for i, typ := range toList(mech, mechlen) { m[i] = NewMechanism(typ, nil) } return m, nil }
/* DigestUpdate continues a multiple-part message-digesting operation. */ func (c *Ctx) DigestUpdate(sh SessionHandle, message []byte) error { e := C.DigestUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&message[0])), C.CK_ULONG(len(message))) if toError(e) != nil { return toError(e) } return nil }
// SignUpdate continues a multiple-part signature operation, // where the signature is (will be) an appendix to the data, // and plaintext cannot be recovered from the signature. func (c *Ctx) SignUpdate(sh SessionHandle, message []byte) error { e := C.SignUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&message[0])), C.CK_ULONG(len(message))) return toError(e) }
/* Digest digests message in a single part. */ func (c *Ctx) Digest(sh SessionHandle, message []byte) ([]byte, error) { var ( hash C.CK_BYTE_PTR hashlen C.CK_ULONG ) e := C.Digest(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&message[0])), C.CK_ULONG(len(message)), &hash, &hashlen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(hash), C.int(hashlen)) C.free(unsafe.Pointer(hash)) return h, nil }
/* OpenSession opens a session between an application and a token. */ func (c *Ctx) OpenSession(slotID uint, flags uint) (SessionHandle, error) { var s C.CK_SESSION_HANDLE e := C.OpenSession(c.ctx, C.CK_ULONG(slotID), C.CK_ULONG(flags), C.CK_SESSION_HANDLE_PTR(&s)) return SessionHandle(s), toError(e) }
/* SetOperationState restores the state of the cryptographic operation in a session. */ func (c *Ctx) SetOperationState(sh SessionHandle, state []byte, encryptKey, authKey ObjectHandle) error { e := C.SetOperationState(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&state[0])), C.CK_ULONG(len(state)), C.CK_OBJECT_HANDLE(encryptKey), C.CK_OBJECT_HANDLE(authKey)) return toError(e) }
// VerifyRecover verifies a signature in a single-part // operation, where the data is recovered from the signature. func (c *Ctx) VerifyRecover(sh SessionHandle, signature []byte) ([]byte, error) { var ( data C.CK_BYTE_PTR datalen C.CK_ULONG ) e := C.DecryptVerifyUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&signature[0])), C.CK_ULONG(len(signature)), &data, &datalen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(data), C.int(datalen)) C.free(unsafe.Pointer(data)) return h, nil }
// VerifyFinal finishes a multiple-part verification // operation, checking the signature. func (c *Ctx) VerifyFinal(sh SessionHandle, signature []byte) error { e := C.VerifyFinal(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&signature[0])), C.CK_ULONG(len(signature))) return toError(e) }
// VerifyUpdate continues a multiple-part verification // operation, where the signature is an appendix to the data, // and plaintext cannot be recovered from the signature. func (c *Ctx) VerifyUpdate(sh SessionHandle, part []byte) error { e := C.VerifyUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&part[0])), C.CK_ULONG(len(part))) return toError(e) }
// SignRecover signs data in a single operation, where the // data can be recovered from the signature. func (c *Ctx) SignRecover(sh SessionHandle, data []byte) ([]byte, error) { var ( sig C.CK_BYTE_PTR siglen C.CK_ULONG ) e := C.SignRecover(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&data[0])), C.CK_ULONG(len(data)), &sig, &siglen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(sig), C.int(siglen)) C.free(unsafe.Pointer(sig)) return h, nil }
/* InitPIN initializes the normal user's PIN. */ func (c *Ctx) InitPIN(sh SessionHandle, pin string) error { p := C.CString(pin) defer C.free(unsafe.Pointer(p)) e := C.InitPIN(c.ctx, C.CK_SESSION_HANDLE(sh), p, C.CK_ULONG(len(pin))) return toError(e) }
// SeedRandom mixes additional seed material into the token's // random number generator. func (c *Ctx) SeedRandom(sh SessionHandle, seed []byte) error { e := C.SeedRandom(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&seed[0])), C.CK_ULONG(len(seed))) return toError(e) }
// Sign signs (encrypts with private key) data in a single part, where the signature // is (will be) an appendix to the data, and plaintext cannot be recovered from the signature. func (c *Ctx) Sign(sh SessionHandle, message []byte) ([]byte, error) { var ( sig C.CK_BYTE_PTR siglen C.CK_ULONG ) e := C.Sign(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&message[0])), C.CK_ULONG(len(message)), &sig, &siglen) if toError(e) != nil { return nil, toError(e) } s := C.GoBytes(unsafe.Pointer(sig), C.int(siglen)) C.free(unsafe.Pointer(sig)) return s, nil }
/* SignEncryptUpdate continues a multiple-part signing and encryption operation. */ func (c *Ctx) SignEncryptUpdate(sh SessionHandle, part []byte) ([]byte, error) { var ( enc C.CK_BYTE_PTR enclen C.CK_ULONG ) e := C.SignEncryptUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&part[0])), C.CK_ULONG(len(part)), &enc, &enclen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(enc), C.int(enclen)) C.free(unsafe.Pointer(enc)) return h, nil }
/* 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) { var key C.CK_OBJECT_HANDLE ac, aclen := cAttributeList(a) mech, _ := cMechanismList(m) 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) }
/* Login logs a user into a token. */ func (c *Ctx) Login(sh SessionHandle, userType uint, pin string) error { p := C.CString(pin) defer C.free(unsafe.Pointer(p)) e := C.Login(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_USER_TYPE(userType), p, C.CK_ULONG(len(pin))) return toError(e) }
/* DecryptVerifyUpdate continues a multiple-part decryption and verify operation. */ func (c *Ctx) DecryptVerifyUpdate(sh SessionHandle, cipher []byte) ([]byte, error) { var ( part C.CK_BYTE_PTR partlen C.CK_ULONG ) e := C.DecryptVerifyUpdate(c.ctx, C.CK_SESSION_HANDLE(sh), C.CK_BYTE_PTR(unsafe.Pointer(&cipher[0])), C.CK_ULONG(len(cipher)), &part, &partlen) if toError(e) != nil { return nil, toError(e) } h := C.GoBytes(unsafe.Pointer(part), C.int(partlen)) C.free(unsafe.Pointer(part)) return h, nil }