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 +9/−16
- hspkcs11.cabal +1/−1
- src/System/Crypto/Pkcs11.chs +277/−98
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