packages feed

hspkcs11 0.4 → 0.5

raw patch · 3 files changed

+287/−115 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- System.Crypto.Pkcs11: data Info
- System.Crypto.Pkcs11: instance Foreign.Storable.Storable System.Crypto.Pkcs11.Info
- System.Crypto.Pkcs11: instance GHC.Show.Show System.Crypto.Pkcs11.Info
+ System.Crypto.Pkcs11: Certificate :: ClassType
+ System.Crypto.Pkcs11: Data :: ClassType
+ System.Crypto.Pkcs11: DomainParameters :: ClassType
+ System.Crypto.Pkcs11: HWFeature :: ClassType
+ System.Crypto.Pkcs11: Mechanism :: ClassType
+ System.Crypto.Pkcs11: PublicKey :: ClassType
+ System.Crypto.Pkcs11: ROPublicSession :: SessionState
+ System.Crypto.Pkcs11: ROUserFunctions :: SessionState
+ System.Crypto.Pkcs11: RWPublicSession :: SessionState
+ System.Crypto.Pkcs11: RWSOFunctions :: SessionState
+ System.Crypto.Pkcs11: RWUserFunctions :: SessionState
+ System.Crypto.Pkcs11: data LibraryInfo
+ System.Crypto.Pkcs11: data Mech
+ System.Crypto.Pkcs11: data SessionInfo
+ System.Crypto.Pkcs11: data SessionState
+ System.Crypto.Pkcs11: getSlotNum :: Library -> Bool -> IO (CULong)
+ System.Crypto.Pkcs11: instance Foreign.Storable.Storable System.Crypto.Pkcs11.LibraryInfo
+ System.Crypto.Pkcs11: instance GHC.Classes.Eq System.Crypto.Pkcs11.SessionState
+ System.Crypto.Pkcs11: instance GHC.Enum.Enum System.Crypto.Pkcs11.SessionState
+ System.Crypto.Pkcs11: instance GHC.Show.Show System.Crypto.Pkcs11.LibraryInfo
+ System.Crypto.Pkcs11: instance GHC.Show.Show System.Crypto.Pkcs11.SessionState
+ System.Crypto.Pkcs11: sessionInfoDeviceError :: SessionInfo -> CULong
+ System.Crypto.Pkcs11: sessionInfoFlags :: SessionInfo -> CULong
+ System.Crypto.Pkcs11: sessionInfoSlotId :: SessionInfo -> SlotId
+ System.Crypto.Pkcs11: sessionInfoState :: SessionInfo -> SessionState
- System.Crypto.Pkcs11: ValueLen :: Integer -> Attribute
+ System.Crypto.Pkcs11: ValueLen :: Int -> Attribute
- System.Crypto.Pkcs11: decrypt :: Session -> ByteString -> CULong -> IO ByteString
+ System.Crypto.Pkcs11: decrypt :: Mech -> Session -> ObjectHandle -> ByteString -> CULong -> IO ByteString
- System.Crypto.Pkcs11: digest :: Session -> ByteString -> CULong -> IO (ByteString)
+ System.Crypto.Pkcs11: digest :: Mech -> Session -> ByteString -> CULong -> IO (ByteString)
- System.Crypto.Pkcs11: encrypt :: Session -> ByteString -> CULong -> IO ByteString
+ System.Crypto.Pkcs11: encrypt :: Mech -> Session -> ObjectHandle -> ByteString -> CULong -> IO ByteString
- System.Crypto.Pkcs11: getInfo :: Library -> IO Info
+ System.Crypto.Pkcs11: getInfo :: Library -> IO LibraryInfo
- System.Crypto.Pkcs11: infoCryptokiVersion :: Info -> Version
+ System.Crypto.Pkcs11: infoCryptokiVersion :: LibraryInfo -> Version
- System.Crypto.Pkcs11: infoFlags :: Info -> Int
+ System.Crypto.Pkcs11: infoFlags :: LibraryInfo -> Int
- System.Crypto.Pkcs11: infoLibraryDescription :: Info -> String
+ System.Crypto.Pkcs11: infoLibraryDescription :: LibraryInfo -> String
- System.Crypto.Pkcs11: infoLibraryVersion :: Info -> Version
+ System.Crypto.Pkcs11: infoLibraryVersion :: LibraryInfo -> Version
- System.Crypto.Pkcs11: infoManufacturerId :: Info -> String
+ System.Crypto.Pkcs11: infoManufacturerId :: LibraryInfo -> String
- System.Crypto.Pkcs11: sign :: Session -> ByteString -> CULong -> IO (ByteString)
+ System.Crypto.Pkcs11: sign :: Mech -> Session -> ObjectHandle -> ByteString -> CULong -> IO (ByteString)
- System.Crypto.Pkcs11: verify :: Session -> ByteString -> ByteString -> IO (Bool)
+ System.Crypto.Pkcs11: verify :: Mech -> Session -> ObjectHandle -> ByteString -> ByteString -> IO (Bool)

Files

