To jest prawidłowa struktura dla certyfikatu.
Kopiuj
default_bits = 2048
default_keyfile = klucz_prywatny.key
distinguished_name = req_distinguished_name
prompt = no
[ req_distinguished_name ]
countryName = PL
givenName = Dawid
surname = Nazwisko
commonName = Firma
serialNumber = NIP-6422786434
Kolejnosc bledow przy autoryzacji:
- Nieprawidłowa treść podpisu.
- Nieprawidłowy certyfikat.
- Nieprawidłowe wyzwanie autoryzacyjne. ->(blednie przekazany nr init do xml)
python3 skrypt podpisujący plik auth.xml do signed.xml (cert p12 bez hasła) - działa z ksef2.0!!! - podziękowania dla ChatGPT 99% roboty odwalił (ja jako amator w programowaniu dzięki ChatGPT zintegrowałem środowisko testowe z moim system fakturowym (lms.org.pl) w 1 dniówkę ):
Kopiuj
import base64
import uuid
from datetime import datetime
from lxml import etree
import xmlsec
from cryptography.hazmat.primitives.serialization import pkcs12, Encoding, PrivateFormat, NoEncryption
from cryptography.hazmat.primitives import hashes
# =======================
# Pliki i konfiguracja
# =======================
xml_input_file = "auth.xml"
xml_output_file = "signed.xml"
p12_file = "cert.p12"
p12_password = b"" # bytes
DS_NS = "http://www.w3.org/2000/09/xmldsig#"
XADES_NS = "http://uri.etsi.org/01903/v1.3.2#"
NSMAP = {
"ds": DS_NS,
"xades": XADES_NS
}
# =======================
# Wczytaj XML
# =======================
tree = etree.parse(xml_input_file)
root = tree.getroot()
# =======================
# UUID i Id dla podpisu
# =======================
sig_id = f"Signature-{uuid.uuid4()}"
qp_id = f"QualifyingProps-{uuid.uuid4()}"
sp_id = f"xades-{uuid.uuid4()}"
# =======================
# Utwórz szablon podpisu (enveloped)
# =======================
signature_node = xmlsec.template.create(
root,
xmlsec.Transform.EXCL_C14N,
xmlsec.Transform.RSA_SHA256,
ns="ds"
)
signature_node.set("Id", sig_id)
root.append(signature_node)
# =======================
# Reference do całego dokumentu z XPath
# =======================
ref_doc = xmlsec.template.add_reference(signature_node, xmlsec.Transform.SHA256, uri="")
xpath_transform = xmlsec.template.add_transform(ref_doc, xmlsec.Transform.XPATH)
# Tworzymy element <ds:XPath> wewnątrz transform
xpath_elem = etree.SubElement(xpath_transform, etree.QName(DS_NS, "XPath"))
xpath_elem.text = "not(ancestor-or-self::ds:Signature)"
# =======================
# KeyInfo / X509Data
# =======================
key_info = xmlsec.template.ensure_key_info(signature_node)
xmlsec.template.add_x509_data(key_info)
# =======================
# Dodaj XAdES-BES Object
# =======================
object_node = etree.SubElement(signature_node, etree.QName(DS_NS, "Object"))
qualifying_properties = etree.SubElement(
object_node,
etree.QName(XADES_NS, "QualifyingProperties"),
Id=qp_id,
Target="#" + sig_id
)
signed_properties = etree.SubElement(
qualifying_properties,
etree.QName(XADES_NS, "SignedProperties"),
Id=sp_id
)
signed_signature_properties = etree.SubElement(
signed_properties,
etree.QName(XADES_NS, "SignedSignatureProperties")
)
# SigningTime z lokalną strefą czasową
local_time = datetime.now().astimezone()
signing_time = etree.SubElement(
signed_signature_properties,
etree.QName(XADES_NS, "SigningTime")
)
signing_time.text = local_time.isoformat(timespec="milliseconds")
# =======================
# Załaduj P12 i certyfikat
# =======================
with open(p12_file, "rb") as f:
p12_data = f.read()
private_key, cert, additional_certs = pkcs12.load_key_and_certificates(p12_data, p12_password)
# SHA256 digest certyfikatu
cert_der = cert.public_bytes(Encoding.DER)
# SigningCertificate
signing_certificate = etree.SubElement(signed_signature_properties, etree.QName(XADES_NS, "SigningCertificate"))
cert_node = etree.SubElement(signing_certificate, etree.QName(XADES_NS, "Cert"))
cert_digest = etree.SubElement(cert_node, etree.QName(XADES_NS, "CertDigest"))
digest_method = etree.SubElement(cert_digest, etree.QName(DS_NS, "DigestMethod"))
digest_method.set("Algorithm", "http://www.w3.org/2001/04/xmlenc#sha256")
digest_value = etree.SubElement(cert_digest, etree.QName(DS_NS, "DigestValue"))
digest = hashes.Hash(hashes.SHA256())
digest.update(cert_der)
digest_value.text = base64.b64encode(digest.finalize()).decode("utf-8")
# IssuerSerial
issuer_serial = etree.SubElement(cert_node, etree.QName(XADES_NS, "IssuerSerial"))
issuer_name = etree.SubElement(issuer_serial, etree.QName(DS_NS, "X509IssuerName"))
issuer_name.text = cert.issuer.rfc4514_string()
serial_number = etree.SubElement(issuer_serial, etree.QName(DS_NS, "X509SerialNumber"))
serial_number.text = str(cert.serial_number)
# =======================
# SignaturePolicyIdentifier (implied)
# =======================
spi = etree.SubElement(signed_signature_properties, etree.QName(XADES_NS, "SignaturePolicyIdentifier"))
etree.SubElement(spi, etree.QName(XADES_NS, "SignaturePolicyImplied"))
# =======================
# SignerRole - tu możesz dodać dane osoby zgodnie z KSeF
# =======================
signer_role = etree.SubElement(signed_signature_properties, etree.QName(XADES_NS, "SignerRole"))
claimed_roles = etree.SubElement(signer_role, etree.QName(XADES_NS, "ClaimedRoles"))
claimed_role = etree.SubElement(claimed_roles, etree.QName(XADES_NS, "ClaimedRole"))
# claimed_role.append(...) # Tutaj możesz wstawić strukturę ePUAP / KSeF
# =======================
# Dodaj Reference do SignedProperties
# =======================
ref_props = xmlsec.template.add_reference(
signature_node,
xmlsec.Transform.SHA256,
uri="#" + sp_id,
type="http://uri.etsi.org/01903#SignedProperties"
)
xmlsec.template.add_transform(ref_props, xmlsec.Transform.EXCL_C14N)
# =======================
# Przygotuj klucz PEM do xmlsec
# =======================
private_key_pem = private_key.private_bytes(
encoding=Encoding.PEM,
format=PrivateFormat.PKCS8,
encryption_algorithm=NoEncryption()
)
cert_pem = cert.public_bytes(Encoding.PEM)
key = xmlsec.Key.from_memory(private_key_pem, xmlsec.constants.KeyDataFormatPem, None)
key.load_cert_from_memory(cert_pem, xmlsec.constants.KeyDataFormatPem)
# =======================
# Podpisz dokument
# =======================
ctx = xmlsec.SignatureContext()
ctx.key = key
ctx.sign(signature_node)
# =======================
# Zapis podpisanego XML
# =======================
tree.write(xml_output_file, encoding="UTF-8", xml_declaration=True, pretty_print=True)
print(f"Dokument podpisany i zapisany jako {xml_output_file}")
Jak już macie token_auth to teraz czas na token do uwierzytelnienia operacji :
Kopiuj
function GetToken($url,$token_auth) {
$url = $url."api/v2/auth/token/redeem";
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$headers = array(
"accept: application/json",
"Authorization: Bearer $token_auth",
"Content-Type: application/json",
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$resp = curl_exec($curl);
var_dump($resp);
curl_close($curl);
return $resp;
};
I sprawdzenie czy jest aktywna sesja:
Kopiuj
function SessionStatus($url,$token) {
$url = $url."api/v2/auth/sessions";
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$headers = array(
"accept: application/json",
"SessionToken: $token",
"Authorization: Bearer $token"
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$resp = curl_exec($curl);
curl_close($curl);
return $resp;
};