Krajowy system e-Faktur

WJ
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 46
0

Dla @gbbsoft, odpowiedź na pytanie "jak z ecd dostać X509Certificate2":

Robię to "jak matematyk", tzn. sprowadzam zagadnienie do prostszego, którego obsługę już mam zaimplementowaną. Najpierw przekształcam zaszyfrowany PEM na niezaszyfrowany PEM, i ten łączę z certyfikatem w nowa instancję X509Certificate2:

kod (.NET Core 9.0) w głównej procedurze (pkeyText to zawartość pliku *.key, certText to zawartość pliku *.crt):

Kopiuj

    if (pkeyText != null && pkeyText.Contains("ENCRYPTED")) //jeżeli klucz prywatny jest zaszyfrowany:
	{
		if (pwd.Length > 0) //Spróbuj odszyfrować podanym hasłem
		{
			result = X509Certificate2.CreateFromPem(certText); //musimy na chwilę załadować sam certyfikat, by sprawdzić typ jego kluczy:
			if (result.GetRSAPublicKey() != null) 
						pkeyText = DecryptPrivateKey(EncryptionMethodEnum.Rsa, pkeyText, pwd);
			else 
			if (result.GetECDsaPublicKey() != null) 
						pkeyText = DecryptPrivateKey(EncryptionMethodEnum.ECDsa, pkeyText, pwd);
			else 
						pkeyText = null; //Nieznany typ klucza
		}
		else  //nie podano hasła 
			pkeyText = null;
	}

	if (pkeyText == null) return X509Certificate2.CreateFromPem(certText); //Cóż, zwróć certyfikat bez klucza 

	//OK, mamy i certyfikat, i klucz:
	result = X509Certificate2.CreateFromPem(certText, pkeyText);

A tu są procedury deszyfrujące:

Kopiuj
private const int BAD_PASSWORD = -2146233087; //msg: "The EncryptedPrivateKeyInfo structure was decoded but was not successfully interpreted,
											  //the password may be incorrect." 
											  // -2146233296;

//Pomocnicza: zamienia PEM z zaszyfrowanym hasłem kluczem prywatnym na PEM bez zabezpieczeń
private static string? DecryptPrivateKey(EncryptionMethodEnum encryption, string? pkeyText, string pwd)
{
	if (pkeyText == null) return null;
	else
		try
		{
			byte[] encryptedKey = Convert.FromBase64String(pkeyText.GetPemSection(PemSection.PRIVATE_KEY, asBase64: true) ?? "");
			return encryption switch
			{
				EncryptionMethodEnum.Rsa => DecryptRSAPrivateKey(encryptedKey, pwd),
				EncryptionMethodEnum.ECDsa => DecryptECPrivateKey(encryptedKey, pwd),
				_ => null,
			};
		}
		catch (CryptographicException ex)
		{
			if (ex.HResult == BAD_PASSWORD) return null; 
			else throw;
		}
}

//Pomocnicza: odszyfrowuje klucz ECDsa:
//Argumenty:
//	encryptedkey:	bajty zaszyfrowanego klucza
//	pwd:			hasło
private static string DecryptECPrivateKey(byte[] encryptedKey, string pwd)
{
	var ecd = new ECDsaCng();
	ecd.ImportEncryptedPkcs8PrivateKey(Encoding.ASCII.GetBytes(pwd), encryptedKey, out _);
	return ecd.ExportPkcs8PrivateKeyPem();
}

//Pomocnicza: odszyfrowuje klucz RSA:
//Argumenty:
//	encryptedkey:	bajty zaszyfrowanego klucza
//	pwd:			hasło
private static string DecryptRSAPrivateKey(byte[] encryptedKey, string pwd)
{
	var rsa = new RSACng();
	rsa.ImportEncryptedPkcs8PrivateKey(Encoding.ASCII.GetBytes(pwd), encryptedKey, out _);
	return rsa.ExportPkcs8PrivateKeyPem();
}

Metoda GetPemSection() (moje rozszerzenie klasy string) zwraca w tym przypadku czysty base64 klucza, bez znaczników "----- BEGIN ...", "---- END ..." i znaków nowej linii.

EN
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1
0

Część III podręcznika KSeF, a dokładniej punkt 3.5. Interfejs informujący o awarii i niedostępności KSeF wspomina o, cutyję:
"Poza komunikatami publikowanymi w BIP MF, zostanie przygotowany dodatkowy niezależny od KSeF interfejs informujący podatnika o awarii i niedostępności KSeF, w tym m.in. o typie zdarzenia (np. o awarii lub pracach serwisowych) jak również o datach ich wystąpienia (o rozpoczęciu awarii systemu i oddzielnie o końcu tej awarii oraz o niedostępnościach KSeF w przedziale czasowym). Programy finansowo-księgowe podatników będą mogły się z tym interfejsem zintegrować, aby sprawdzać dostępność KSeF"
Czy ktoś z Was widział gdzieś jakieś wzmianki o tym dodatkowym, niezależnym od KSeF interfejsie? 🤔

