Coder Social home page Coder Social logo

Comments (24)

danni avatar danni commented on August 26, 2024 1

In your first code:

with token.open(user_pin=pin) as session:
    # Here is where you leave the session with a PKCS#11 object, which will fail.
    # Objects are only valid in the session they were created.
    # Objects from other session will get you an InvalidHandle, or worse, the wrong object!
    return session.get_objects({Attribute.CLASS: ObjectClass.PUBLIC_KEY})

In your second code:

with token.open(user_pin=pin) as session:
    for i in session.get_objects({Attribute.CLASS: ObjectClass.PUBLIC_KEY}):
        # Here you are printing an object inside the session while it is still valid
        # This will work.
        print(i)
        return ''

In the third code:

with token.open(user_pin=pin) as session:
    for i in session.get_objects({Attribute.CLASS: ObjectClass.PUBLIC_KEY}):
        # This will work because you're extracting the key from the object inside the session,
        # while it is still valid, you're then returning string, not a key object.
        # If you want PEM, this is the best option.
        return pem.armor('RSA PUBLIC KEY', encode_rsa_public_key(i)).decode()

To clarify: with starts a block that holds open the resource only while you are inside the block. If you leave the block due to return, Exception or reaching the end, the resource will be closed. These are called context managers. You will see them used for files, transactions, devices, and other resources you need to explicitly close. For this reason they are extremely useful because they prevent you from leaking resources.

You can, if you prefer, call token.open() directly, but you must match this with a session.close(), else you will leak the session (including any possible exception handling). Context managers are better, because they're easier to get right.

~

One more thing, be aware of exchanges between str and bytes. In general I try to minimise my exchanges, because eventually I'll break my unicode handling. It's better to only do encode/decode on input or output. When you do use encode and decode be explicit what you're encoding/decoding from (e.g. utf-8, ascii).

So when you capture the token serial, encode immediately based on the terminal/file encoding (Python has utilties for this). PEM is bytes, and while it is "ascii clean", unless you need to output it to a terminal, just keep it as bytes. The next library is probably going to consume it as bytes. Moving it in and out of unicode is just an opportunity for mistakes.

from python-pkcs11.

danni avatar danni commented on August 26, 2024

The module for pkcs11-tool and python-pkcs11 are the same. If it works for one it should work for the other.

What does your code look like? Do you have a module called pkcs11 that is masking the library?

You said in #10 you had installed packages from apt. I was not aware python-pkcs11 had been packaged into Debian/Ubuntu, have you definitely installed python-pkcs11?

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

root@waffle:~# dmesg -T
[Qua Mai 16 21:03:10 2018] usb 2-1: new full-speed USB device number 5 using xhci_hcd
[Qua Mai 16 21:03:10 2018] usb 2-1: New USB device found, idVendor=0529, idProduct=0620
[Qua Mai 16 21:03:10 2018] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[Qua Mai 16 21:03:10 2018] usb 2-1: Product: Token JC
[Qua Mai 16 21:03:10 2018] usb 2-1: Manufacturer: SafeNet
[Qua Mai 16 21:04:27 2018] usb 2-1: USB disconnect, device number 5
[Qua Mai 16 21:04:29 2018] usb 2-1: new full-speed USB device number 6 using xhci_hcd
[Qua Mai 16 21:04:29 2018] usb 2-1: New USB device found, idVendor=0529, idProduct=0620
[Qua Mai 16 21:04:29 2018] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[Qua Mai 16 21:04:29 2018] usb 2-1: Product: Token JC
[Qua Mai 16 21:04:29 2018] usb 2-1: Manufacturer: SafeNet

import pkcs11

lib = pkcs11.lib('/usr/lib/libeToken.so.9')
token = lib.get_token()

with token.open(user_pin='****') as session:
print(session)

