Comments (10)
From the stack trace, it appears that pyHanko isn't able to find the private key handle (although the error message is definitely less than enlightening — I'll do something about that).
Probably, the PKCS#11 label of the private key is not the same as that of the certificate object. Can you try to list the labels of the keys on the card using a tool like pkcs11-tool
(or using python-pkcs11
, whichever you prefer)? Once you know what the label of the key is, you should pass it to the PKCS11Signer
constructor as the key_label
parameter.
Let me know if that helps. Incidentally, you might also want to pass in "CertFirmaDigital" as the cert_label
parameter, by the way.
PS: The ECDSA signing commands for PKCS#11 are almost completely untested, since SoftHSMv2 doesn't (didn't?) support ECDSA properly when I wrote the tests for it. So far, there's no indication that points towards that being the issue here, though.
PPS: By the way, validating against the validation contexts from the test suite won't help you, I'm afraid. Those have been set up to only accept the trust roots from my testing CAs. You'll want to set up a validation context with at least one trust root that covers your ID cert. If there's such a trust root in the system trust store, initialising your validation context without any arguments might already be sufficient.
from pyhanko.
Thanks for your reply:
List of label of the keys using the pkcs11-tool are:
Using slot 0 with a present token (0x10000)
Certificate Object; type = X.509 cert
label: CertAutenticacion
subject: DN: C=ES/serialNumber=3400xxxxx SN=LOPEZ, GN=FERNANDO, CN=LOPEZ MOZOS, FERNANDO (AUTENTICACI\xC3\x93N)
ID: 413032303934423xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Certificate Object; type = X.509 cert
label: CertFirmaDigital
subject: DN: C=ES/serialNumber=3400xxxxx SN=LOPEZ, GN=FERNANDO, CN=LOPEZ MOZOS, FERNANDO (FIRMA)
ID: 463032303934xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Certificate Object; type = X.509 cert
label: CertCAIntermediaDGP
subject: DN: C=ES, O=DIRECCION GENERAL DE LA POLICIA, OU=DNIE, CN=AC DNIE 005
ID: 53303230393442xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Public Key Object; RSA 2048 bits
label: KpuAutenticacion
ID: 41303230393442xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Usage: verify
Access: local
Public Key Object; RSA 2048 bits
label: KpuFirmaDigital
ID: 463032303934xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Usage: verify
Access: local
Data object 2097159
label: 'DG1'
application: ''
app_id:
flags: modifiable
Data object 2097160
label: 'DG11'
application: ''
app_id:
flags: modifiable
Data object 2097161
label: 'DG13'
application: ''
app_id:
flags: modifiable
Data object 2097162
label: 'DG2'
application: ''
app_id:
flags: modifiable
Data object 2097163
label: 'DG7'
application: ''
app_id:
flags: modifiable
Data object 2097164
label: 'DG3'
application: ''
app_id:
flags: modifiable
Data object 2097165
label: 'DG14'
application: ''
app_id:
flags: modifiable
Data object 2097166
label: 'EFCOM'
application: ''
app_id:
flags: modifiable
Data object 2097167
label: 'EFSOD'
application: ''
app_id:
flags: modifiable
As you can see, there is public labelled "KpuFirmaDigital". I have tried to pass it as the key_label parameter in the PKCS11Signer with no luck. Same error. I have also used your improvement in the code to get an error message on a missing key handle, but have the same error on "signers.sign.pdf(....)" on the "test_wrong_key_label(buk_fetch)" function.
But if I use another wrong cert name (invented one), give "Exception has occurred: PKCS11Error
Could not find (unique) cert with label ...), which means that it is succesfully accessing to the certs stored in the card.
This also happens when the CLI is used where you do not specify the name of the cert to use, so is it possible that this is not related with the key label management?
Thanks again
from pyhanko.
Just to confirm: I'm not seeing any private keys in the pkcs11-tool
listing. Possibly those are only accessible after logging in to the PKCS#11 token (but it depends). Did you run pkcs11-tool --module /path/to/p11-library.so -O -l
?
Anyway, the certificates and public key objects won't help you when signing things, so you'll need to find a way to talk to the private keys :/
Are you able to sign things using other PKCS#11-based tools?
from pyhanko.
For comparison: this is what I see on my Belgian eID. Note in particular that there are two objects of type "Private Key" (labelled "Authentication" and "Signature", respectively).
Certificate Object; type = X.509 cert
label: Authentication
subject: <censored>
ID: 0200000000000000
Certificate Object; type = X.509 cert
label: Signature
subject: <censored>
ID: 0300000000000000
Certificate Object; type = X.509 cert
label: CA
subject: DN: C=BE, CN=Citizen CA/serialNumber=<censored>
ID: 0400000000000000
Certificate Object; type = X.509 cert
label: Root
subject: DN: C=BE, CN=Belgium Root CA4
ID: 0600000000000000
Private Key Object; RSA
label: Authentication
ID: 0200000000000000
Usage: sign
Access: sensitive
Public Key Object; RSA 2048 bits
label: Authentication
ID: 0200000000000000
Usage: verify
Access: none
Private Key Object; RSA
label: Signature
ID: 0300000000000000
Usage: sign
Access: sensitive
Public Key Object; RSA 2048 bits
label: Signature
ID: 0300000000000000
Usage: verify
Access: none
from pyhanko.
Hi Mathias, you were right:
After logging in my eID card, I got the label of the private key which was "KprivFirmaDigital". So it seems there is not error if I pass this as key_value parameter to the PKCS11Signer constructor. Now I am struggling how to save this in a pdf after the sign to check if this has worked.
Anyway, thanks for your help and congratulation for your code.
I owe you a beer/paella if you come to Valencia.
Fernando
from pyhanko.
Haha, good to hear that that part got solved ;)
As for saving the output to a file: there you have multiple options.
Assuming that you're calling sign_pdf
more or less as in this test, you should be able to do something like this:
with open('output-file.pdf', 'wb') as outf:
# preparation goes here
# ...
signers.sign_pdf(w, meta, signer=signer, output=outf)
PyHanko should take care of the buffer management behind the scenes. If the input buffer is writable as well, you can also pass in_place=True
instead. See here for more info.
For what it's worth, the PKCS#11 signer is also available directly from the CLI (with pyhanko sign addsig pkcs11
), and there's a command line flag (--key-label
) to specify the key label you need. Depending on what you want to do, that might be easier.
I'll keep this issue open for now; let me know if that solves your use case.
from pyhanko.
Well, that works like a charm and now I am able to get a valid pades-b signature. Thank you very much.
My last question (I promise) is that I want to make a visible signature in a box. I am able to print the box with the timestamp, but neither the subject nor the issuer. This is the code I am using:
`def _simple_sess():
lib = "/usr/lib64/pkcs11/opensc-pkcs11.so"
session=pkcs11.open_pkcs11_session(
lib, user_pin='p4rp4rp4arpxp2', token_label='DNI electrónico (PIN1)'
)
return session
default_other_certs = ('CertCAIntermediaDGP',)
def test_simple_sign(bulk_fetch, pss):
with _simple_sess() as sess:
for certi in sess.get_objects({ Attribute.LABEL: "CertFirmaDigital",
Attribute.CLASS: ObjectClass.CERTIFICATE,}):
der_bytes = certi[Attribute.VALUE]
certi = x509.Certificate.load(der_bytes)
w = IncrementalPdfFileWriter(BytesIO(MINIMAL))
signerp = pkcs11.PKCS11Signer(
sess, 'CertFirmaDigital',None,key_label='KprivFirmaDigital', other_certs_to_pull=default_other_certs,
bulk_fetch=bulk_fetch, prefer_pss=pss
)
vc = ValidationContext(trust_roots=[signerp.signing_cert])
#tsl_client = timestamps.HTTPTimeStamper('http://timestamp.digicert.com')
tsl_client=datetime.now()
identificador= fields.SigCertConstraints(subjects=[certi])
sv = fields.SigSeedValueSpec(
reasons=[ ],
cert=fields.SigCertConstraints( subjects=[certi], flags=fields.SigCertConstraintFlags.SUBJECT ),
digest_methods=['sha256', 'sha384', 'sha512'],
flags=fields.SigSeedValFlags.REASONS | fields.SigSeedValFlags.DIGEST_METHOD)
sp = fields.SigFieldSpec('Signature', seed_value_dict=sv, box=(200, 50, 400, 100),)
#image = PdfImage(image=settings.STAMP_IMAGE)
style = TextStampStyle(background=None, border_width=0)
with open('output-file.pdf', 'wb') as outf:
out = signers.PdfSigner(signature_meta=signers.PdfSignatureMetadata(
field_name='Signature',
reason='Firma',
location='',
use_pades_lta=True,
subfilter=fields.SigSeedSubFilter.PADES,
embed_validation_info=True,
validation_context=vc
),
signer=signerp,
timestamper=None,
stamp_style=style,
new_field_spec=sp
).sign_pdf(w,output=outf)
test_simple_sign(True,False)`
Obviously, I am not managing / understanding the "SigSeedValueSpec" in a proper way. Last code I made to get the subject, issuer and serial number was:
`def obtcer():
pk11objects = session2.findObjects([(PK11.CKA_CLASS,PK11.CKO_CERTIFICATE),
(PK11.CKA_LABEL,"CertFirmaDigital")])
all_attributes = [
PK11.CKA_SUBJECT,
PK11.CKA_VALUE,
#PK11.CKA_ISSUER,
#PK11.CKA_CERTIFICATE_CATEGORY,
#PK11.CKA_END_DATE,
PK11.CKA_LABEL,
PK11.CKA_ID,
]
for pk11object in pk11objects:
try:
attributes = session2.getAttributeValue(pk11object, all_attributes)
#print(attributes)
except PK11.PyKCS11Error as e:
continue
attrDict = dict(list(zip(all_attributes, attributes)))
#cert = bytes(attrDict[PK11.CKA_VALUE])
certs = [OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_ASN1, bytes(attrDict[PK11.CKA_VALUE]))]
for certi in certs:
x509_cert = XX509()
x509_cert.parse(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, certi).decode('utf-8'))
subject = certi.get_subject()
nombre = dict(subject.get_components())[b'CN'].decode()
dni = dict(subject.get_components())[b'serialNumber'].decode()
return nombre,dni
`
Thanks Matthias
from pyhanko.
A couple things:
- Don't bother with seed values if you're creating signature fields and then immediately signing them yourself. Seed values are a somewhat obscure feature of the standard intended for form authors to pass instructions to (later) signers. Support for those is fairly sparse "in the wild" anyhow.
- The visual appearance of the signature can be customised, but it's admittedly not that well-documented. I don't have the bandwidth to put together a full example for the documentation right now, but I can point you in the right direction (see below).
To put in a custom appearance, you'll have to work directly with the (slightly more detailed) API on which signers.sign_pdf()
is built, i.e. use the sign_pdf
method of PdfSigner
directly: https://pyhanko.readthedocs.io/en/latest/api-docs/pyhanko.sign.signers.html#pyhanko.sign.signers.PdfSigner.sign_pdf. Note the following facts:
PdfSigner
takes astamp_style
parameter. You can override that one, either to a parametrised style (like the default one), or just put in the text that you want to show directly. For reference, this is how the default appearance is initialised:pyHanko/pyhanko/sign/signers.py
Line 1823 in f43c3c0
- If you decide to go with a parametrised style, you'll have to add string interpolation parameters for the subject & issuer DN, since pyHanko doesn't include those by default. When calling
sign_pdf
on yourPdfSigner
, you can then pass in those extra parameters as a dictionary via theappearance_text_params
keyword argument.
Granted, it's a bit complicated, but the APIs are there. :) I've made a note to add a proper example to the documentation when I find the time, but I can't promise when that'll happen.
from pyhanko.
Thank you for your help Matthias. All working now. And once more, congratulations for your code.
Best regards
Fernando
from pyhanko.
Great! And thank you for making good use of it :)
I'll go ahead and close the issue now, if you don't mind.
from pyhanko.
Related Issues (20)
- Needs a requirements.txt file HOT 5
- TextStamp applied after signature invalidates the previous signature HOT 1
- PDFs where Root -> AcroForm is a broken reference (resolves to a NullObject) fails to parse HOT 2
- cli --no-strict-syntax missing HOT 2
- Signature faulty with rotate_with_page = False on rotated pages/pdfs HOT 1
- non-ascii(chinese) characters not disaplying correctly when generating default signature appearance HOT 1
- enhance document to provide concret example for specifying the page and coordinates of the signature field HOT 2
- can't install pyhanko because of uharfbuzz depending on cython HOT 8
- Validating signature with embedded timestamp fails on 0.19.0 HOT 1
- Cannot install using pip HOT 3
- Link signature certificate HOT 1
- Link to the documentation in description HOT 1
- stamp font and position is inverted for some PDFs. HOT 5
- [pyhanko-certvalidator] PEM certificate not getting extracted due to incorrect Content-Type header HOT 3
- [pyhanko-certvalidator] Ability to skip nonce validation in OCSP response HOT 3
- Expose encryption dictionary in PdfFileReader as instance variable HOT 9
- The Coordinates Not Set Properly HOT 3
- LICENSE.PyPDF2 missing from wheel distributions HOT 3
- Add digital signature is broken for PDF file larger than 100 000 000 bytes HOT 3
- Xrefs disable
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from pyhanko.