Damian Florczak
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 2
0

Cześć,
Tylko ja mam problem z SKD Java po ostatniej aktualizacji?
Przykłady z dokumentacji przestały działać a samo SDK zostało przebudowane w mniejszym lub większym stopniu.
Dodatkowo mam wrażenie jakby ktoś wrzucił jakieś niesprawdzone testowe SDK.
Aktualizacja SDK jest sprzed jakiegoś tygodnia z małym hakiem.

MG
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 44
0

Czy certyfikat wygenerowany przez MCU działa na demo? Czy będzie działał w przyszłości tylko na produkcji? Ktoś wcześniej napisał, że się loguje tym certyfikatem na demo, ale mnie się nie udało.

BB
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1
0

Cześć. Mogę poprosić o wystawienie kilku faktur na demo dla 1132335790. Dzięki!

MG
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 44
0

Jest już aplikacja https://web2te-ksef.mf.gov.pl/web/

S8
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 78
0

No ok, jest aplikacja..ale chyba nie da się przetestować jeszcze kodów QR ?

AE
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 2
0

Witam,
Dzięki @JanuszKrawczyk dotarłem do wysyłania faktury, ale mam problem z pobraniem numeru KSeF faktury.
Wysyłam fakturę i nie zamykając sesji wywołuję

Kopiuj
CancellationToken cancellationToken = default;
var invoice = await ksefClient.GetSessionInvoiceAsync(sessionReferenceNumber, sendInvoiceResponse.ReferenceNumber, accessToken, cancellationToken);

i w invoice nie ma numeru KSeF.
Coś z tym cancellationToken nie tak? Trzeba go jakoś uzupełnić wpierw? Czy co innego?

ZB
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 57
0

Trochę się zagubiłem a propos MCU, na tej stronie:

https://ksef.podatki.gov.pl/modul-certyfikatow-i-uprawnien-mcu/

piszą:

Kopiuj
Ważne informacje

API MCU nie zostanie udostępnione.

MCU jest w pełni zgodny z architekturą nowego rozwiązania i stanowi
element docelowego systemu produkcyjnego KSeF 2.0.

Od 1 lutego 2026 r. funkcjonalności zarządzania uprawnieniami i wnioskowania
o certyfikat będą dostępne w Aplikacji Podatnika KSeF 2.0, lub w zintegrowanych
z API KSeF 2.0 programach komercyjnych, co spowoduje że nie będzie już dostępny poprzez te stronę.

Jednocześnie dziś @Grzegorz Molenda pisał:

Grzegorz Molenda dziś, 13:33
MCU jest tylko do produkcji, nie działa z niczym innym, kropka.

To skoro MCU nie będzie dostępny od lutego a teraz do niczego nie jest przydatny... po co w ogóle jest to MCU?

GM
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 22
0

U mnie to nie działa, a chwilę wcześniej było ok.
screenshot-20251104005636.png

W logu błędu, czytamy:

Kopiuj
{
  "headers": {
    "normalizedNames": {},
    "lazyUpdate": null
  },
  "status": 400,
  "statusText": "OK",
  "url": "https://web2te-ksef.mf.gov.pl/webs/api/v2/invoices/query/metadata?pageOffset=0&pageSize=10&sortOrder=Desc",
  "ok": false,
  "name": "AppHttpErrorResponse",
  "message": "Http failure response for https://web2te-ksef.mf.gov.pl/webs/api/v2/invoices/query/metadata?pageOffset=0&pageSize=10&sortOrder=Desc: 400 OK",
  "error": {
    "DateRange.To": [
      "Podana data jest nowsza niż aktualny czas."
    ]
  },
  "frontErrorDate": "2025-11-03T23:53:24.847Z",
  "dateTimeFormattedInPolishContext": "04/11/2025 00:53:24",
  "id": {
    "type": "Guid",
    "value": "..."
  },
  "sessionContext": {
    "roles": [],
    "contextType": "Nip",
    "contextValue": "...",
    "contextQualified": "QualifiedSeal",
    "referenceNumber": "...",
    "tokenSubjectIdentifierType": "Nip",
    "tokenSubjectIdentifierValue": "...",
    "permissionsParent": [],
    "permissionsSession": [
      "Owner"
    ],
    "permissionsContext": [],
    "lastRefreshDate": "2025-11-03T22:43:24.536Z",
    "loggedInGuid": "..."
  }
}

EDIT: a zaraz po publikacji tego postu, znowu zaczęło działać, ciekawe i za razem przerażające, dobrze że jeszcze jakieś 88 dni zostało na uruchomienie tego produkcyjnie, może w tym czasie wyłapiemy większą część takich niespodzianek.

SK
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10
0