Traceback (most recent call last):
File "teste.py", line 4, in
token = lib.get_token()
File "pkcs11/_pkcs11.pyx", line 1268, in pkcs11._pkcs11.lib.get_token
File "pkcs11/_pkcs11.pyx", line 1235, in get_tokens
File "pkcs11/_pkcs11.pyx", line 182, in pkcs11._pkcs11.Slot.get_token
File "pkcs11/_errors.pyx", line 88, in pkcs11._pkcs11.assertRV
pkcs11.exceptions.TokenNotPresent

I have an virtual env with python 3.5.4. I installed python-pkcs11 from pip install. I guess I don't have any module "pkcs11" masking things

Hope it helps you to help me heh

from python-pkcs11.

danni avatar danni commented on August 26, 2024

Okay that looks more promising. You probably just need to give something to identify the token. Try lib.get_slots() or list(lib.get_tokens()) to see what slots and tokens are available.

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

print(lib.get_slots())

[<Slot (slotID=0 flags=SlotFlag.HW_SLOT|REMOVABLE_DEVICE)>, <Slot (slotID=1 flags=SlotFlag.HW_SLOT|REMOVABLE_DEVICE|TOKEN_PRESENT)>, <Slot (slotID=2 flags=SlotFlag.HW_SLOT|REMOVABLE_DEVICE)>, <Slot (slotID=3 flags=SlotFlag.HW_SLOT|REMOVABLE_DEVICE)>, <Slot (slotID=4 flags=SlotFlag.HW_SLOT|REMOVABLE_DEVICE)>, <Slot (slotID=5 flags=SlotFlag.HW_SLOT|REMOVABLE_DEVICE)>, <Slot (slotID=6 flags=SlotFlag.HW_SLOT|REMOVABLE_DEVICE)>, <Slot (slotID=7 flags=SlotFlag.HW_SLOT|REMOVABLE_DEVICE)>, <Slot (slotID=8 flags=SlotFlag.REMOVABLE_DEVICE)>, <Slot (slotID=9 flags=SlotFlag.REMOVABLE_DEVICE)>]

from python-pkcs11.

danni avatar danni commented on August 26, 2024

Try print(list(lib.get_tokens()))

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

File "pkcs11/_pkcs11.pyx", line 1235, in get_tokens
File "pkcs11/_pkcs11.pyx", line 182, in pkcs11._pkcs11.Slot.get_token
File "pkcs11/_errors.pyx", line 88, in pkcs11._pkcs11.assertRV
pkcs11.exceptions.TokenNotPresent

But don't worry @danni , I guess you gave me the way! I will take a look at the api reference and do some tests... I'll give you a feedback! Thankssssssssssssssssssss

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

@danni it seems that everything is working fine so far! Do you know if it's possible to create a x509 certificate and sign it with python-pkcs11? Currently I am creating x509 certs with cryptography (cryptography.io), but I am using an rsa private key on disk to sign. But my main objective is to replace by token signing.

from python-pkcs11.

danni avatar danni commented on August 26, 2024

Yes it is. See https://github.com/danni/python-pkcs11/blob/master/tests/test_x509.py#L166

This is implemented using asn1crypto which is what all the crypto-interchange fundamentals in python-pkcs11 are built in, but would port to cryptography easily enough.

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

Hi @danni ,
I don't think I have enough skills to fully understand code written by other people, but , for example, in that link:

https://github.com/danni/python-pkcs11/blob/master/tests/test_x509.py#L166

The line:

pub, priv = self.session.generate_keypair(KeyType.RSA, 1024)

Made me a bit confused. I saw the Generation Keys at readthedocs and I still confused because my eToken is provided by Safenet Company, and the RSA private key cannot ever be accessed or exported.

So, what does the generate_keypair really do? Does it generate something like session key to access the API of the USB eToken hardware , after authentication, or it expects to read the public and private key from token and stores it in pub and priv variables?

It's worth to remember that I can sign a file with pkcs11-tool with no problem.

from python-pkcs11.

danni avatar danni commented on August 26, 2024

Not all PKCS#11 devices support key generation. Some simply have a key baked in. It's a broad standard. The tests generate a key for the session, because the tests don't want to create hundreds of keys they leave lying around.

