Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: kejhal 17. 10. 2015, 17:07:58
-
Zdravím,
už nějakou dobu se trápím s digitálním podpisem souboru, repsektive PDFka.. Máme certifikát zakoupený na ssls.cz, přesněji tento digitální podpis https://www.ssls.cz/id/professional.html.
Všechno se odehrává v průběhu nějakého php procesu. Používám na to funkci openssl_pkcs7_sign(), pro ukázku kód vypadá přesně takto:
openssl_pkcs7_sign($path,
$this->debtor->getPath($this->uploadDir . '/signed.pdf'),
'file://' . realpath('_cesta_/signcert.pem')),
'file://' . realpath('_cesta_/private.pem')),
[]
);
Cesty jsou generované na 100% správně.
Soukromý klíč jsem stáhl v administraci ssls.cz ve formátu .pfx a veřejný .cer binární a .pem plain.
Soukromý klíč jsem převedl z pkcs12 (.pfx) do pkcs7 (.pem) pomocí příkazu
openssl pkcs12 -in filename.pfx -nocerts -nodes -out key.pem
V tuto chvíli, když vemu veřejný .pem plain, pojmenovaný jako signcert.pem a privátní .pem pojmenovaný private.pem, tak mi server vrátí "openssl_pkcs7_sign(): error getting private key".
Plno lidí má tenhle problém spojený se špatnou cestou, ta je opravená právě pomocí realpath(), ale i tak nejsem schopný soubor podepsat..
Kdyby se tady našel někdo, kdo už s tím zkušenost měl nebo by ho napadl jakýkoli způsob, budu velmi rád.
Díky :)
-
openssl pkcs12 -in filename.pfx -nocerts -nodes -out key.pem
Kdyz pouzivas funkci openssl_pkcs7_sign, nema tam byt pri konverzi openssl pkcs7 ...?
-
Nemůže to být o předponě file://? V příkladu na http://php.net/manual/en/function.openssl-pkcs7-sign.php není pro certifikát použitá. Zkusil bych privátní klič vygenerovat s heslem (
-nodes) a pak použít volání z toho přikladu. Funguje to, pokud to podepíšeš pomocí openssl?
openssl cms -sign -signer sign.pem
sign.pem obsahuje signcert.pem + private.pem.
-
Nemůže to být o předponě file://?
Nemůže, tak je přece 100% správně ;D
Je k té funkci nějaký funkční example s jejich/ukázkovými klíči? Vypadají ty klíče „podobně“? Co na to řekne openssl rsa -noout -text -in bla.key nebo openssl x509 -noout -text -in bla.key?
-
Mně je tam tedy podezřelý ten převod privátního klíče do PKCS7. PKCS7 je formát uložená zpráv, tj. např. šifrovaný/podepsaný e-mail, případně se v něm ukládají sady certifikátů (buď certifikační cesta nebo CRL). Ale že by v PKCS7 byl uložen privátní klíč, to se mi moc nezdá.
Nicméně ten příkaz, který jste použil, podle mne jenom z PFX souboru extrahoval privátní klíč a uložil ho nešifrovaný do souboru key.pem. Pokud jste ten soubor pak přejmenoval na private.pem a máte ho uložený ve správném umístění, mělo by to být v pořádku.
To realpath() vám vrací správnou cestu?
Jinak dokumentace té funkce openssl_pkcs7_sign je opravdu fascinující. Nicméně ve všech příkladech tam v parametru pro privátní klíč předávají pole, ve kterém je na první pozici cesta k souboru s klíčem a na druhém heslo ke klíči. Zkuste si ten privátní klíč vyexportovat s nějakým heslem a použít tuhle variantu. Některé knihovny bez hesla neumějí pracovat.
-
Všechno vrací správné cesty, několikrát kontrolované, pro jistotu i teď znovu a cesty jsou na 110% správné.
Ta předpona file:// by tam být měla, podle všech článků na stackoverflow, kdy to lidem pomohlo vyřešit problém se stejným errorem.
Pravda, že to, co jsem posílal v předchozím postu, byl privátní klíč bez hesla. I když jsem zkusil podle @TTTTTTT privátní klíč vygenerovat s heslem, problém je pořád stejný.
Když jsem zkusil openssl cms -sign -signer sign.pem
, tak mi to bash vrátil bohužel jako neplatný command.
---
@fantomas - tak by ta konverze měla být správně, našel jsem to tak na stackoverflow, ale i na jiných zdrojích (https://www.sslshopper.com/ssl-converter.html).
Problém je, že ten .pfx nese úplně všechno, certifikační autoritu, veřejný i privátní klíč. Po jeho konverzi tak je potřeba ten soubor otevřít a jednotlivé klíče z toho vytáhnout každý zvlášť.. Ale problém je i tak pořád stejný, stále stejný error.
---
I když zkusím do funkce dát jako argument .pfx certifikát, nikam se nepohnu.
A je pravda, že pkcs7 je používaný i mimo jiné k podepisování mailů, ale přesně tato funkce je použita v knihovne TCPDF, která dělá vlastně totéž..
openssl_pkcs7_sign($tempdoc, $tempsign, $this->signature_data['signcert'], array($this->signature_data['privkey'], $this->signature_data['password']), array(), PKCS7_BINARY | PKCS7_DETACHED);
Přesně tuhle konstrukci jsem zkoušel jak s pfx, tak s .pem, jak s heslem, tak i bez hesla..
-
Ten soubor s privátním klíčem, který se snažíte použít, tedy vypadá následovně?
-----BEGIN PRIVATE KEY-----
…data zakódovaná v BASE64…
-----END PRIVATE KEY-----
Tj. nic dalšího v tom souboru není?
-
Vypadá spíše takto
Bag Attributes
localKeyID: 6A B3...(pokračuje)
Key Attributes: <No Attributes>
-----BEGIN RSA PRIVATE KEY-----
zakódovaná data
-----END RSA PRIVATE KEY-----
Ať to exportuju jakkoli, vdždycky jsem došel do této podoby.
-
To je divné, nedivil bych se, kdyby s tímhle openssl neumělo pracovat. Zkuste ten začátek smazat, aby tam zůstaly jen ty řádky s BEGIN a END a ta data mezi nimi. Také je mi divné to „RSA“, to je podle mne privátní klíč ve formátu PKCS1, který používaly staré verze OpenSSL, novější používají PKCS8, kde je typ klíče uložen uvnitř těch dat. Používáte nejnovější verzi OpenSSL?
-
Vypadá spíše takto
Bag Attributes
localKeyID: 6A B3...(pokračuje)
Key Attributes: <No Attributes>
-----BEGIN RSA PRIVATE KEY-----
zakódovaná data
-----END RSA PRIVATE KEY-----
Navrhuji smajznout vše před "-----BEGIN RSA PRIVATE KEY-----" a za "-----END RSA PRIVATE KEY-----". Některé softwary to nemají rády. (A obdobně u certifikátu.)
Mně to už dvakrát pomohlo. Čímž netvrdím, že je to samospasitelné, ten "doplňkový binec" by ničemu vadit neměl - teoreticky...
-
Lokální verze OpenSSL je OpenSSL 0.9.8zg 14 July 2015.
Zkusil jsem celý export udělat na linuxovém stroji kde verze OpenSSL je OpenSSL 1.0.1k 8 Jan 2015.
Když jsem vyexportoval .pfx soubor, který nese jak certifikační autoritu, veřejný i soukromý klíč, tak už to správně udělalo u privátního klíče s heslem
-----BEGIN ENCRYPTED PRIVATE KEY-----
...
-----END ENCRYPTED PRIVATE KEY-----
bez hesla
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
Vytáhl jsem tak jednotlivé klíče a udělal zvlášť public
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
a zvlášť privátní. Zkusil jsem to teď pro změnu jak s těmi Bag Attributes, tak i bez, ale jsem pořád tam kde jsem byl.. Pravdou je, že převod na lokálu, kde je jiná verze OpenSSL byla asi špatná
-
- funguje zašifrování pomocí openssl cms? Je od verze 1.0.0, tedy ten novější stroj by to měl podporovat
- změní se chybová hláška, pokud soubor vůbec není k dispozici?
- čte skript soubor s privátním klíčem (prozradí strace)?
-
Pak už podle mne zbývá jenom podívat se na zdroják té funkce, jaké kroky postupně dělá, a zkusit zjistit, kde přesně to končí chybu – např. ty jednotlivé kroky provést zvlášť. Případně jestli tam je možné zapnout vyšší úroveň logování, abyste zjistil, co se provedlo a co ne. Protože ta funkce musí jenom při načítání privátního klíče najít soubor, otevřít a přečíst ho, dekódovat ten formát PKCS8 nebo PKCS1, čímž teprve získá data k rozšifrování a ta rozšifrovat zadaným heslem. Z té hlášky vůbec není jasné, ve které fázi k té chybě dojde a kde tedy hledat problém.
-
Pokud soubor není vůbec k dispozici, tak to vrací pořád stejnou chybu..
Když jsem ale teď zkusil tedy přímo na serveru zmiňovaný openssl cms, tak.. I když se tomu snažím porozumět, už se v tom začínám ztrácet. Jaký z certifikátů bych měl pro tento příkaz správně použít?
Když použiji čistě privátní zašifrovaný, tak dostanu
139809107854992:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:703:Expecting: TRUSTED CERTIFICATE
To stejné i s veřejným.
Když zkusím ale privátní s certifikátem certifikační autority, dostanu odpověď
139957258282640:error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch:x509_cmp.c:330:
139957258282640:error:2E066088:CMS routines:CMS_add1_signer:private key does not match certificate:cms_sd.c:311:
Bohužel tady už je to úplně mimo mé znalnosti co se certifikátů týká, tak zkouším všechny možnosti.
strace zkusím použít, ale nejspíš to nebude úplně nejjednodušší kvůli použitému frameworku, kdy se nedá určitá stránka jen tak z konzole spustit.
@Filip Jirsák, je to taky varianta, zkusím pozjišťovat něco i touto cestou.
V nejhorším případě mě napadá soubor podepsat bashovým skriptem, kdyby se nenašel jiný způsob.. >:(
-
Omlouvám se za double post, ale když jsem vzal veřejný, privátní i certifikační autoritu v jednom, tak už to po openssl cms skočilo do nějakého editoru S/MIME signed message. Když jsem ale to stejné zkusil v phpku, žádná šance..
-
K podpisu je potřeba certifikát a k němu příslušející privátní klíč. Dle pojmenování z php scriptu tedy cat signcert.pem private.pem > sign.pem. Certifikační autorita je potřeba jen při ověření podpisu.
Když použiji čistě privátní zašifrovaný ...
..., tak to řve, že mu chybí certifikát
Když zkusím ale privátní s certifikátem certifikační autority ...
..., tak to řve, že privátní klíč neodpovídá veřejnému klíči v certifikátu.
Příkaz pro kontrolu, že jsou certifikáty správně:
echo -n "hello world" | \
openssl cms -sign -signed sign.pem -nodetach | \
openssl cms -verify -CAfile ca.pem
-nodetach říká, že má certifikát být v součástí podepsané zprávy, pamatuju-li si dobře. Zdá se, že certifikáty máte správně, pokud to openssl vezme.
Stránka na serveru se možná spustit nedá, ale mohlo by pomoct udělal si php skript, který bude volat jen tuhle jednu funkci a odladit do mimo server. Třeba nakonec zjistíte, že skript je dobře, jen ten server nemá přístup k certifikátům...
-
Když zkusím zmiňovaný postup, příkaz, tak jsem dostal pouze tuto odpověď.
Error reading S/MIME message
140735151387472:error:0D0D40D1:asn1 encoding routines:SMIME_read_ASN1:no content type:asn_mime.c:440:
Nakonec se to budu nejspíš stejně snažit vyřešit podpisem přes bashový skript, který phpko zavolá. Přijde mi to jako rychlejší cesta na vyřešení, snad si s tímto už poradím a najdu, co zmiňovaný chyba znamená.
-
Podobne jsem v tom plaval take. Doporucuju podivat se do TCPDF, ta vyuziva stejnou fukci a me funguje. Pozdeji jsem podobny model implementoval do jineho pho , kde podpis vytvarime mimo tcpdf, dal jsme to dokonce prenesli i do C kodu a posledni aplikace s podpisem byla opacna - ta podpis z pdf ziskava, kontroluje - to posledni uz ale bylo o napsani vlastni php extension.
Pkcs7 je v pohode, takto to do php opravdu jde, myslim ze v hex konvezi, zarovnava se to nulami, no detail je vide zkoumanim kodu v tcpdf
-
@Petr, aspoň, že vím, že to teda někomu funguje. Právě, že já jsem se to pokoušel to vykuchat z toho tcpdfka.
Když už jsi s tím měl takovouto zkušenost, můžu tě poprosit, co je obsahem těch tvých certifikátů? Respektive co by správně měl obsahovat ten první, "signing_cert" a co všechno "private_key"? Protože i když jsem to zkusil udělat přes tcpdf, tak s tím nehnu a věřím, že chyba musí být v tom, co obsahují ty soubory, jen prostě nevím co ty soubory správně musí obsahovat.
-
@Petr, aspoň, že vím, že to teda někomu funguje. Právě, že já jsem se to pokoušel to vykuchat z toho tcpdfka.
Když už jsi s tím měl takovouto zkušenost, můžu tě poprosit, co je obsahem těch tvých certifikátů? Respektive co by správně měl obsahovat ten první, "signing_cert" a co všechno "private_key"? Protože i když jsem to zkusil udělat přes tcpdf, tak s tím nehnu a věřím, že chyba musí být v tom, co obsahují ty soubory, jen prostě nevím co ty soubory správně musí obsahovat.
Ozvi se mi na petr@xgw.cz a pokusim se pomoci :-)