Czytam te wszystkie wątki i trochę się chyba pogubiłem w tych wszystkich certyfikato - uprawnieniach, i mam problem podobny to tego co napisał @gbbsoft : "Czyli, jeżeli mamy program, który wysyła w nocy faktury sam, to trzeba wybrać pracownika, na certyfikacie którego to będzie działać. Czy jest jakieś inne wyjście?"
To jak to de-facto zrobić, żeby było dobrze? Bo moje rozumienie jest takie, że jak ktoś zaloguje się pieczęcią firmową i wygeneruje certyfikat, to po zalogowaniu na niego aplikacja będzie miała uprawnienia właścicielskie, czyli trochę dużo. A jak zrobić, żeby logować się, ale tylko z uprawnieniami do wystawiania i odbierania faktur?

Miang
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1776
0

https://x.com/JustynaStol/status/1985339912464318746
Analiza KSEF wg „Testu Zdrowego Rozsądku KKP
(Chat GPT)

[...]

5️⃣ Czy zapewnia uczciwą konkurencję – wolny rynek bez monopolu i przewagi korporacji?

NIE, jest zaprzeczeniem wolnego rynku.

Tworzy monopol. Państwo staje się monopolistycznym dostawcą obowiązkowej "usługi" fakturowania, niszcząc konkurencyjny rynek dostawców oprogramowania do fakturowania elektronicznego.
Faworyzuje dużych graczy. Duże korporacje mają departamenty IT i zasoby, by łatwo dostosować się do każdego, nowego, narzuconego systemu. Dla mikroprzedsiębiorców i małych firm to kolejny, kosztowny i skomplikowany przymus administracyjny, który pogarsza ich pozycję konkurencyjną.
Niszczy różnorodność i wolność wyboru na rynku usług IT.
Jak powinna wyglądać decyzja zgodna z ideą wolności, własności i suwerenności?

M4
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 52
0

Mam pytanie wygenerowałem certyfikat w MCU, chce się uwierzytelnić na testowy serwer,piszę w PHP, certyfikat tworze

Kopiuj

openssl pkcs12 -export \
  -in certyfikat.crt \
  -inkey klucz.key \
  -out certyfikat.p12 \
  -name "ksef" \
  -passout pass:TwojeHasło

I cały czas w momencie wysyłki na auth/xades-signature mam błąd, certyfikat self signed działa bez problemu

Kopiuj
"{"exception":{"exceptionDetailList":[{"exceptionCode":9105,"exceptionDescription":"Nieprawidłowy podpis.","details":["Podpis zweryfikowany negatywnie."]}],"serviceCode":"00-9d194b43d34153b69d33bf29734f834d-f26b1b35d09d802c-01","timestamp":"2025-11-04T07:51:13.8743576Z"}} ◀"
KR
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1
0