Test.hs view
@@ -23,7 +23,9 @@     lib <- loadLibrary "/usr/local/Cellar/softhsm/2.3.0/lib/softhsm/libsofthsm2.so"     info <- getInfo lib     putStrLn(show info)-    slots <- getSlotList lib True 10+    allSlotsNum <- getSlotNum lib False+    putStrLn("total number of slots: " ++ show allSlotsNum)+    slots <- getSlotList lib True 2     putStrLn("slots: " ++ show slots)     let slotId = head slots @@ -71,8 +73,7 @@         encData <- PL.encrypt sess (BSL.pack [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])         putStrLn $ show encData         putStrLn "decryption"-        decryptInit (simpleMech AesEcb) sess aesKeyHandle-        decData <- decrypt sess (BSL.toStrict encData) 1000+        decData <- decrypt (simpleMech AesEcb) sess aesKeyHandle (BSL.toStrict encData) 1000         putStrLn $ show decData         putStrLn "generating key pair"         (pubKeyHandle, privKeyHandle) <- generateKeyPair sess (simpleMech RsaPkcsKeyPairGen) [ModulusBits 2048, Token True, Label "key"] [Token True, Label "key"]@@ -82,19 +83,15 @@         putStrLn $ show wrappedAesKey         putStrLn "unwrap key"         unwrappedAesKey <- unwrapKey (simpleMech RsaPkcs) sess privKeyHandle wrappedAesKey [Class SecretKey, KeyType AES]-        putStrLn "signInit"-        signInit (simpleMech RsaPkcs) sess privKeyHandle         putStrLn "sign"         let signedData = BS.pack [0,0,0,0]-        signature <- sign sess signedData 1000+        signature <- sign (simpleMech RsaPkcs) sess privKeyHandle signedData 1000         putStrLn $ show signature-        putStrLn "verifyInit"-        verifyInit sess (simpleMech RsaPkcs) pubKeyHandle         --putStrLn "get operation state"         --operState <- getOperationState sess 1000         --putStrLn $ show operState         putStrLn "verify"-        verRes <- verify sess signedData signature+        verRes <- verify (simpleMech RsaPkcs) sess pubKeyHandle signedData signature         putStrLn $ "verify result " ++ (show verRes)         --putStrLn "signRecoverInit"         --signRecoverInit (simpleMech Rsa9796) sess privKeyHandle@@ -113,10 +110,8 @@         putStrLn $ show copiedObjHandle         putStrLn "deleting object"         destroyObject sess aesKeyHandle-        putStrLn "digestInit"-        digestInit (simpleMech Sha256) sess         putStrLn "digest"-        digestedData <- digest sess signedData 1000+        digestedData <- digest (simpleMech Sha256) sess (BS.replicate 16 0) 1000         putStrLn $ show digestedData         putStrLn "create object"         createdAesKey <- createObject sess [Class SecretKey,@@ -175,13 +170,11 @@             encryptedMessage = AESmod.encryptECB aesKey "hello00000000000"          -- test decryption using RSA key-        decryptInit (simpleMech RsaPkcs) sess objId-        dec <- decrypt sess (BSL.toStrict encKey) 1000+        dec <- decrypt (simpleMech RsaPkcs) sess objId (BSL.toStrict encKey) 1000         putStrLn $ show dec          -- test decryption using AES key-        decryptInit (simpleMech AesEcb) sess unwrappedKeyHandle-        decAes <- decrypt sess encryptedMessage 1000+        decAes <- decrypt (simpleMech AesEcb) sess unwrappedKeyHandle encryptedMessage 1000         putStrLn $ show decAes         logout sess 
hspkcs11.cabal view
@@ -1,5 +1,5 @@ name:           hspkcs11-version:        0.4+version:        0.5 synopsis:       Wrapper for PKCS #11 interface description:    This package allows to call PKCS#11 provider libraries.  PKCS#11 is a C interface specification for cryptography providers, such as crypto tokens and HSMs homepage:       https://github.com/denisenkom/hspkcs11
src/System/Crypto/Pkcs11.chs view
@@ -6,21 +6,25 @@     releaseLibrary,      -- ** Reading library information-    Info,     getInfo,+    LibraryInfo,     infoCryptokiVersion,     infoManufacturerId,     infoFlags,     infoLibraryDescription,     infoLibraryVersion,+    Version,+    versionMajor,+    versionMinor,      -- * Slots     SlotId,+    getSlotNum,     getSlotList,      -- ** Reading slot information-    SlotInfo,     getSlotInfo,+    SlotInfo,     slotInfoDescription,     slotInfoManufacturerId,     slotInfoFlags,@@ -40,31 +44,38 @@     setPin,      -- * Mechanisms+    getMechanismList,+    getMechanismInfo,     MechType(RsaPkcsKeyPairGen,RsaPkcs,Rsa9796,AesEcb,AesCbc,AesMac,AesMacGeneral,AesCbcPad,AesCtr,AesKeyGen,Sha256,         DhPkcsKeyPairGen,DhPkcsParameterGen,DhPkcsDerive),     MechInfo,-    getMechanismList,-    getMechanismInfo,     mechInfoMinKeySize,     mechInfoMaxKeySize,     mechInfoFlags,+    Mech,     simpleMech,      -- * Session management     Session,-    UserType(User,SecurityOfficer,ContextSpecific),     withSession,+    login,+    UserType(User,SecurityOfficer,ContextSpecific),+    logout,     closeAllSessions,     getSessionInfo,+    SessionInfo,+    sessionInfoSlotId,+    sessionInfoState,+    sessionInfoFlags,+    sessionInfoDeviceError,+    SessionState(ROPublicSession,ROUserFunctions,RWPublicSession,RWUserFunctions,RWSOFunctions),     getOperationState,-    login,-    logout,      -- * Object attributes     ObjectHandle,     Attribute(Class,Label,KeyType,Modulus,ModulusBits,PrimeBits,PublicExponent,Prime,Base,Token,Decrypt,ValueLen,               Extractable,Value),-    ClassType(PrivateKey,SecretKey),+    ClassType(Data,Certificate,PublicKey,PrivateKey,SecretKey,HWFeature,DomainParameters,Mechanism),     KeyTypeValue(RSA,DSA,DH,ECDSA,EC,AES),     destroyObject,     createObject,@@ -98,33 +109,29 @@     unwrapKey,      -- * Encryption/decryption-    decryptInit,     decrypt,-    encryptInit,     encrypt,+    -- ** Multipart operations+    decryptInit,+    encryptInit,     encryptUpdate,     encryptFinal,      -- * Digest-    digestInit,     digest,+    digestInit,      -- * Signing-    signInit,     sign,-    signRecoverInit,+    verify,     signRecover,+    signInit,     verifyInit,-    verify,+    signRecoverInit,      -- * Random     seedRandom,     generateRandom,--    -- * Misc-    Version,-    versionMajor,-    versionMinor, ) where import Foreign import Foreign.Marshal.Utils@@ -152,10 +159,12 @@  rsaPkcsKeyPairGen = {#const CKM_RSA_PKCS_KEY_PAIR_GEN#} :: Int +-- | Used to reference an object type ObjectHandle = {#type CK_OBJECT_HANDLE#} {#typedef CK_OBJECT_HANDLE ObjectHandle#} {#default in `ObjectHandle' [CK_OBJECT_HANDLE] fromIntegral#} {#default out `ObjectHandle' [CK_OBJECT_HANDLE] fromIntegral#}+ type SlotId = {#type CK_SLOT_ID#} {#typedef CK_SLOT_ID SlotId#} {#default in `SlotId' [CK_SLOT_ID] fromIntegral#}@@ -167,7 +176,6 @@ type CK_BYTE = {#type CK_BYTE#} type CK_FLAGS = {#type CK_FLAGS#} type GetFunctionListFunPtr = {#type CK_C_GetFunctionList#}-type GetSlotListFunPtr = {#type CK_C_GetSlotList#} type NotifyFunPtr = {#type CK_NOTIFY#} type SessionHandle = {#type CK_SESSION_HANDLE#} {#typedef CK_SESSION_HANDLE SessionHandle#}@@ -175,7 +183,7 @@ {#default out `SessionHandle' [CK_SESSION_HANDLE] fromIntegral#}  {#pointer *CK_FUNCTION_LIST as FunctionListPtr#}-{#pointer *CK_INFO as InfoPtr -> Info#}+{#pointer *CK_INFO as LibraryInfoPtr -> LibraryInfo#} {#pointer *CK_SLOT_INFO as SlotInfoPtr -> SlotInfo#} {#pointer *CK_TOKEN_INFO as TokenInfoPtr -> TokenInfo#} {#pointer *CK_SESSION_INFO as SessionInfoPtr -> SessionInfo#}@@ -204,7 +212,8 @@     {#set CK_VERSION->major#} p (fromIntegral $ versionMajor x)     {#set CK_VERSION->minor#} p (fromIntegral $ versionMinor x) -data Info = Info {+-- | Represents general library information. Returned by 'getInfo' function.+data LibraryInfo = LibraryInfo {     -- | Cryptoki interface version number, for compatibility with future revisions of this interface     infoCryptokiVersion :: Version,     -- | ID of the Cryptoki library manufacturer@@ -216,7 +225,7 @@     infoLibraryVersion :: Version } deriving (Show) -instance Storable Info where+instance Storable LibraryInfo where   sizeOf _ = (2+32+4+32+10+2)   alignment _ = 1   peek p = do@@ -227,7 +236,7 @@     libraryDescription <- peekCStringLen ((p `plusPtr` (2+32+4+10)), 32)     --libraryDescription <- {# get CK_INFO->libraryDescription #} p     libVer <- peek (p `plusPtr` (2+32+4+32+10)) :: IO Version-    return Info {infoCryptokiVersion=ver,+    return LibraryInfo {infoCryptokiVersion=ver,                  infoManufacturerId=manufacturerId,                  infoFlags=fromIntegral flags,                  infoLibraryDescription=libraryDescription,@@ -237,10 +246,6 @@     error "not implemented"  -peekInfo :: Ptr Info -> IO Info-peekInfo ptr = peek ptr-- data SlotInfo = SlotInfo {     slotInfoDescription :: String,     slotInfoManufacturerId :: String,@@ -304,9 +309,13 @@         error "not implemented"  +-- | Represent information about a mechanism.  Returned by 'getMechanismInfo' function. data MechInfo = MechInfo {+    -- | Minimum size of a key in bits or bytes depending on the mechanism.     mechInfoMinKeySize :: Int,+    -- | Maximum size of a key in bits or bytes depending on the mechanism.     mechInfoMaxKeySize :: Int,+    -- | Mechanism's flags as described in https://www.cryptsoft.com/pkcs11doc/v220/pkcs11__all_8h.html#aCK_MECHANISM_INFO     mechInfoFlags :: Int } deriving (Show) @@ -323,12 +332,15 @@     {#set CK_MECHANISM_INFO->flags#} p (fromIntegral $ mechInfoFlags x)  +-- | Represents mechanism with parameters to be used in cryptographic operation.  Parameterless mechanism can be+-- created with 'simpleMech' function.  Few example operations using this data structure are 'encrypt', 'generateKey'. data Mech = Mech {     mechType :: MechType,     mechParamPtr :: Ptr (),     mechParamSize :: Int } +-- | Return parameterless mechanism which can be used in cryptographic operation. simpleMech :: MechType -> Mech simpleMech mechType = Mech mechType nullPtr 0 @@ -343,21 +355,28 @@         poke (p `plusPtr` ({#sizeof CK_MECHANISM_TYPE#} + {#sizeof CK_VOID_PTR#})) (mechParamSize x)  +-- | Represent session information.  Returned by 'getSessionInfo' function. data SessionInfo = SessionInfo {-    slotId :: SlotId,-    state :: CULong,-    flags :: CULong,-    deviceError :: CULong+    -- | Slot for which session is open+    sessionInfoSlotId :: SlotId,+    -- | State of the session, e.g. 'ROPublicSession', 'RWUserFunctions'.+    sessionInfoState :: SessionState,+    -- | Session flags as described in https://www.cryptsoft.com/pkcs11doc/v220/pkcs11__all_8h.html#aCK_SESSION_INFO.+    sessionInfoFlags :: CULong,+    -- | Device specific error code.+    sessionInfoDeviceError :: CULong } deriving (Show) + instance Storable SessionInfo where     sizeOf _ = {#sizeof CK_SESSION_INFO#}     alignment _ = 1     peek p = SessionInfo         <$> liftM fromIntegral ({#get CK_SESSION_INFO->slotID#} p)-        <*> {#get CK_SESSION_INFO->state#} p+        <*> liftM culong2sessState ({#get CK_SESSION_INFO->state#} p)         <*> {#get CK_SESSION_INFO->flags#} p         <*> {#get CK_SESSION_INFO->ulDeviceError#} p+        where culong2sessState val = toEnum $ fromIntegral val     poke p x = do         error "not implemented" @@ -368,17 +387,40 @@  {#fun unsafe CK_FUNCTION_LIST.C_GetInfo as getInfo'  {`FunctionListPtr',-  alloca- `Info' peekInfo* } -> `Rv' fromIntegral#}+  alloca- `LibraryInfo' peek* } -> `Rv' fromIntegral#} +{#fun unsafe CK_FUNCTION_LIST.C_GetSlotList as getSlotList'+ {`FunctionListPtr',+  `Bool',+  castPtr `Ptr SlotId',+  `CULong' peek*} -> `Rv'+#} -getSlotList' functionListPtr active num = do-  alloca $ \arrayLenPtr -> do-    poke arrayLenPtr (fromIntegral num)+-- | Return number of slots in the system.+getSlotNum :: Library -- ^ Library to be used for operation.+           -> Bool -- ^ If True will return only slots with tokens in them.+           -> IO (CULong) -- ^ Number of slots.+getSlotNum (Library _ functionListPtr) active = do+    (rv, outNum) <- getSlotList' functionListPtr active nullPtr 0+    if rv /= 0+        then fail $ "failed to get number of slots " ++ (rvToStr rv)+        else return outNum++-- | Get a list of slot IDs in the system.  Can filter for slots with attached tokens.+--+-- > slotsIds <- getSlotList lib True 10+--+-- In this example retrieves list of, at most 10 (third parameter) slot identifiers with tokens present (second parameter is set to True)+getSlotList :: Library -- ^ Library to be used for operation.+            -> Bool -- ^ If True will return only slots with tokens in them.+            -> Int -- ^ Maximum number of slot IDs to be returned.+            -> IO [SlotId]+getSlotList (Library _ functionListPtr) active num = do     allocaArray num $ \array -> do-      res <- {#call unsafe CK_FUNCTION_LIST.C_GetSlotList#} functionListPtr (fromBool active) array arrayLenPtr-      arrayLen <- peek arrayLenPtr-      slots <- peekArray (fromIntegral arrayLen) array-      return (fromIntegral res, slots)+        (rv, outNum) <- getSlotList' functionListPtr active array (fromIntegral num)+        if rv /= 0+            then fail $ "failed to get list of slots " ++ (rvToStr rv)+            else peekArray (fromIntegral outNum) array   initToken' :: FunctionListPtr -> SlotId -> BU8.ByteString -> String -> IO (Rv)@@ -493,7 +535,16 @@  {#enum define UserType {CKU_USER as User, CKU_SO as SecurityOfficer, CKU_CONTEXT_SPECIFIC as ContextSpecific} deriving (Eq) #} +{#enum define SessionState {+    CKS_RO_PUBLIC_SESSION as ROPublicSession,+    CKS_RO_USER_FUNCTIONS as ROUserFunctions,+    CKS_RW_PUBLIC_SESSION as RWPublicSession,+    CKS_RW_USER_FUNCTIONS as RWUserFunctions,+    CKS_RW_SO_FUNCTIONS as RWSOFunctions+    } deriving (Eq,Show)+#} + {#fun unsafe CK_FUNCTION_LIST.C_GetOperationState as getOperationState'  {`FunctionListPtr',   `SessionHandle',@@ -520,6 +571,7 @@   `SessionHandle',   `ObjectHandle'} ->  `Rv'#} +-- | Deletes an object from token or session. destroyObject (Session sessHandle funcListPtr) objectHandle = do     rv <- destroyObject' funcListPtr sessHandle objectHandle     if rv /= 0@@ -544,6 +596,17 @@ --   alloca- `ObjectHandle'} -> `Rv' fromIntegral#}  +-- | Generates a symmetric key using provided mechanism and applies provided attributes to resulting key object.+--+-- Examples:+--+-- Generate 128-bit AES key:+--+-- > keyHandle <- generateKey sess (simpleMech AesKeyGen) [ValueLen 16]+--+-- Generate 1024-bit Diffie-Hellman domain parameters using PKCS#3 mechanism:+--+-- > dhParamsHandle <- generateKey sess (simpleMech DhPkcsParameterGen) [PrimeBits 1028] generateKey :: Session -> Mech -> [Attribute] -> IO ObjectHandle generateKey (Session sessHandle funcListPtr) mech attribs = do     (rv, keyHandle) <- generateKey' funcListPtr sessHandle mech attribs@@ -552,7 +615,12 @@         else return keyHandle  -_generateKeyPair :: FunctionListPtr -> SessionHandle -> Mech -> [Attribute] -> [Attribute] -> IO (Rv, ObjectHandle, ObjectHandle)+_generateKeyPair :: FunctionListPtr+                 -> SessionHandle+                 -> Mech+                 -> [Attribute]+                 -> [Attribute]+                 -> IO (Rv, ObjectHandle, ObjectHandle) _generateKeyPair functionListPtr session mech pubAttrs privAttrs = do     alloca $ \pubKeyHandlePtr -> do         alloca $ \privKeyHandlePtr -> do@@ -649,11 +717,11 @@ {#enum define ClassType {     CKO_DATA as Data,     CKO_CERTIFICATE as Certificate,-    CKO_PUBLIC_KEY as PublicKey,-    CKO_PRIVATE_KEY as PrivateKey,-    CKO_SECRET_KEY as SecretKey,+    CKO_PUBLIC_KEY as PublicKey,  -- ^ asymmetric public key, e.g. RSA public key+    CKO_PRIVATE_KEY as PrivateKey,  -- ^ asymmetric private key, e.g. RSA private key+    CKO_SECRET_KEY as SecretKey,  -- ^ symmetric key, e.g. AES key     CKO_HW_FEATURE as HWFeature,-    CKO_DOMAIN_PARAMETERS as DomainParameters,+    CKO_DOMAIN_PARAMETERS as DomainParameters,  -- ^ e.g. parameters for Diffie-Hellman     CKO_MECHANISM as Mechanism } deriving (Show, Eq) #}@@ -791,21 +859,22 @@     CKA_VENDOR_DEFINED     as VendorDefinedType     } deriving (Show, Eq) #} -data Attribute = Class ClassType-    | KeyType KeyTypeValue-    | Label String-    | ModulusBits Int-    | PrimeBits Int-    | Token Bool-    | Decrypt Bool-    | Sign Bool-    | Modulus Integer-    | PublicExponent Integer-    | Prime Integer-    | Base Integer-    | ValueLen Integer-    | Value BS.ByteString-    | Extractable Bool+-- | Represents an attribute of an object+data Attribute = Class ClassType -- ^ class of an object, e.g. 'PrivateKey', 'SecretKey'+    | KeyType KeyTypeValue -- ^ e.g. 'RSA' or 'AES'+    | Label String -- ^ object's label+    | Token Bool -- ^ whether object is stored on the token or is a temporary session object+    | Decrypt Bool -- ^ allow/deny encryption function for an object+    | Sign Bool -- ^ allow/deny signing function for an object+    | ModulusBits Int -- ^ number of bits used by modulus, for example in RSA public key+    | Modulus Integer -- ^ modulus value, used by RSA keys+    | PublicExponent Integer -- ^ value of public exponent, used by RSA public keys+    | PrimeBits Int -- ^ number of bits used by prime in classic Diffie-Hellman+    | Prime Integer -- ^ value of prime modulus, used in classic Diffie-Hellman+    | Base Integer -- ^ value of generator, used in classic Diffie-Hellman+    | ValueLen Int -- ^ length in bytes of the corresponding 'Value' attribute+    | Value BS.ByteString -- ^ object's value attribute, for example it is a DER encoded certificate for certificate objects+    | Extractable Bool -- ^ allows or denys extraction of certain attributes of private keys     deriving (Show)  data LlAttribute = LlAttribute {@@ -945,17 +1014,18 @@  -- High level API starts here -+-- | Represents a PKCS#11 library. data Library = Library {     libraryHandle :: DL,     functionListPtr :: FunctionListPtr }  +-- | Represent session. Created by 'withSession' function. data Session = Session SessionHandle FunctionListPtr  --- | Load PKCS#11 dynamically linked library+-- | Load PKCS#11 dynamically linked library from given path -- -- > lib <- loadLibrary "/path/to/dll.so" loadLibrary :: String -> IO Library@@ -972,13 +1042,14 @@                 else return Library { libraryHandle = lib, functionListPtr = functionListPtr }  +-- | Releases resources used by loaded library releaseLibrary lib = do     rv <- finalize $ functionListPtr lib     dlclose $ libraryHandle lib  --- | Returns general information about Cryptoki-getInfo :: Library -> IO Info+-- | Get general information about Cryptoki library+getInfo :: Library -> IO LibraryInfo getInfo (Library _ functionListPtr) = do     (rv, info) <- getInfo' functionListPtr     if rv /= 0@@ -986,20 +1057,12 @@         else return info  --- | Allows to obtain a list of slots in the system------ > slotsIds <- getSlotList lib True 10------ In this example retrieves list of, at most 10 (third parameter) slot identifiers with tokens present (second parameter is set to True)-getSlotList :: Library -> Bool -> Int -> IO [SlotId]-getSlotList (Library _ functionListPtr) active num = do-    (rv, slots) <- getSlotList' functionListPtr active num-    if rv /= 0-        then fail $ "failed to get list of slots " ++ (rvToStr rv)-        else return $ map (fromIntegral) slots---initToken :: Library -> SlotId -> BU8.ByteString -> String -> IO ()+-- | Initialize a token in a given slot.  All objects created by user on the token are destroyed.+initToken :: Library -- ^ PKCS#11 library+          -> SlotId  -- ^ slot id in which to initialize token+          -> BU8.ByteString -- ^ token's security officer password+          -> String  -- ^ new label for the token+          -> IO () initToken (Library _ funcListPtr) slotId pin label = do     rv <- initToken' funcListPtr slotId pin label     if rv /= 0@@ -1045,7 +1108,12 @@         else return ()  -withSession :: Library -> SlotId -> Bool -> (Session -> IO a) -> IO a+-- | Opens a read-only or read-write session with a token in a given slot and then closes it after callback function is finished.+withSession :: Library -- ^ Library to use.+            -> SlotId -- ^ Slot ID for which to open session.+            -> Bool -- ^ If True will open writable session, otherwise will open read-only session.+            -> (Session -> IO a) -- ^ Callback function which is executed while session is open.+            -> IO a -- ^ Returns a result of callback function. withSession lib slotId writable f = do     let flags = if writable then _rwSession else 0     bracket@@ -1079,13 +1147,25 @@         else return ()  +-- | Searches current session for objects matching provided attributes list, returns a list of matching object handles findObjects :: Session -> [Attribute] -> IO [ObjectHandle] findObjects session attribs = do     _findObjectsInitEx session attribs     finally (_findObjectsEx session) (_findObjectsFinalEx session)  -generateKeyPair :: Session -> Mech -> [Attribute] -> [Attribute] -> IO (ObjectHandle, ObjectHandle)+-- | Generates an asymmetric key pair using provided mechanism.+--+-- Examples:+--+-- Generate an 2048-bit RSA key:+--+-- > (pubKey, privKey) <- generateKeyPair sess (simpleMech RsaPkcsKeyPairGen) [ModulusBits 2048] []+generateKeyPair :: Session -- ^ session in which to generate key+                -> Mech -- ^ a mechanism to use for key generation, for example 'simpleMech RsaPkcs'+                -> [Attribute] -- ^ attributes applied to generated public key object+                -> [Attribute] -- ^ attributes applied to generated private key object+                -> IO (ObjectHandle, ObjectHandle) -- ^ created objects references, first is public key, second is private key generateKeyPair (Session sessionHandle functionListPtr) mech pubKeyAttrs privKeyAttrs = do     (rv, pubKeyHandle, privKeyHandle) <- _generateKeyPair functionListPtr sessionHandle mech pubKeyAttrs privKeyAttrs     if rv /= 0@@ -1103,6 +1183,8 @@   alloca- `ObjectHandle' peek*} -> `Rv' #} +-- | Derives a key from a base key using provided mechanism and applies provided attributes to a resulting key.+-- Can be used to derive symmetric key using Diffie-Hellman key exchange. deriveKey (Session sessHandle funcListPtr) mech baseKeyHandle attribs = do     _withAttribs attribs $ \attribsPtr -> do         (rv, createdHandle) <- deriveKey' funcListPtr sessHandle mech baseKeyHandle attribsPtr (fromIntegral $ length attribs)@@ -1119,6 +1201,7 @@   alloca- `ObjectHandle' peek*} -> `Rv' #} +-- | Creates an object from given list of attributes and returns a reference to created object. createObject (Session sessHandle funcListPtr) attribs = do     _withAttribs attribs $ \attribsPtr -> do         (rv, createdHandle) <- createObject' funcListPtr sessHandle attribsPtr (fromIntegral $ length attribs)@@ -1136,6 +1219,7 @@   alloca- `ObjectHandle' peek*} -> `Rv' #} +-- | Makes a copy of an object and changes attributes of copied object, returns a reference to new object. copyObject (Session sessHandle funcListPtr) objHandle attribs = do     _withAttribs attribs $ \attribsPtr -> do         (rv, createdHandle) <- copyObject' funcListPtr sessHandle objHandle attribsPtr (fromIntegral $ length attribs)@@ -1151,6 +1235,7 @@   alloca- `CULong' peek*} -> `Rv' #} +-- | Returns an approximate amount of space occupied by an object in bytes. getObjectSize (Session sessHandle funcListPtr) objHandle = do     (rv, objSize) <- getObjectSize' funcListPtr sessHandle objHandle     if rv /= 0@@ -1228,6 +1313,7 @@   `CULong'} -> `Rv' #} +-- | Modifies attributes of an object. setAttributes (Session sessHandle funcListPtr) objHandle attribs = do     _withAttribs attribs $ \attribsPtr -> do         rv <- setAttributeValue' funcListPtr sessHandle objHandle attribsPtr (fromIntegral $ length attribs)@@ -1236,6 +1322,8 @@             else return ()  +-- | Initializes normal user's PIN.  Session should be logged in by SO user in other words it should be in+-- 'RWSOFunctions' state. initPin :: Session -> BU8.ByteString -> IO () initPin (Session sessHandle funcListPtr) pin = do     rv <- initPin' funcListPtr sessHandle pin@@ -1244,7 +1332,11 @@         else return ()  -setPin :: Session -> BU8.ByteString -> BU8.ByteString -> IO ()+-- | Changes PIN of a currently logged in user.+setPin :: Session  -- ^ session to act on+       -> BU8.ByteString -- ^ old PIN+       -> BU8.ByteString -- ^ new PIN+       -> IO () setPin (Session sessHandle funcListPtr) oldPin newPin = do     rv <- setPin' funcListPtr sessHandle oldPin newPin     if rv /= 0@@ -1252,7 +1344,11 @@         else return ()  -login :: Session -> UserType -> BU8.ByteString -> IO ()+-- | Logs a user into a token.+login :: Session -- ^ session to act on+      -> UserType -- ^ type of user to login+      -> BU8.ByteString -- ^ user's PIN+      -> IO () login (Session sessionHandle functionListPtr) userType pin = do     rv <- _login functionListPtr sessionHandle userType pin     if rv /= 0@@ -1260,6 +1356,7 @@         else return ()  +-- | Logs a user out from a token. logout :: Session -> IO () logout (Session sessionHandle functionListPtr) = do     rv <- {#call unsafe CK_FUNCTION_LIST.C_Logout#} functionListPtr sessionHandle@@ -1625,6 +1722,7 @@     } deriving (Eq,Show) #}  +-- | Initialize a multi-part decryption operation using provided mechanism and key. decryptInit :: Mech -> Session -> ObjectHandle -> IO () decryptInit mech (Session sessionHandle functionListPtr) obj = do     with mech $ \mechPtr -> do@@ -1634,8 +1732,19 @@             else return ()  -decrypt :: Session -> BS.ByteString -> CULong -> IO BS.ByteString-decrypt (Session sessionHandle functionListPtr) encData outLen = do+-- | Decrypt data using provided mechanism and key handle.+--+-- Example AES ECB decryption.+--+-- > decData <- decrypt (simpleMech AesEcb) sess aesKeyHandle encData 1000+decrypt :: Mech -- ^ Mechanism used for decryption.+        -> Session -- ^ Session on which key resides.+        -> ObjectHandle -- ^ Key handle used for decryption.+        -> BS.ByteString -- ^ Encrypted data to be decrypted.+        -> CULong -- ^ Maximum number of bytes to be returned.+        -> IO BS.ByteString -- ^ Decrypted data+decrypt mech (Session sessionHandle functionListPtr) keyHandle encData outLen = do+    decryptInit mech (Session sessionHandle functionListPtr) keyHandle     unsafeUseAsCStringLen encData $ \(encDataPtr, encDataLen) -> do         allocaBytes (fromIntegral outLen) $ \outDataPtr -> do             with outLen $ \outDataLenPtr -> do@@ -1647,7 +1756,11 @@                         BS.packCStringLen (castPtr outDataPtr, fromIntegral outDataLen)  -encryptInit :: Mech -> Session -> ObjectHandle -> IO ()+-- | Initialize multi-part encryption operation.+encryptInit :: Mech -- ^ Mechanism to use for encryption.+               -> Session -- ^ Session in which to perform operation.+               -> ObjectHandle -- ^ Key handle.+               -> IO () encryptInit mech (Session sessionHandle functionListPtr) obj = do     with mech $ \mechPtr -> do         rv <- {#call unsafe CK_FUNCTION_LIST.C_EncryptInit#} functionListPtr sessionHandle mechPtr obj@@ -1656,8 +1769,15 @@             else return ()  -encrypt :: Session -> BS.ByteString -> CULong -> IO BS.ByteString-encrypt (Session sessionHandle functionListPtr) encData outLen = do+-- | Encrypt data using provided mechanism and key handle.+encrypt :: Mech -- ^ Mechanism to use for encryption.+        -> Session -- ^ Session in which to perform operation.+        -> ObjectHandle -- ^ Key handle.+        -> BS.ByteString -- ^ Data to be encrypted.+        -> CULong -- ^ Maximum number of bytes to be returned.+        -> IO BS.ByteString -- ^ Encrypted data.+encrypt mech (Session sessionHandle functionListPtr) keyHandle encData outLen = do+    encryptInit mech (Session sessionHandle functionListPtr) keyHandle     unsafeUseAsCStringLen encData $ \(encDataPtr, encDataLen) -> do         allocaBytes (fromIntegral outLen) $ \outDataPtr -> do             with outLen $ \outDataLenPtr -> do@@ -1723,8 +1843,19 @@   with* `CULong' peek*} -> `Rv' #} -digest :: Session -> BS.ByteString -> CULong -> IO (BS.ByteString)-digest (Session sessHandle funcListPtr) digestData outLen = do+-- | Calculates digest aka hash of a data using provided mechanism.+--+-- Example calculating SHA256 hash:+--+-- >>> digest (simpleMech Sha256) sess (replicate 16 0) 1000+-- "7G\b\255\247q\157\213\151\158\200u\213l\210(om<\247\236\&1z;%c*\171(\236\&7\187"+digest :: Mech -- ^ Digest mechanism.+       -> Session -- ^ Session to be used for digesting.+       -> BS.ByteString -- ^ Data to be digested.+       -> CULong -- ^ Maximum number of bytes to be returned.+       -> IO (BS.ByteString) -- ^ Resulting digest.+digest mech (Session sessHandle funcListPtr) digestData outLen = do+    digestInit mech (Session sessHandle funcListPtr)     allocaBytes (fromIntegral outLen) $ \outPtr -> do         (rv, outResLen) <- digest' funcListPtr sessHandle digestData (fromIntegral $ BS.length digestData) outPtr outLen         if rv /= 0@@ -1763,9 +1894,19 @@         then fail $ "failed to initialize signing operation: " ++ (rvToStr rv)         else return () --sign :: Session -> BS.ByteString -> CULong -> IO (BS.ByteString)-sign (Session sessHandle funcListPtr) signData outLen = do+-- | Signs data using provided mechanism and key.+--+-- Example signing with RSA PKCS#1+--+-- > signature <- sign (simpleMech RsaPkcs) sess privKeyHandle signedData 1000+sign :: Mech -- ^ Mechanism to use for signing.+     -> Session -- ^ Session to work in.+     -> ObjectHandle -- ^ Key handle.+     -> BS.ByteString -- ^ Data to be signed.+     -> CULong -- ^ Maximum number of bytes to be returned.+     -> IO (BS.ByteString) -- ^ Signature.+sign mech (Session sessHandle funcListPtr) key signData outLen = do+    signInit mech (Session sessHandle funcListPtr) key     with outLen $ \outLenPtr -> do         allocaBytes (fromIntegral outLen) $ \outPtr -> do             (rv, outResLen) <- sign' funcListPtr sessHandle signData (fromIntegral $ BS.length signData) outPtr outLen@@ -1830,8 +1971,20 @@         then fail $ "failed to initialize verify operation: " ++ (rvToStr rv)         else return () -verify :: Session -> BS.ByteString -> BS.ByteString -> IO (Bool)-verify (Session sessHandle funcListPtr) signData signatureData = do+-- | Verifies signature using provided mechanism and key.+--+-- Example signature verification using RSA public key:+--+-- >>> verify (simpleMech RsaPkcs) sess pubKeyHandle signedData signature+-- True+verify :: Mech -- ^ Mechanism to be used for signature validation.+       -> Session -- ^ Session to be used.+       -> ObjectHandle -- ^ Key handle.+       -> BS.ByteString -- ^ Signed data.+       -> BS.ByteString -- ^ Signature.+       -> IO (Bool) -- ^ True is signature is valid, False otherwise.+verify mech (Session sessHandle funcListPtr) keyHandle signData signatureData = do+    verifyInit (Session sessHandle funcListPtr) mech keyHandle     rv <- verify' funcListPtr sessHandle signData (fromIntegral $ BS.length signData) signatureData (fromIntegral $ BS.length signatureData)     case rv of 0 -> return True                {#const CKR_SIGNATURE_INVALID#} -> return False@@ -1848,6 +2001,18 @@   with* `CULong' peek*} -> `Rv' #} +-- | Wrap a key using provided wrapping key and return opaque byte array representing wrapped key.  This byte array+-- can be stored in user application and can be used later to recreate wrapped key using 'unwrapKey' function.+--+-- Example wrapping AES key using RSA public key:+--+-- > wrappedAesKey <- wrapKey (simpleMech RsaPkcs) sess pubRsaKeyHandle aesKeyHandle 300+wrapKey :: Mech -- ^ Mechanism used to wrap key (to encrypt)+        -> Session -- ^ Session in which both keys reside.+        -> ObjectHandle -- ^ Key which will be used to wrap (encrypt) another key+        -> ObjectHandle -- ^ Key to be wrapped+        -> CULong -- ^ Maximum size in bytes of a resulting byte array+        -> IO BS.ByteString -- ^ Resulting opaque wrapped key wrapKey mech (Session sessHandle funcListPtr) wrappingKey key dataLen = do     allocaBytes (fromIntegral dataLen) $ \dataPtr -> do         (rv, outDataLen) <- wrapKey' funcListPtr sessHandle mech wrappingKey key dataPtr dataLen@@ -1856,11 +2021,20 @@             else BS.packCStringLen (castPtr dataPtr, fromIntegral outDataLen)  -unwrapKey :: Mech -> Session -> ObjectHandle -> BS.ByteString -> [Attribute] -> IO ObjectHandle+-- | Unwrap a key from opaque byte string and apply attributes to a resulting key object.+--+-- Example unwrapping AES key using RSA private key:+--+-- > unwrappedAesKey <- unwrapKey (simpleMech RsaPkcs) sess privRsaKeyHandle wrappedAesKey [Class SecretKey, KeyType AES]+unwrapKey :: Mech -- ^ Mechanism to use for unwrapping (decryption).+          -> Session -- ^ Session in which to perform operation.+          -> ObjectHandle -- ^ Handle to a key which will be used to unwrap (decrypt) key.+          -> BS.ByteString -- ^ Key to be unwrapped.+          -> [Attribute] -- ^ Attributes applied to unwrapped key object.+          -> IO ObjectHandle -- ^ Unwrapped key handle. unwrapKey mech (Session sessionHandle functionListPtr) key wrappedKey template = do     _withAttribs template $ \attribsPtr -> do-        alloca $ \mechPtr -> do-            poke mechPtr mech+        with mech $ \mechPtr -> do             unsafeUseAsCStringLen wrappedKey $ \(wrappedKeyPtr, wrappedKeyLen) -> do                 alloca $ \unwrappedKeyPtr -> do                     rv <- {#call unsafe CK_FUNCTION_LIST.C_UnwrapKey#} functionListPtr sessionHandle mechPtr key (castPtr wrappedKeyPtr) (fromIntegral wrappedKeyLen) attribsPtr (fromIntegral $ length template) unwrappedKeyPtr@@ -1878,6 +2052,7 @@   `CULong'} -> `Rv' #} +-- | Mixes provided seed data with token's seed seedRandom (Session sessHandle funcListPtr) seedData = do     rv <- seedRandom' funcListPtr sessHandle seedData (fromIntegral $ BS.length seedData)     if rv /= 0@@ -1892,6 +2067,10 @@   `CULong'} -> `Rv' #} +-- | Generates random data using token's RNG.+generateRandom :: Session -- ^ Session to work on.+               -> CULong -- ^ Number of bytes to generate.+               -> IO BS.ByteString -- ^ Generated random bytes. generateRandom (Session sessHandle funcListPtr) randLen = do     allocaBytes (fromIntegral randLen) $ \randPtr -> do         rv <- generateRandom' funcListPtr sessHandle randPtr randLen