In your case you can use get_key. You will need to call it once for the public object and once for the private object. Or if you need your X.509 certificate you can retrieve it with get_objects.

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

Thank you so much again @danni . So, the get_key and get_objects methods belongs to pkcs11.Session class. At the readthedocs, the signature of this class is: get_key(object_class=None, key_type=None, label=None, id=None) but looking at the code itself, the signature is: def init(self, token, handle, rw=False, user_type=UserType.NOBODY): . I don't know what are the possibilities for this "handle" parameter. It seems that there is a lack in the documentation. Do you know that is this "handle" ?

Besides, do you know if is there any documentation for the asn1crypto? The only think I found was the source code. It's too hard to understand how to use the things, at least for me.

from python-pkcs11.

danni avatar danni commented on August 26, 2024

__init__ is to set up a session. The correct way to get a session is with Token.open:

with token.open(user_pin='****') as session:
    pub = session.get_key(object_class=ObjectClass.PUBLIC_KEY)
    priv = session.get_key(object_class=ObjectClass.PRIVATE_KEY)

Documentation for asn1crypto is here: https://github.com/wbond/asn1crypto#documentation
It's a bit hard to understand if you don't understand ASN.1, but it's part of a set of higher order libraries you can crib from.

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

Thanks @danni . I'll try to stop asking. Maybe last question. With that test example you gave (test_x509.py#L166) , I can run this code using priv and pub key from session.get_key. But the output is an <asn1crypto.x509.Certificate 140408562903024 b'0\x82\x02\xa40\x82\x01\x8e\x02 ....> I am trying for some hours to find out how to decode/convert this to known formats, like PEM, DER, CER...
The parser.emit() and parser.parse() expects bytestring, not asn1crypto.x509.Certificate. Do you have any idea? I'll keep trying while you can answer again.

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

@danni , the solution for this was given in: wbond/asn1crypto#95
It's now working. But I am trying to understand why the pem content pasted in https://lapo.it/asn1js/ does not show the trust chain of the signature. I opened https://stackoverflow.com/questions/50416132/where-is-the-trust-chain-python-asn1crypto-and-pkcs11-aladdin-usb-etoken
Thanks again for patient

from python-pkcs11.

danni avatar danni commented on August 26, 2024

Okay I am going to close this issue in preference for Stack Overflow, where I've tried to provide you some answers.

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

Hi again @danni , maybe this question should not be made here in this thread, sorry in advance. After you helped me a lot, now I can create certificates, signing with pkcs11 and then, appending the certificate exported form eToken, making the trust chain. So I'm generating two blocks of BEGIN CERTIFICATE / END CERTIFICATE. You told me that even the openssl and decoders websites read just the first block, it's alright because the check of the chain of trust is other procedure that these tools don't do, right?

I'd like to know about the TRUSTED certificate. So, for the openssl confirm that a certificate is TRUSTED, would be enough to change from BEGIN CERTIFICATE / END CERTIFICATE to BEGIN TRUSTED CERTIFICATE / END TRUSTED CERTIFICATE ?

Most of documentation on the internet is a superficial explanation about trusted certificate. Since you are a guru on this subject, do you mind to tell me what is the difference between trusted certificate and a common certificate? And how can I do to start creating trusted certificate?

I was thinking in why the certificate exported from the eToken does not have the BEGIN TRUSTED CERTIFICATE, since it was issued by a CA with chain of trust.

Thanks in advance

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

Hi @danni , I am stuck on getting public key again, because I have a new token model, which is:

https://github.com/OpenSC/OpenSC/wiki/StarSign-Token

I tried this:

        def getTokenPublicKey(serial,pin):
            try:
                for token in lib.get_tokens():
                    if token.serial.decode() == serial:
                        with token.open(user_pin=pin) as session:
                            pub = next(session.get_objects({Attribute.CLASS: ObjectClass.PUBLIC_KEY}))
                            return pub
                    else:
                        return 'Token com o serial {} nao encontrado.'.format(serial)
            except TokenNotPresent:
                pass