Mam problem z autoryzacją tokenem wygenerowanym przez aplikację klienta (https://web2te-ksef.mf.gov.pl/web/).

Token generuje z uprawnieniami odczytu i zapisu dla NIP 1111111111:
screenshot-20251104091056.png
Oto i on: 20251104-EC-1B0F411000-40E8E9C3B2-6F|nip-1111111111|6ab0946ad9ed4473b907174a406554d44f63d66c65a94db9a5f8c9368fa10df0
screenshot-20251104091040.png
Niestety próba autoryzacji kończy się niepowodzeniem. Po żądaniu autoryzacyjnym (api/v2/auth/ksef-token) które zwróciło token operacyjny oraz nr referencyjny (20251104-AU-1B4FCB7000-FF845CCE81-97) wywołanie endpointa:

https://ksef-test.mf.gov.pl/api/v2/auth/20251104-AU-1B4FCB7000-FF845CCE81-97

zwraca StatusCode: 401 Unauthorized

Wydaje mi się że nie powinna być to kwestia niepoprawnego zaszyfrowania danych, gdyż po stronie Aplikacji Klienta jest informacja o czasie ostatniego wykorzystania tokena, której system by nie wyciągnął bez prawidłowego rozszyfrowania przesłanych informacji.
screenshot-20251104091014.png

Czy ktoś z działającą implementacją mógłby przetestować ten token na nipie 1111111111 – czy loguje się poprawnie?
Ewentualnie podratowałby mnie działającym tokenem? (priv)
Z góry dziękuję za pomoc.

JK
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 32
0

Pociągnę jeszcze temat aplikacji serwerowych, czyli mamy sytuację, gdzie są 2 podmioty: root (właściciel aplikacji) i firmy (klienci aplikacji)

Czy taki scenariusz, gdzie firma daje uprawnienia rootowi do pobierania faktur firmy zadziała jeśli w cronie będę używał nie certyfikatu KSeF roota tylko tokenu KSeF?

Token zawiera w sobie uprawnienia (przynajmniej tak było w KSeF 1), ale czy to nie są uprawnienia do podmiotu, który wygenerował token? Czyli jak root wygeneruje sobie token z uprawnieniami tylko do odczytu faktur to po zalogowaniu tym tokenem będzie mógł pobrać tylko swoje faktury czy również faktury firm, które mu przyznały uprawnienia do pobierania?

Taki scenariusz jest chyba najbezpieczniejszy, bo firma ma cały czas kontrolę nad uprawnieniami, może je zabrać nawet jak aplikacja nie udostępnia takiej opcji albo będzie miał awarię itp. A dodatkowo nie używam certyfikatu roota, czyli nie muszę mieć zapisanego hasła do tego certyfikatu w aplikacji/bazie, po drugie w razie gdyby taki token wyciekł to ktoś postronny może w najgorszym przypadku mieć dostęp tylko do pobrania faktur, gdybym korzystał z certyfikatu ksef to ktoś miałby pełne uprawnienia do ksefu roota.

Spróbuję to sprawdzić w najbliższym czasie, ale w międzyczasie może ktoś będzie miał coś jeszcze tutaj ciekawego do powiedzenia albo już sam sprawdził.

ZD
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 3
0

Cześć,
zastanawiał się ktoś może nad pobraniem przez API wizualizacji PDF? Nie ma takiego endpointu, ale na aplikacji podatnika jest taka możliwość. Z tym, że request do xml i do pdf wygląda tak samo, chyba wizualizacja generowa jest po stronie frontu. Mam w swojej aplikacji generowanie pdf z xml z wykorzystaniem szablonów wizualizacji z gov, ale muszę teraz jeszcze dorzucić kod qr. Nie wiem czy nie lepiej będzie pokombinować i pobrać gotowy plik. Nie znalazłem nigdzie info, żeby mieli to zmiar kiedyś udostępnić, więc trochę też to ryzykowne. Nawet jak uda się coś teraz zaciągnąć, czy będzie to zawsze działać.

GB
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 26
0

Prosta procedura wysyłania interaktywnie fakturę, przepisana z dokumentacji:

Kopiuj
private async Task<SendInvoiceResponse> DoSendinvoice(string XML, bool offline, CancellationToken ct)
{
    // check access token
    ArgumentNullException.ThrowIfNull(AccessToken);
    await DoRefreshAccessToken();

    // crypto data
    var CryptographyService = await GetCryptographyService(ct);
    var encryptionData = CryptographyService.GetEncryptionData();

    // XML to bytes
    var FileBody = UTF8Encoding.UTF8.GetBytes(XML);

    // send
    byte[] encryptedInvoice = CryptographyService.EncryptBytesWithAES256(FileBody, encryptionData.CipherKey, encryptionData.CipherIv);
    FileMetadata invoiceMetadata = CryptographyService.GetMetaData(FileBody);
    FileMetadata encryptedInvoiceMetadata = CryptographyService.GetMetaData(encryptedInvoice);

    SendInvoiceRequest sendOnlineInvoiceRequest = SendInvoiceOnlineSessionRequestBuilder
        .Create()
        .WithInvoiceHash(invoiceMetadata.HashSHA, invoiceMetadata.FileSize)
        .WithEncryptedDocumentHash(encryptedInvoiceMetadata.HashSHA, encryptedInvoiceMetadata.FileSize)
        .WithEncryptedDocumentContent(Convert.ToBase64String(encryptedInvoice))
        .WithOfflineMode(offline)
        .Build();

    return await ksefClient.SendOnlineSessionInvoiceAsync(sendOnlineInvoiceRequest, Session_ReferenceNo, AccessToken.Token, ct);
}

A KSeF (baza test) zwraca: Błąd odszyfrowania pliku
Jakieś pomysły?

PU
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1
0

Cześć, czy sprawdzał ktoś może jaką wizualizację pdf proponuje MF dla faktury z załącznikiem ?
Zwłaszcza takim gdzie w tabeli liczba nagłówków kolumn nie jest równa liczbie komórek w poszczególnych wierszach - schema to dopuszcza..

W teście Aplikacji podatnika nie ma możliwości sprawdzić takiej wizualizacji - komunikat "Plik zawiera załącznik. Wystawianie faktury z załącznikiem w Aplikacji Podatnika nie jest możliwe."
Czy dobrze rozumiem komunikaty z MF że faktura z załącznikiem może być wysłana tylko przez wysyłkę wsadową w API ? Czy to oznacza że aplikacja podatnika nigdy nie pozwoli wczytać faktury z załącznikiem / czy to jednak inna blokada (np. kwestia zgłoszenia do MF potrzeby wysyłki załączników)?

V1
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1
0

cześć
Zaczynam trochę z tym tematem, przeglądam i czytam to od ok 3 m-cy, ale trochę mam mętlik w głowie.
Generalnie mam dla swoich potrzeb aplikację do wystawiania faktur opartą na php/mysql (napisaną z 15 lat temu) i będę chciał spróbować dostosować to do obsługi ksef. Znalazłem klasę udostępnioną przez użytkownika @N1ebieski (dzięki Tobie za to 😀 ) i będę się męczył pewnie, aby ją jakoś przysposobić. Coś tam zacząłem na środowisku testowym, ale raczej z marnym skutkiem jak na razie.

  1. Z tego z wyczytałem to wygenerowanie certyfikatu ksef dla demo będzie możliwe dopiero od 15.11. Zastanawiam się czy warto zaczynać teraz na środowisku testowym, czy nie lepiej już poczekać do tego 15.11 i robić to na demo.
  2. Takie pytanie ogólne mnie zastanawia i chyba nigdzie nie znalazłem odpowiedzi - Jak wygląda sprawa faktur kosztowych, które mają być uwzględnione w kosztach i faktur kosztowych wystawionych w ksef, ale które mają NIE być zaliczone do kosztów. Czy takie faktury kosztowe są w jakiś sposób oznaczane ? Jeśli tak, to przez kogo tzn. przykładowo czy ja jako właściciel jdg, ale być może również księgowa ? Z tego co widziałem na szkoleniu z ksef można nadać komuś uprawnienia tylko do odczytu albo do wystawiania fv, ale nie ma uprawnienia osobnego do oznaczenia jako koszt do zaksięgowania.
ZB
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 57
0

Eksport paczki faktur, czyli endpoint:

Kopiuj
/api/v2/invoices/exports

W parametrach filtra jest pole:

Kopiuj
subjectType required string
Enum: "Subject1" "Subject2" "Subject3" "SubjectAuthorized"
Typ podmiotu, którego dotyczą kryteria filtrowania metadanych faktur. Określa kontekst, w jakim przeszukiwane są dane.

A w dokumentacji opis:
Faktury powinny być pobierane oddzielnie dla każdego typu podmiotu (Podmiot 1, Podmiot 2, Podmiot 3, Podmiot upoważniony) występującego w dokumencie. Iteracja przez podmioty zapewnia kompletność danych - firma może występować w różnych rolach na fakturach.

I teraz pytanie. Jak zafiltruje po Subject1 to pobiorę swoje faktury, które wystawiłem czy otrzymałem?
A Subject2?
W jakich w ogóle przypadkach których Subject używać?

V2
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 16
0

W KSeF 1.0 wprowadzili bezsensowny dualizm - sesje interaktywne i wsadowe. To niestety przeniosło się do KSeF 2.0, ale wydaje się jeszcze bardziej bezsensowne. Ktoś może wytłumaczyć co twórca 2.0 miał na myśli? Może być równocześnie kilka sesji interaktywnych dla jednej autoryzacji? Można w trakcie takiej sesji internaktywnej (lub kilku równoczesnych sesji interaktywnych) wykonać sesję wsadową? Kilka sesji wsadowych? Jaki jest w tym wszystkim sens - czemu ma to służyć? Jest to gdziekolwiek wytłumaczone w dokumentacji (jeśli tak, to poprosiłbym o link)?
W KSeF 1.0 sesja interaktywna wygasała po 120 minutach nieaktywności. Czy w 2.0 wygasa w ogóle sama? Czy wygasa wraz z wygaśnięciem refreshToken? A sesja wsadowa wygasa po jakimś czasie jeśli nie wywoła się /api/v2/sessions/batch/{referenceNumber}/close? Co z fakturami wysłanymi w takiej ewentualnie wygasłej sesji wsadowej - czy są odrzucane?

Damian Florczak
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 2
0

Cześć,
miał może ktoś podobny problem i zna jakieś sensowne rozwiązanie?

Wygenerowałem klucz i certyfikat przez MCU (testowe/produkcyjne nie ma znaczenia).

Chcę użyć SDK do podpisania xml:
DefaultSignatureService signatureService = new DefaultSignatureService();
String signedXml = signatureService.sign(xml.getBytes(), cert, privateKey);

I tu pojawia się problem, ponieważ dostaję błąd java.lang.IllegalArgumentException: The provided SignatureAlgorithm 'RSA with SHA256' cannot be used to sign with the token's implied EncryptionAlgorithm 'ECDSA' .

Czyli wychodzi na to, że MCU generuje nam klucz, których nie obsługuje SDK, albo ja czegoś nie rozumiem.
Jeżeli komuś udało się rozwiązać ten problem, to będę wdzięczny za podpowiedzi.
Aktualnie jedyne co mi przychodzi do głowy to napisanie skryptu, który będzie podpisywał ES256 zamiast RS256.

EDIT 05.11.2025:
Udało mi się to ogarnąć, jeżeli ktoś chce to tutaj jest cała klasa napisana specjalnie do EC, oczywiście wcześniej musicie sprawdzić, czy to ES256, czy RS256 i użyć odpowiedniej klasy. Rozwiązanie to ogólnie przerobiona klasa DefaultSignatureService.

Kopiuj
import eu.europa.esig.dss.enumerations.DigestAlgorithm;
import eu.europa.esig.dss.enumerations.EncryptionAlgorithm;
import eu.europa.esig.dss.enumerations.MimeTypeEnum;
import eu.europa.esig.dss.enumerations.SignatureLevel;
import eu.europa.esig.dss.enumerations.SignaturePackaging;
import eu.europa.esig.dss.model.DSSDocument;
import eu.europa.esig.dss.model.InMemoryDocument;
import eu.europa.esig.dss.model.SignatureValue;
import eu.europa.esig.dss.model.ToBeSigned;
import eu.europa.esig.dss.model.x509.CertificateToken;
import eu.europa.esig.dss.validation.CommonCertificateVerifier;
import eu.europa.esig.dss.xades.XAdESSignatureParameters;
import eu.europa.esig.dss.xades.signature.XAdESService;
import pl.akmf.ksef.sdk.client.interfaces.SignatureService;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.cert.X509Certificate;

/**
 *
 * @author Damian Florczak
 */
public class XadesEcSigner implements SignatureService {

    public String sign(byte[] xml, X509Certificate signatureCertificate, PrivateKey privateKey) throws IOException {
        DSSDocument toSignDocument = new InMemoryDocument(xml, null, MimeTypeEnum.XML);
        CommonCertificateVerifier verifier = new CommonCertificateVerifier();
        XAdESService service = new XAdESService(verifier);

        XAdESSignatureParameters parameters = prepareParameters(signatureCertificate);
        ToBeSigned dataToSign = service.getDataToSign(toSignDocument, parameters);
        byte[] jcaSignature = signEcdsaSha256(privateKey, dataToSign);

        SignatureValue signatureValue
                = new SignatureValue(eu.europa.esig.dss.enumerations.SignatureAlgorithm.ECDSA_SHA256, jcaSignature);

        DSSDocument signed = service.signDocument(toSignDocument, parameters, signatureValue);

        try (ByteArrayInputStream in = (ByteArrayInputStream) signed.openStream()) {
            return new String(in.readAllBytes(), StandardCharsets.UTF_8);
        }
    }

    private XAdESSignatureParameters prepareParameters(X509Certificate signatureCertificate) {
        XAdESSignatureParameters p = new XAdESSignatureParameters();
        p.setSignaturePackaging(SignaturePackaging.ENVELOPED);
        p.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B);
        p.setEncryptionAlgorithm(EncryptionAlgorithm.ECDSA);
        p.setDigestAlgorithm(DigestAlgorithm.SHA256);
        p.setSigningCertificateDigestMethod(DigestAlgorithm.SHA256);
        p.setEn319132(false);
        p.setSigningCertificate(new CertificateToken(signatureCertificate));
        return p;
    }

    private byte[] signEcdsaSha256(PrivateKey privateKey, ToBeSigned dataToSign) throws IOException {
        try {
            Signature sig = Signature.getInstance("SHA256withECDSA");
            sig.initSign(privateKey);
            sig.update(dataToSign.getBytes());
            return sig.sign();
        } catch (Exception e) {
            throw new IOException("ECDSA signing failed: " + e.getMessage(), e);
        }
    }

}
Dzmitry Lysko
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 3
0

