diff --git a/pkcs11/_pkcs11.pyx b/pkcs11/_pkcs11.pyx index 84b5973..4261fe4 100644 --- a/pkcs11/_pkcs11.pyx +++ b/pkcs11/_pkcs11.pyx @@ -1148,6 +1148,40 @@ cdef class Session(HasFuncList, types.Session): op.ingest_chunks(data) return op.finish() + def set_pin(self, old_pin, new_pin): + cdef CK_ULONG old_pin_length + cdef CK_ULONG new_pin_length + cdef CK_OBJECT_HANDLE handle = self.handle + cdef CK_UTF8CHAR *old_pin_data + cdef CK_UTF8CHAR *new_pin_data + cdef CK_RV retval + + pin_old = old_pin.encode('utf-8') + pin_new = new_pin.encode('utf-8') + + old_pin_data = pin_old + new_pin_data = pin_new + old_pin_length = len(pin_old) + new_pin_length = len(pin_new) + + with nogil: + retval = self.funclist.C_SetPIN(handle, old_pin_data, old_pin_length, new_pin_data, new_pin_length) + assertRV(retval) + + def init_pin(self, pin): + cdef CK_OBJECT_HANDLE handle = self.handle + cdef CK_UTF8CHAR *pin_data + cdef CK_ULONG pin_length + cdef CK_RV retval + + pin = pin.encode('utf-8') + + pin_data = pin + pin_length = len(pin) + + with nogil: + retval = self.funclist.C_InitPIN(handle, pin_data, pin_length) + assertRV(retval) cdef class ObjectHandleWrapper(HasFuncList): """ diff --git a/pkcs11/types.py b/pkcs11/types.py index 2ca5846..35527d0 100644 --- a/pkcs11/types.py +++ b/pkcs11/types.py @@ -576,6 +576,19 @@ def digest(self, data, **kwargs): return self._digest_generator(data, **kwargs) + def set_pin(self, old_pin, new_pin): + """Change the user pin.""" + raise NotImplementedError() + + def init_pin(self, pin): + """ + Initializes the user PIN. + + Differs from set_pin in that it sets the user PIN for the first time. + Once set, the pin can be changed using set_pin. + """ + raise NotImplementedError() + def _digest(self, data, mechanism=None, mechanism_param=None): raise NotImplementedError() diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 70c1081..3889eb8 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -11,6 +11,7 @@ PKCS11Error, ) from pkcs11.attributes import AttributeMapper, handle_bool, handle_str +from pkcs11.exceptions import PinIncorrect, PinLenRange from . import TOKEN_PIN, TOKEN_SO_PIN, Not, Only, TestCase, requires @@ -291,3 +292,52 @@ def _handler(self, key): bool_read = key[Attribute.ID] self.assertIsInstance(bool_read, bool) self.assertFalse(bool_read, False) + + @Only.softhsm2 + def test_set_pin(self): + old_token_pin = TOKEN_PIN + new_token_pin = f"{TOKEN_PIN}56" + + with self.token.open(rw=True, user_pin=old_token_pin) as session: + session.set_pin(old_token_pin, new_token_pin) + + with self.token.open(user_pin=new_token_pin) as session: + self.assertIsInstance(session, pkcs11.Session) + + with self.token.open(rw=True, user_pin=new_token_pin) as session: + session.set_pin(new_token_pin, old_token_pin) + + with self.token.open(user_pin=old_token_pin) as session: + self.assertIsInstance(session, pkcs11.Session) + + with self.token.open(rw=True, user_pin=old_token_pin) as session: + with self.assertRaises(AttributeError): + session.set_pin(None, new_token_pin) + with self.assertRaises(AttributeError): + session.set_pin(old_token_pin, None) + with self.assertRaises(PinLenRange): + session.set_pin(old_token_pin, "") + with self.assertRaises(PinIncorrect): + session.set_pin("", new_token_pin) + + @Only.softhsm2 + def test_init_pin(self): + new_token_pin = f"{TOKEN_PIN}56" + + with self.token.open(rw=True, so_pin=TOKEN_SO_PIN) as session: + session.init_pin(new_token_pin) + + with self.token.open(rw=True, user_pin=new_token_pin) as session: + self.assertIsInstance(session, pkcs11.Session) + + with self.token.open(rw=True, so_pin=TOKEN_SO_PIN) as session: + session.init_pin(TOKEN_PIN) + + with self.token.open(rw=True, user_pin=TOKEN_PIN) as session: + self.assertIsInstance(session, pkcs11.Session) + + with self.token.open(rw=True, so_pin=TOKEN_SO_PIN) as session: + with self.assertRaises(AttributeError): + session.init_pin(None) + with self.assertRaises(PinLenRange): + session.init_pin("")