I tried too:
pub = session.get_objects({Attribute.CLASS: ObjectClass.PUBLIC_KEY})
Both cases produces:

<pkcs11._pkcs11.SearchIter object at 0x7f5c70806550>
Exception ignored in: <bound method SearchIter.del of <pkcs11._pkcs11.SearchIter object at 0x7f5c70806550>>
Traceback (most recent call last):
File "pkcs11/_pkcs11.pyx", line 275, in pkcs11._pkcs11.SearchIter.del
File "pkcs11/_pkcs11.pyx", line 281, in pkcs11._pkcs11.SearchIter._finalize
File "pkcs11/_errors.pyx", line 88, in pkcs11._pkcs11.assertRV
pkcs11.exceptions.SessionHandleInvalid:

I don't make any idea of what to do. Thanks in advance

from python-pkcs11.

danni avatar danni commented on August 26, 2024

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

Hi, I didn't understand. I am already getting the object within the session as you can see from my code snippet. If I change it to get the certificate object class, it works fine.

from python-pkcs11.

danni avatar danni commented on August 26, 2024

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

Hi @danni , so my code is below, and I am getting the same error.

        def getTokenPublicKey(serial,pin):
            try:
                for token in lib.get_tokens():
                    if token.serial.decode() == serial:
                        with token.open(user_pin=pin) as session:
                            return session.get_objects({Attribute.CLASS: ObjectClass.PUBLIC_KEY})

                return 'Token com o serial {} nao encontrado.'.format(serial)
            except TokenNotPresent:
                pass

But, if I do:

        def getTokenPublicKey(serial,pin):
            try:
                for token in lib.get_tokens():
                    if token.serial.decode() == serial:
                        with token.open(user_pin=pin) as session:
                            for i in session.get_objects({Attribute.CLASS: ObjectClass.PUBLIC_KEY}):
                                print(i)
                                return ''
                            # return session.get_objects({Attribute.CLASS: ObjectClass.PUBLIC_KEY})

                return 'Token com o serial {} nao encontrado.'.format(serial)
            except TokenNotPresent:
                pass

I get:

<PublicKey label='********:23471920000193's AC ***** ID' id='*******' 2048-bit RSA>

Why? And, if I use the encode_rsa_public_key(), I get a DER encoded format, but I d'like to convert it to PEM

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

I did:

from asn1crypto import pem

        def getTokenPublicKey(serial,pin):
            try:
                for token in lib.get_tokens():
                    if token.serial.decode() == serial:
                        with token.open(user_pin=pin) as session:
                            for i in session.get_objects({Attribute.CLASS: ObjectClass.PUBLIC_KEY}):
                                return pem.armor('RSA PUBLIC KEY', encode_rsa_public_key(i)).decode()

                return 'Token com o serial {} nao encontrado.'.format(serial)
            except TokenNotPresent:
                pass

Result:

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAmZo0QwIFCnZjPjBl6mQkFFtY8WVi2174VJtTGbep/kuXGCO6IN3e
/OjU8XJbPrO4/MNC98SasDP4BsAT3LLqGtnJlpJlrwztOIuo4dSznYKGBhQDG9P/
Xp0JMwABwfimYqYGZjIogcv/xCi98ugwZvvpMYasa5w4xk0G/Uvt7WRe3lh0DmEp
DZcE6T6hHpKQhWB/CJUBdeuPOUKZlxr/HL/qWgyg24Tj7ZAr6EBbaf/xIGYRoDLs
h2r9OJooWgsKGPfhJEw6NdQVIhiJ0Mu93fGG3GIhfY7LkaP20TRIV2EkAIlGBkYF
NUymmjm4Kv+HrwyT667JdC9Q4PwqHqU54QIDAQAB
-----END RSA PUBLIC KEY-----

What do you think? Is that correct?

from python-pkcs11.

ftbarata avatar ftbarata commented on August 26, 2024

Hi @danni, thanks a lot again. I always convert to string because I need to send to my Django webservice I created in a Post request, as data dictionary. I didn't see how to send bytes in such scenario.

from python-pkcs11.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.