W 2022 roku, jako właściciel spółki, złożyłem formularz ZAW-FA. Otrzymałem potwierdzenie, że dane zostały wprowadzone do systemu.
Zgodnie z aktualną dokumentacją KSeF 2.0 rozumiem, że nie ma potrzeby ponownego składania ZAW-FA, ponieważ uprawnienia nadane w ten sposób pozostają ważne.

Niestety, obecnie nie mogę się uwierzytelnić w MCU. Czy ktoś miał podobną sytuację?
Zastanawiam się, czy problem może wynikać z opóźnionej synchronizacji danych między KSeF 1.0 a MCU, czy raczej jest to błąd po stronie systemu.
Czy ktoś wie, ile realnie może trwać aktywacja uprawnień lub synchronizacja danych z ZAW-FA z 1.0?

Będę wdzięczny za wszelkie wskazówki lub potwierdzenie, że to tymczasowy problem techniczny.

Dzyszla
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 161
0

Z ciekawości, gdzie jesteście, jeśli nie tajemnica? (Podajcie liczby w komentarzu + ewentualne uwagi, czy chcecie/nie chcecie coś realizować)

  1. Autoryzacja certyfikatem
  2. Autoryzacja pod PZ
  3. Autoryzacja tokenem
  4. Obsługa certyfikatów (listowanie, generowanie, unieważnienie)
  5. Obsługa tokenów
  6. Kody QR dla faktur z KSeF (własne wizualizacje)
  7. Kody QR dla faktur offline (własne wizualizacje)
  8. Potwierdzenie sprzedaży
  9. Wysyłka interaktywna
  10. Wysyłka wsadowa
  11. Odbieranie
  12. Zarządzanie uprawnieniami (tworzenie, nadanie, odbieranie)

Oczywiście chodzi mi o pełną integrację, a nie tylko implementację klienta.

JK
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 32
0

Czy ktoś robił autoryzację pieczęcią firmową przy użyciu oprogramowania KIR/Szafir (https://www.mszafir.pl/)? U mnie jest wersja webowa, ale podejrzewam, że z innymi środowiskami może być podobnie.

Wysyłam do Szafira taki XML:

Kopiuj
<?xml version="1.0" encoding="UTF-8"?>
<TaskList>
  <SigningTask>
    <Format>XAdES-BES</Format>
    <DataEmbedding>true</DataEmbedding>
    <EncodeToBase64>true</EncodeToBase64>
    <SigningTaskItem Id="ID-fac771be-9202-471a-970e-9a50849615a0">
      <DataToSign>
        <Base64Binary>PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZG.....</Base64Binary>
      </DataToSign>
      <SignatureToCreate>
        <Base64Binary></Base64Binary>
      </SignatureToCreate>
    </SigningTaskItem>
  </SigningTask>
</TaskList>

<DataToSign> to jest xml z AuthTokenRequest. W odpowiedzi dostaję sam podpis, jeszcze jakby wrzucony w kontener podpisów:

Kopiuj
<?xml version="1.0" encoding="UTF-8"?>
<Signatures Id="ID-737f3997-160f-445f-a30b-4d811ebd9da2">
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="ID-30241772-ee2a-4746-8a4b-827c687e7180">
  ...

Zaznaczona jest opcja XAdES i Podpis wewnętrzny, również w tym pierwszym XMLu wysyłam <Format>XAdES-BES</Format> i <DataEmbedding>true</DataEmbedding>:

screenshot-20251105042919.png

Ktoś ma jakiś pomysł dlaczego nie dostaję podpisu osadzonego?

Janusz Konik
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5
0

Jeśli kolumnę tabeli załącznika deklaruje się "dec" to w zasadzie jakie to ma znaczenie?
Moim zdaniem przynajmniej powinno być prawo adjustowne, a tak nie jest.
Czy ktoś to zgłaszał?

Dzyszla
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 161
0

Dopracowałem nieco kod z generowaniem certyfiaktów. Co prawda poprzedni też działał, ale zastanawiało mnie, co z tą krzywą... Teoretycznie poniższy powinien uwzględnić właściwą:

Kopiuj
crtKey := TMemoryStream.Create;
try
	CertRequest := TElCertificateRequest.Create(nil);
	try
		with CertRequest.Subject do
		begin
			Add(SB_CERT_OID_COMMON_NAME, BytesOfString(KSeFClient.JSONResponse.GetValue<String>('commonName', '')));
			Add(SB_CERT_OID_COUNTRY, BytesOfString(KSeFClient.JSONResponse.GetValue<String>('countryName', 'PL')));

			tmpS := KSeFClient.JSONResponse.GetValue<String>('givenName', '');
			if not tmpS.IsEmpty then
				Add(SB_CERT_OID_GIVEN_NAME, BytesOfString(tmpS));

			tmpS := KSeFClient.JSONResponse.GetValue<String>('surname', '');
			if not tmpS.IsEmpty then
				Add(SB_CERT_OID_SURNAME, BytesOfString(tmpS));

			tmpS := KSeFClient.JSONResponse.GetValue<String>('serialNumber', '');
			if not tmpS.IsEmpty then
				Add(SB_CERT_OID_SERIAL_NUMBER, BytesOfString(tmpS));

			tmpS := KSeFClient.JSONResponse.GetValue<String>('uniqueIdentifier', '');
			if not tmpS.IsEmpty then
				Add(SB_CERT_OID_UNIQUE_IDENTIFIER, BytesOfString(tmpS));

			tmpS := KSeFClient.JSONResponse.GetValue<String>('organizationName', '');
			if not tmpS.IsEmpty then
				Add(SB_CERT_OID_ORGANIZATION, BytesOfString(tmpS));

			tmpS := KSeFClient.JSONResponse.GetValue<String>('organizationIdentifier', '');
			if not tmpS.IsEmpty then
				Add(SB_CERT_OID_ORGANIZATION_IDENTIFIER, BytesOfString(tmpS));
		end;

		AlgObj := nil;
		HashObj := nil;
		try
			if rbAlgorytm_RSA.Checked then
			begin
				Algorithm := SB_CERT_ALGORITHM_ID_RSA_ENCRYPTION;
				if rbHash_SHA1.Checked then
					Hash := SB_CERT_ALGORITHM_SHA1_RSA_ENCRYPTION
				else if rbHash_SHA256.Checked then
					Hash := SB_CERT_ALGORITHM_SHA256_RSA_ENCRYPTION
				else if rbHash_SHA384.Checked then
					Hash := SB_CERT_ALGORITHM_SHA384_RSA_ENCRYPTION
				else
					Hash := SB_CERT_ALGORITHM_SHA512_RSA_ENCRYPTION;

				KeySize := 2048;
			end
			else if rbAlgorytm_RSA_PSS.Checked then
			begin
				Algorithm := SB_CERT_ALGORITHM_ID_RSAPSS;

				KeySize := 2048;
			end
			else
			begin
				Algorithm := SB_CERT_ALGORITHM_EC;     // SB_OID_EC_SECP256R1
				if rbHash_SHA512.Checked then
					Hash := SB_CERT_ALGORITHM_SHA512_ECDSA
				else if rbHash_SHA384.Checked then
					Hash := SB_CERT_ALGORITHM_SHA384_ECDSA
				else
					Hash := SB_CERT_ALGORITHM_SHA256_ECDSA;
				KeySize := 256;

				AlgObj := TElAlgorithmIdentifier.CreateByAlgorithm(Algorithm);
				TElECAlgorithmIdentifier(AlgObj).Curve := SB_OID_EC_SECP256R1;
			end;
			if AlgObj = nil then
				AlgObj := TElAlgorithmIdentifier.CreateByAlgorithm(Algorithm);
			HashObj := TElAlgorithmIdentifier.CreateByAlgorithm(Hash);

			CertRequest.Generate(AlgObj, KeySize, HashObj);
		finally
			if Assigned(AlgObj) then
				AlgObj.Free;
			if Assigned(HashObj) then
				HashObj.Free;
		end;
		CertRequest.SaveKeyToStreamPEM(crtKey, '');

//ŻĄDANIA I ODBIÓR do crtBytes. Złączenie:
		Cert := TElX509Certificate.Create(nil);
		crtStream := TMemoryStream.Create;
		try
			crtStream.Write(crtBytes, Length(crtBytes));
			crtStream.Position := 0;
			Cert.LoadFromStream(crtStream);

			crtKey.Position := 0;
			Cert.LoadKeyFromStreamPEM(crtKey, '');

			Cert.FriendlyName := edNazwaCertyfikatu.Text; // i tak nie dołącza :(
			Cert.WinSetFriendlyName(edNazwaCertyfikatu.Text); // i tak nie dołącza :(

			crtStream.Clear;
			Cert.SaveToStreamPFX(crtStream, edPassword.Text, SB_ALGORITHM_PBE_SHA1_3DES, SB_ALGORITHM_PBE_SHA1_RC2_128);
		finally
			crtStream.Free;
			Cert.Free;
		end;
finally
	CrtKey.Free;
end;

Zwracam uwagę na hasło przy zapisie do PFX - musi jakieś być, bo bez tego niby jest certyfikat i wszystko, ale jak go się próbuje użyć to dostaję komunikat "failed to acquire key context" Nie wiem, jak zmusić do dołączenia atrybutu FriendlyName :( Ale może przestanę to instalować przez certutils z pliku PFX, tylk też SBB wykorzystam wprost to wsadzenia certyfikatu do magazynu windowsa.

M4
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 52
0

Mam pytanie do piszących w PHP, jak pobieracie paczki z fakturami bo wydaje mi się że get do pobrania paczki trwa u mnie bardzo długo paczka też nie dużo waży kilkadziesiąt kb, poniżej kawałek kodu

Kopiuj
$response = $this->client->request('GET', $url, [
                        'timeout' => 120,
                        'headers' => [
                            'User-Agent' => 'KSeFClient/2.0)',
                            'Accept' => 'application/octet-stream',
                        ],
                    ]);

                    $statusCode = $response->getStatusCode();

                    if ($statusCode !== 200) {
                        throw new \RuntimeException("Nie udało się pobrać paczki faktur. Kod HTTP: {$statusCode}");
                    }

                    $content = $response->getContent();

                    if (empty($content)) {
                        throw new \RuntimeException("Pusta zawartość odpowiedzi dla: {$url}");
                    }

                    $fh = fopen($localFilePath, 'wb');
                    if (!$fh) {
                        throw new \RuntimeException("Nie udało się otworzyć pliku do zapisu: {$localFilePath}");
                    }

                    fwrite($fh, $content);
                    fflush($fh);
                    fclose($fh);
                    clearstatcache(true, $localFilePath);
AdrianWladyka
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 6
0

jak przerobić certyfikat na .p12 majac .cert i .key?

Próbowałem w ten sposób i dostaję błąd: Uncaught RuntimeException: Uwierzytelnianie zakończone niepowodzeniem
I w ten sposób walę głową o ścianę :/

Kopiuj
openssl pkcs12 -export  -in  test05112025v1.crt   -inkey test05112025v1.key   -out test05112025v1.p12   -name "KSeF"   -certpbe AES-256-CBC  -keypbe  AES-256-CBC  -macalg  sha256
RA
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 32
0

Odnośnie wysyłki interaktywnej (z góry przepraszam jeśli to było gdzieś poruszone już).
Wysyłanie faktury (/api/v2/sessions/online/{referenceNumber}/invoices) kończy się timeoutem. Czy użycie "/api/v2/sessions/{referenceNumber}/invoices" natychmiast po timeoucie gwarantuje, że na podstawie zwróconej listy faktur można stwierdzić czy owa faktura została odebrana? Nie jest dla mnie istotne nawet czy została przyjęta czy z jakiegoś powodu odrzucona - chodzi tylko o to czy dotarła. Obstawiam, że nie. RequestTimeout w ich bibliotece javowej jest ustawiony na 100 sekund, czyli ksef może to jeszcze mielić jak będę odpytywał o listę faktur. Ile czekacie w takiej sytuacji, żeby zdecydować co dalej z tą fakturą robić, czy wysyłać ponownie bo może nawet nie dotarła do ksefu?

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.