Postup vydání TWINS certifikátu¶
V této kapitole je popsán postup volání jednotlivých komunikací se systémy I.CA, jak by měly být postupně za sebou provolány při procesu vydání TWINS certifikátu. Proces vydání lze rozdělit na dvě varianty vydání certifikátu, viz Varianty vydání certifikátu.
Prerekvizitou pro vydání certifikátu je mít nastavený kód RA a vlastnit certifikát (komerční nebo twins pár) s operátorským oprávněním. Pro vydání balíčku TWINS je potřeba mít vygenerovány dvě CSR ve formátu PKCS#10, kdy z první CSR bude vytvořen kvalifikovaný certifikát a z druhé komerční certifikát. V balíčku TWINS jsou poté certifikáty propojeny pomocí rozšíření certifikátu, kdy každý certifikát ma svou roli:
- master - hlavní certifikát z balíčku TWINS - certifikát kvalifikovaný
- slave - podřízený certifikát z balíčku TWINS - certifikát komerční
Při vydávání certifikátů formou balíčku TWINS je potřeba mít dvě instance třídy CaConnector
. Při procesu se komunikuje vždy s komerční (SICA) i kvalifikovanou (SICA) CA. Pro obě CA lze využít jeden a operátorský certifikát.
Proces vydání certifikátu¶
1. Ověření operátorského certifikátu (BicaConnector.ControlOperatorAsync)¶
Před zahájením zpracování žádosti by se měl ověřit certifikát, kterým se podepisují těla http požadavků, zda má operátorské oprávnění a lze s ním vydávat nové certifikáty. Zavoláním této komunikace lze předejít budoucím chybným voláním následujících komunikací, kdy by všechny vracely chybu použití špatného certifikátu pro komunikaci s daným systémem.
Ověření probíhá na základě podpisu http těla požadavku komunikace BicaConnector.ControlOperatorAsync
, kdy BICA získá informace o podpisovém certifikátu a ověří jej, zda má operátorské oprávnění.
2. Získání ID pro žádost o kvalifikovaný certifikát z balíčku TWINS (CaConnector.GetReqIdAsync)¶
Po načtení žádosti by se mělo nejprve žádosti přiřadit id. Id žádosti se přiřazuje na začátku procesu z důvodu, že je součástí protokolu, který je potřeba získat před odesláním žádosti na CA.
Metoda GetReqIdAsync
vrací poslední evidované číslo žádosti pro daný kód RA. Získané číslo žádosti tedy není možné ihned použít ale je potřeba jej inkrementovat do doby dokud se z něj nestane unikátní číslo žádosti (např. z CA se získá id žádosti 101, v RA jsou rozpracované žádosti 102 a 103, nově vytvářené žádosti je tedy potřeba přiřadit id 104)
Odpověď je zapouzdřena ve třídě GetReqIdResp. Číslo žádosti je uvedené ve vlastnosti GetReqIdResp.ReqID
.
Vlastnost GetReqIdResp.ReqIDTwin
slouží pro porovnání id žádostí párových certifikátů při vydávání certifikátů twins. Tato vlastnost je přidána z důvodu oddělené kvalifikované (QICA) a komerční CA (SICA). Slouží ke kontrole aby se twins žádosti nenastavili špatné id. Srovnává se ReqIdTwin získáné ze SICA s ReqId ziskáným ze QICA a naopak.
3. Získání ID pro žádost o komerční certifikát z balíčku TWINS (CaConnector.GetReqIdAsync)¶
Obdobně jako v bodu 2. je potřeba provést komunikaci ještě jednou pro získání id žádosti pro komerční CSR. Komunikace probíhá úplně stejně, pouze je potřeba použít instanci connectoru, která cílí na SICA.
4. Získání protokolu o podání žádosti (BicaConnector.GetProtocolAsync)¶
Dalším krokem získání protokolu o podání žádosti, který je potřeba vytisknout a podepsat (v rámci elektronického vydávání pouze el. podepsat). Protokol je generován systémem BICA. Aplikace RA zašle dostupná data (data ze žádosti o certifikát a osobní údaje žadatele získané operátorem RA nebo jiným způsobem), která jsou k dispozici ve třídě GetProtocolReqBody a GetProtocolBodyData.
Komunikace BicaConnector.GetProtocolAsync
slouží pro vygenerování více druhů protokolů, z toho důvodu je naplnění instance třídy GetProtocolBodyData
velice variabilní. V rámci získání protokolu o podání žádosti o TWINS balíček certifikátů je potřeba nastavit tyto položky:
ChallengePassword
- heslo pro zneplatněníDate
- datum vytvoření protokoluDateAndTime
- datum podpisu protokoluFirmName
- název společnosti, je potřeba uvést pouze pokud je certifikát vydáván zaměstnanci nebo právnické osobě.Locality
- umístění kde protokol vznikl (lokalita kde se nachází RA)RaCode
- identifikační kód RARaOperator
- celé jméno operátora RAAddress
- adresa žadateleCertificateTransparency
- příznak o zveřejnění certifikátuIdentification
- rodné číslo nebo datum narozeníMpsv
- příznak o přidělení IK MPSVName
- křestní jméno žadatelePrimaryDocument
- primární doklad totožnosti (typicky občanský průkaz)SecondaryDocument
- sekundární doklad totožnosti (povinný pouze pro kvalifikované certifikáty)PublicCertificate
- příznak zda bude certifikát vydán jako veřejnýReqId
- číslo žádosti o hlavní (kvalifikovaný) certifikátSurname
- Příjmení žadateleDn
- předmět žádosti o hlavní (kvalifikovaný) certifikát (Dictionary položek OID a seznam hodnot)San
- alternativní jméno předmětu žádosti o hlavní (kvalifikovaný) (Dictionary položek OID a seznam hodnot) - pouze pokud je SAN k dispoziciEku
- rozšířené použití klíče hlavního (kvalifikovaného) certifikátu (Dictionary položek OID a seznam hodnot) - pouze pokud žádost obsahuje EKUSigner
- podepisující (jméno žadatele, které se vkládá do závěrečné části pod kolonku pro podpis žadatele)Dn2
- předmět žádosti o podřízený (komerční) certifikátSan2
- alternativní jméno předmětu (Dictionary položek OID a seznam hodnot) pro podřízený (komerční) certifikát - pouze pokud je SAN k dispoziciEku2
- rozšířené použití klíče (Dictionary položek OID a seznam hodnot) podřízený (komerční) certifikát - pouze pokud žádost obsahuje EKUCertType2
- typ podřízeného certifikátu (komerčního) z balíčku TWINS
Pro získání instance třídy GetProtocolBodyData je k dispozici builder třída GetProtocolBodyDataBuilder. Pro získání položek typu Dictionary{string, List{string}}
(např. Dn, San, Eku) lze využít builder třídu GetProtocolDictionaryBuilder
Ukázka použití GetProtocolDictionaryBuilder
pro nastavení SAN:
var sanKc = new GetProtocolDictionaryBuilder()
.AddItem("1", "novak@example.cz")
.AddItem("0", "a.example.cz")
.AddItem("0", "b.example.cz")
.Build();
Ukázka použití GetProtocolDictionaryBuilder
pro nastavení EKU:
var eku = new GetProtocolDictionaryBuilder()
.AddItem("1.3.6.1.5.5.7.3.4", null, true)
.AddItem("1.3.6.1.5.5.7.3.2", null, true)
.Build();
Instance třídy GetProtocolBodyData se poté vkládá do objektu GetProtocolReqBody. Tento objekt obsahuje základní základní informace o žádosti:
CertType
- typ hlavního certifikátu (viz typy certifikátů) (kvalifikovaného) z balíčku TWINSLanguage
- jazyk v jakém bude protokol vygenerován (hodnoty - cs, en, sk)PayParentId
- id plátce za certifikát (viz plátce za certifikát)Data
- instance objektu GetProtocolBodyDataTemplate
- typ šablony, zde vždy hodnotaPROTOCOL
Pro vytvoření instance GetProtocolReqBody
lze využít builder třídu GetProtocolBodyBuilder
Instanci třídy GetProtocolReqBody
je potřeba převést do JSON a zakódovat do Base64String. Tuto hodnotu je potřeba vložit do objektu GetProtocolReq. Pro tvorbu instance GetProtocolReq
lze využít builder třídu GetProtocolReqBuilder, která přebírá instanci GetProtocolReqBody
a provede převedení do JSON a zakódování do Base64String.
Instanci třídy GetProtocolReq
již lze předat parametru funkce BicaConnector.GetProtocolAsync
, která zašle požadavek na vygenerování protokolu. Ten je navrácen ve třídě GetProtocolResp ve vlastnosti Protocol
, kde je zakódován v Base64String. Protokol je generován ve formátu PDF.
Získaný protokol je poté v závislosti na způsobu vydání certifikátu zpracovat:
- Papírově - protokol je potřeba vytisknout a fyzicky jej podepsat (operátor i žadatel).
- Elektronicky - protokol elektronicky (PAdES-B) podepíše operátor svým kvalifikovaným certifikátem.
5. Odeslání protokolu o podání žádosti na systém STORAGE (StorageConnector.PutCertificateRequest)¶
Pokud je žádost o certifikát vyřizována papírovou formou, tento krok se musí přeskočit.
V případně elektronické formy vydání certifikátu je před odesláním žádosti na CA nejprve potřeba žádost zaevidovat v systému Storage, kde se pro žádost budou archivovat jednotlivé protokoly.
Funkce StorageConnector.PutCertificateRequest
na vstupu přebírá instanci třídy PutCertificateRequestReq, která musí mít inicializovány následující položky:
ReqId
- id žádosti o certifikát. Pokud se jedná o žádost pro párový certifikát TWINS, udává se id hlavní žádosti (id žádosti pro kvalifikovaný certifikát z páru TWINS).CertProfile
- typ profilu certifikátu (viz profily žadatelů)OperatorCertificate
- informace o kvalifikovaném certifikátu z páru TWINS operátora (sériové číslo a AKID)PayParent
- id plátce za certifikát (viz plátce za certifikát)CertType
- typ certifikátu (viz typy certifikátů)Documents
- seznam přiložených dokumentů. Seznam musí obsahovat dokument s typem PROTOCOL, který vznikl v kroku 4 a byl elektronicky podepsán. Informace o dokumentu jsou zapouzdřeny ve třídě StorageDocumentObject.
Pro získání instance třídy PutCertificateRequestReq
je k dispozici builder třída PutCertificateRequestReqBuilder, která obsahuje metodu i pro vytvoření instance třídy StorageDocumentObject
a přidání do seznamu dokumentů.
Po úspěšném zavolání metody StorageConnector.PutCertificateRequest
lze pokračovat dále v odeslání žádostí na SICA a QICA. Pokud v této komunikaci nastane chyba, nesmí být žádosti odeslány.
Server Storage validuje zaslané dokumenty - ty musí obsahovat el. podpis certifikátem. Pokud se jedná o přílohu typu PDF, el. podpis musí být typu PAdES. Pokud se jedná např o přílohu JPG, musí se jednat o externí podpis CAdES-B.
6. Odeslání žádosti komerční certifikát z balíčku TWINS na systém SICA (CaConnector.PutReqAsync)¶
Doporučený postup při odesílání žádostí na systémy CA je nejprve odeslat žádost o komerční certifikát. Díky tomu je kompletní proces vydání obou certifikátů o něco rychlejší (při vydání probíhá interní komunikace mezi QICA a SICA, QICA se dotazuje SICA na přítomnost párové žádosti, pokud ji SICA v tento moment již eviduje, je zpracování vydání kvalifikovaného certifikátu zahájeno ihned. V opačném případě je žádost u určitý interval pozdržena a poté se opět dotazuje SICA na přítomnost párové žádosti).
Funkce pro odeslání žádosti Caconnector.PutReqAsync
přebírá jako parametr instanci třídy PutReqReq, která se skládá z následujících položek:
KeyAndRequestData (KeyAndRequestDataObject)¶
Obsahuje samotnou žádost o certifikát, ID žádosti a další údaje týkající se žádosti (např. číslo karty, pokud byl klíč generován na kartě). Instanci třídy lze získat pomocí builder třídy KeyAndRequestDataBuilder a je potřeba inicializovat tyto položky:
Request
- data žádosti o komerční certifikát z balíčku TWINS ve formátu PEMReqId
- id žádosti o komerční certifikát z balíčku TWINSReqIDInterconnection
- pro žádost o balíček TWINS je potřeba uvést údaje o žádostech z daného balíčku. U TWINS se jedná o dva záznamy:- Informace o kvalifikované žádosti z balíčku TWINS - zadat její ID, roli (vždy master) a typ certifikátu (typicky Q-TW-CZ)
- Informace o komerční žádosti z balíčku TWINS - zadat její ID, roli (vždy slave) a typ certifikátu (typicky S-TW)
Ukázka použití třídy KeyAndRequestDataBuilder
s přidáním informací o párových žádostech:
var keyAndReqDataQc = new KeyAndRequestDataBuilder()
.SetReqID(newReqIdQc.ToString())
.SetRequest(reqDataQc)
// Při odesílání na CA je potřeba odeslat specifikovat informace o tom jak má výsledné spárování v balíčku Twins vypadat. Je potřeba vždy specifikovat informace o obou certifikátech a jejich roli:
// Žádost o kvalifikovaný certifikát je vždy master, dále uvedeme typ kvalifikovaného certifikátu a ID žádosti o kvalifikovaný certifikát
// Žádost o komerční certifikát je vždy slave, dále uvedeme typ komerčního certifikátu a ID žádosti o komerční certifikát
.SetReqIDInterconnection(newReqIdQc, "master", "Q-TW-CZ") // kvalifikovaný certifikát z balíčku TWINS
.SetReqIDInterconnection(newReqIdKC, "slave", "S-TW") // Komerční certifikát z balíčku TWINS
.SetCardNumber("9203070100044401")
.Build();
Další položky se nastavují v závislosti na typu certifikátu a kde je uložen klíčový pár (např. CardNumber
a QSCD
pokud bude certifikát uložen na čipové kartě, která má status QSCD).
CertificateProperties PutReqCertProps¶
Parametry pro vytvářený certifikát. Pro získání instance třídy PutReqCertProps
lze využít builder třídu PutReqCertPropsBuilder. Objekt musí mít inicializovány alespoň tyhle hodnoty:
CertChallengePassword
- heslo pro zneplatnění certifikátuCertType
- typ kvalifikovaného certifikátu z balíčku TWINS, viz typy certifikátůMpsvIk
- Příznak zda se má vložit do certifikátu IK MPSV (hodnoty - yes, no) (lze použít pouze pro kvalifikované certifikáty, komerční certifikáty musí mít hodnotu "no")
BillingData (BillingDataObject)¶
Informace o plátci za certifikát. Instanci BillingDataObject
lze získat pomocí builder třídy BillingDataBuilder. Instance musí mít inicializovanou hodnotu PayParentId
(viz plátce za certifikát).
UserData (PutReqUserData)¶
Osobní údaje a další vyžadované informace o žadateli. Instanci PutReqUserData
lze získat pomocí builder třídy PutReqUserDataBuilder, a musí mít inicializované následující vlastnosti:
Name
- křestní jméno žadateleSurname
- příjmení žadateleAddress
- adresa trvalého bydliště žadateleDocument
- Doklad totožnostiLanguage
- Jazyk (Hodnoty - cs, en, sk)
Ostatní položky jsou povinné pouze pro specifické typy nebo profily certifikátů, např.:
Document2
- vyžadováno pro identitní certifikátySex
- pohlaví žadatele (M - muž, F - žena). Je potřeba zadat pouze pro kvalifikovaný certifikát, bude obsahovat IK MPSV (pohlaví je vyžadováno při přidělení IK MPSV).Company
- vyžadováno pro zaměstnanecké profily certifikátů (instanci třídy CompanyObject lze získat pomocí builder třídy CompanyBuilder).
Instanci třídy PutReqReq
lze získat pomocí builder třídy PutReqReqBuilder.
Pokud odeslání žádosti proběhne v pořádku není navrácena žádná návratová hodnota. V případě chyby je navrácena výjimka CAServerException.
Žádost o komerční certifikát z balíčku TWINS je potřeba odeslat na komerční CA (SICA).
7. Odeslání žádosti kvalifikovaný certifikát z balíčku TWINS na systém QICA (CaConnector.PutReqAsync)¶
Po odeslání žádosti o komerční certifikát je potřeba odeslat ještě žádost o kvalifikovaný certifikát. Proces je totožný jako v předchozím bodě, pouze je potřeba dbát na vložení údajů ze žádosti o kvalifikovaný certifikát z balíčku TWINS.
Rozlišenosti v údajích:
KeyAndRequestData
-Request
aReqID
.ReqIDInterconnection
je potřeba vložit stejně jako v bodě 6.CertificateProperties
-CertType
, zbytek údajů jsou shodnéBillingData
- údaje jsou shodnéUserData
- údaje jsou shodné
Žádost o kvalifikovaný certifikát z balíčku TWINS je potřeba odeslat na kvalifikovanou CA (QICA).
8. Získání vydaného komerčního certifikátu z balíčku TWINS ze systému SICA (CaConnection.GetCertificateAsync)¶
Získání vydaného certifikátu probíhá pomocí volání komunikace CaConnection.GetCertificateAsync
. Metoda v parametru přebírá instanci třídy GetCertReqBody. Vyhledávat certifikát lze buď pomocí sériového čísla, čísla žádosti nebo SHA-1 otisku klíče.
Při vydávání prvotního certifikátu se využívá čísla žádosti, pro dotaz je tedy potřeba vytvořit instanci třídy GetCertReqBody
a inicializovat její vlastnost ReqId
. Pro inicializaci instance GetCertReqBody
lze využít builder třídu GetCertReqBodyBuilder.
Metoda CaConnections.GetCertificateAsync
vrací v odpovědi instanci třídy GetCertRespBody. V této instanci je nejprve potřeba zkontrolovat naplnění vlastnosti GetCertRespBody.RegInfo.State. Tato vlastnost indikuje aktuální stav zpracování žádosti o certifikát. Rozlišují se tři stavy:
inprocess
(CaConnection.GETCERT_STATE_INPROCESS) - žádost se zpracovává a certifikát ještě nebyl vydán. Vlastnosti GetCertRespBody.CertificateObject a GetCertRespBody.ReqRejectInfo mají hodnotu null. Objekt GetCertRespBody.RegInfo obsahuje ještě vlastnost StateCode, kde je uveden kód identifikující v jakém kroku se zpracování žádosti nyní nachází.certissued
(CaConnection.GETCERT_STATE_CERTISSUED) - certifikát byl vydán. Certifikát se nachází v objektu GetCertRespBody.CertificateObject.rejected
(CaConnection.GETCERT_STATE_REJECTED) - žádost o vydání certifikátu byla zamítnuta. Důvod zamítnutí žádosti je uveden v objektu GetCertRespBody.ReqRejectInfo, ve kterém jsou dostupné informace z jakého důvodu byla žádost zamítnuta.
Dotazy vzniklé v komunikaci GetCertificateAsync je možné cachovat, viz Obecný popis třídy CaConnector.
Pokud je stav žádosti inprocess
, je potřeba se po čase dotázat stejným způsobem na aktuální stav a tento dotaz opakovat dokud se stav žádosti nezmění na certissued
nebo rejected
.
Dotaz je potřeba odesílat na systém SICA!
9. Získání vydaného kvalifikovaného certifikátu z balíčku TWINS ze systému QICA (CaConnection.GetCertificateAsync)¶
Stejně jako v bodě 8 je potřeba i v tomto kroku komunikovat se systémem QICA pro získání kvalifikovaného certifikátu z balíčku TWINS. Proces je totožný, rozdíl je pouze v ID žádosti a systému na který se požadavek odesílá.
Kroky 7 a 8 lze provádět najednou paralelně.
10. Získání smlouvy o vydání balíčku certifikátů TWINS (BicaConnector.GetProtocolAsync)¶
K získání smlouvy o certifikát se používá funkce BicaConnector.GetProtocolAsync
podobně jako v kroku 4. Smlouvu je poté potřeba vytisknout a vlastnoručně podepsat nebo v případě elektronické formy vydání elektronicky podepsat (operátor i klient).
Pro vygenerování smlouvy je potřeba zaslat systému BICA informace pro vyplnění šablony smlouvy pro TWINS balíček certifikátů. Instance třídy GetProtocolBodyData by měla mít inicializované tyto vlastnosti:
CertDateTimeFrom
- Platnost hlavního (kvalifikovaného) certifikátu odCertDateTimeFrom2
- platnost podřízeného (komerčního) certifikátu odCertDateTimeTo
- platnost hlavního (kvalifikovaného) certifikát doCertDateTimeTo2
- platnost podřízeného (komerčního)certifikátu doDate
- datum vytvoření protokoluDateAndTime
- datum a čas, který bude uveden v protokoluLocality
- umístění RARaCode
- identifikační kód RARaOperator
- jméno operátora RASerialNumber
- sériové číslo hlavního (kvalifikovaného) certifikátuSerialNumber2
- sériové číslo podřízeného (komerčního) certifikátuAddress
- adresa trvalého bydliště žadateleAlgorithm
- algoritmus klíčového páru hlavního (kvalifikovaného) certifikátuAlgorithm2
- algoritmus klíčového páru párového podřízeného (komerčního) certifikátuIdentification
- rodné číslo / datum narozeníName
- křestní jméno majitele certifikátuSurname
- Příjmení majitele certifikátuReqId
- id žádosti o hlavní (kvalifikovaný) certifikátReqId2
- id žádosti o podřízený (komerční) certifikátDn
- předmět hlavního (kvalifikovaného) certifikátu jako Dictionary{string, List{string}}Dn1
- předmět podřízeného (komerčního) certifikátu jako Dictionary{string, List{string}}DnIssuer
- předmět vydavatele hlavního (kvalifikovaného) certifikátu jako Dictionary{string, List{string}}DnIssuer2
- předmět vydavatele podřízeného (komerčního) certifikátu jako Dictionary{string, List{string}}Signer
- jméno majitele certifikátu (je uvedeno v podpisové části smlouvy)CertType2
- typ podřízeného (komerčního) certifikátu, viz typy certifikátů
Instance třídy GetProtocolBodyData
se poté vkládá do objektu GetProtocolReqBody. Tento objekt obsahuje základní základní informace o žádosti:
CertType
- typ hlavního (kvalifikovaného) certifikátu, viz typy certifikátůLanguage
- jazyk v jakém bude protokol vygenerován (hodnoty - cs, en, sk)PayParentId
- id plátce za certifikátData
- instance objektu GetProtocolBodyDataTemplate
- typ šablony, zde vždy hodnotaAGREEMENT
Pro vytvoření instance GetProtocolReqBody
lze využít builder třídu GetProtocolBodyBuilder
Instance třídy GetProtocolReqBody
je potřeba převést do JSON a zakódovat do Base64String. Tuto hodnotu je potřeba vložit do objektu GetProtocolReq. Pro tvorbu instance GetProtocolReq
lze využít builder třídu GetProtocolReqBuilder, která převedení na json a zakódování do Base64String má implementováno.
Instanci třídy GetProtocolReq
již lze předat parametru funkce BicaConnector.GetProtocolAsync
, která zašle požadavek na vygenerování smlouvy. Ta je navrácena ve třídě GetProtocolResp ve vlastnosti Protocol
, kde je smlouva zakódována v Base64String. Po dekódování hodnoty je smlouva dostupná ve formátu PDF.
Pokud je balíček TWINS vydán papírovou formou, získanou smlouvu je potřeba vytisknout a vlastnoručně fyzicky podepsat. V případě zpracování elektronického je potřeba smlouvu podepsat elektronicky podpisem typu PAdES-B a pokračovat krokem 11.
11. Uložení smlouvy o využití certifikátů z baličku TWINS na úložiště dokumentů STORAGE (StorageConnector.PutCertificateAgreementAsync)¶
Pokud byl balíček certifikátů TWINS vydán papírovou formou, tento krok se neprovádí a proces vydání certifikátu je dokončen.
V případě vydání certifikátu el. formou je posledním krokem nahrání el. podepsané smlouvy na úložiště dokumentů. Tento krok je nutno provést, v opačném případě se certifikáty z balíčku TWINS po definované době (1 měsíc) automaticky zneplatní.
StorageConnector.PutCertificateAgreementAsync
na vstupu přebírá instanci třídy PutCertAgreementReq. Instanci lze získat pomocí builder třídy PutCertAgreementReqBuilder a musí mít inicializovány tyto vlastnosti:
ReqId
- id žádosti o hlavní (kvalifikovaný) certifikátApplicantCertificate
- informace (sériové číslo a AKID (Authority Key Identifier)) nově vydaného hlavního (kvalifikovaného) certifikátu z balíčku TWINSIssuedCertificate
- informace (sériové číslo a AKID) nově vydaného hlavního (kvalifikovaného) certifikátu z balíčku TWINS (stejné jako vlastnost ApplicantCertificate)OperatorCertificate
- informace o kvalifikovaném certifikátu z páru TWINS operátora (sériové číslo a AKID)CertType
- typ certifikátu, viz typy certifikátůAggreement
- smlouva o vydání certifikátu el. podepsaná operátorským kvalifikovaným certifikátem z páru TWINS a nově vydaným klientským certifikátem
Po úspěšném provedení komunikace StorageConnector.PutCertificateAgreementAsync je dokončen i proces el. vydání certifikátu.
Ukázka procesu vydání TWINS certifikátu pomocí UNIT testů¶
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RAConnection.BICA.Builders;
using RAConnection.CA.Builders;
using RAConnection.CA.GetCert;
using RAConnection.Common;
using RAConnection.Common.Cache;
using RAConnection.IssueCertTest.Utils;
using RAConnection.Storage.Builders;
using System;
using System.IO;
using System.Net.Http;
using System.Numerics;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
namespace RAConnection.IssueCertTest;
[TestClass]
public class TwinIssueCertTest
{
ILogger<IssueCertTest> _log;
CaConnector _qicaConnector;
CaConnector _sicaConnector;
StorageConnector _storageConnector;
BicaConnector _bicaConnector;
HttpClient _httpClient;
ILoggerFactory _loggerFactory;
const string URL_SICA = "https://tests.ica.cz:443/cgi-bin/racom.cgi";
const string URL_QICA = "https://testq.ica.cz:443/cgi-bin/racom.cgi";
const string URL_BICA = "https://tbica.ica.cz/cgi-bin/BicaRaComAPI.cgi";
const string URL_STORAGE = "https://td.ica.cz/cgi-bin/StorageRaComAPI.cgi";
string _opraCertSN = "01a854"; // Nastavit sériové číslo operátorského certifikátu
string _codeRA = "000"; // Nastavit kód RA podle toho jaký vám přiřadí
string _certTypeQc = "Q-TW-CZ";
string _certTypeKC = "S-TW";
string _profile = "NATURAL-PERSON";
string _profileEmployee = "EMPLOYEE";
string _payParentId = "26995"; // Nastavit plátce jaký vám bude přiřazen
[TestInitialize]
public void Initialize()
{
_httpClient = new HttpClient();
_loggerFactory = LoggerFactory.Create((x) =>
{
var log4netProvider = new Log4NetProviderOptions("log4net.config");
x.AddLog4Net(log4netProvider);
x.SetMinimumLevel(LogLevel.Debug);
});
_log = _loggerFactory.CreateLogger<IssueCertTest>();
var clientName = "CertiSysRA";
// U Twins se komunikuje s kvalifikovanou i komerční CA, stav vydání obou certifikátu balíčku twins si musí hlídat RA
_qicaConnector = new CaConnector(_httpClient, _loggerFactory, clientName, getReqIdCache: null, getCertCache: new MemoryGetCertCache(),
getProvCertCache: null);
_sicaConnector = new CaConnector(_httpClient, _loggerFactory, clientName, getReqIdCache: null, getCertCache: new MemoryGetCertCache(),
getProvCertCache: null);
_storageConnector = new StorageConnector(_loggerFactory, clientName, _httpClient);
_bicaConnector = new BicaConnector(_loggerFactory, clientName, _httpClient);
var opraSigner = new DefaultOperatorSigner(LoadCertificate());
_qicaConnector.ServerUrl = URL_QICA;
_qicaConnector.OperatorSigner = opraSigner;
_qicaConnector.SetRaCodeFromString(_codeRA);
_sicaConnector.ServerUrl = URL_SICA;
_sicaConnector.OperatorSigner = opraSigner;
_sicaConnector.SetRaCodeFromString(_codeRA);
_bicaConnector.ServerUrl = URL_BICA;
_bicaConnector.OperatorSigner = opraSigner;
_bicaConnector.SetRaCodeFromString(_codeRA);
_storageConnector.ServerUrl = URL_STORAGE;
_storageConnector.OperatorSigner = opraSigner;
_storageConnector.SetRaCodeFromString(_codeRA);
}
X509Certificate2 LoadCertificate(string certSN = null)
{
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
string sn = certSN ?? _opraCertSN;
X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindBySerialNumber, sn, true);
if (certificates.Count > 0)
return certificates[0];
foreach (X509Certificate2 x509 in store.Certificates)
{
if (x509.Subject.IndexOf(sn) != -1)
return x509;
}
certificates = store.Certificates;
return certificates[0];
}
[TestMethod]
public async Task IssueCertPaperless_01_SendReq()
{
try
{
_log.LogInformation("IssueCertPaperless_01_SendReq START");
// 1 - ověření operátorského certifikátu
await _bicaConnector.ControlOperatorAsync();
// 2 - získání ID žádosti o kvalifikovaný certifikát
var lastReqIdQc = await _qicaConnector.GetReqIdAsync();
var reqIdQc = BigInteger.Parse(lastReqIdQc.ReqId);
++reqIdQc;
var newReqIdQc = reqIdQc.ToString();
File.WriteAllText("newReqIdQc.txt", newReqIdQc); // id žádosti bude potřeba pro další test metody
// 3 - získání ID žádosti o komerční certifikát
var lastReqIdKc = await _sicaConnector.GetReqIdAsync();
var reqIdKc = BigInteger.Parse(lastReqIdKc.ReqId);
++reqIdKc;
var newReqIdKC = reqIdKc.ToString();
File.WriteAllText("newReqIdKc.txt", newReqIdKC); // id žádosti bude potřeba pro další test metody
// 4 - Získání protokolu o podání žádosti - je stejné jako u samostatného certifikátu, jen je potřeba zadat jiný typ certifikátu
// a přidat další metadata pro vygenerování protokolu
var dnQc = new GetProtocolDictionaryBuilder()
.AddItem("2.5.4.3", "Jan Novák")
.AddItem("2.5.4.4", "Novák")
.AddItem("2.5.4.6", "CZ")
.AddItem("2.5.4.42", "Jan")
.Build();
var dnKc = new GetProtocolDictionaryBuilder()
.AddItem("2.5.4.3", "Jan Novák")
.AddItem("2.5.4.4", "Novák")
.AddItem("2.5.4.6", "CZ")
.AddItem("2.5.4.42", "Jan")
.Build();
var sanQc = new GetProtocolDictionaryBuilder()
.AddItem("1", "manak@ica.cz") // Podobným způsobem lze nastavit ostatní hodnoty SAN (pokud by bylo potřeba vložit např více DNS name, stačí opět zavolat AddItem s DNS Name)
.Build();
var sanKc = new GetProtocolDictionaryBuilder()
.AddItem("1", "manak@ica.cz")
.Build();
// Pro SAN i EKU se používá společná třída pro serializaci objektu, pro EKU stačí zadat pouze OID, hodnotry pro v druhém parametru pak nastavit na null
// a v posledním parametru povolit nastavení hodnoty null
var ekuQc = new GetProtocolDictionaryBuilder()
.AddItem("1.3.6.1.5.5.7.3.4", null, true)
.Build();
var ekuKc = new GetProtocolDictionaryBuilder()
.AddItem("1.3.6.1.5.5.7.3.4", null, true)
.AddItem("1.3.6.1.5.5.7.3.2", null, true)
.Build();
// Předměty certifikátu jsou typicky stejné (my v generátoru žádostí údaje zadáváme jednou a ty se pak použijí při tvorbě obou CSR)
var protocolData = new GetProtocolBodyDataBuilder()
// Obecné údaje pro protokol
.SetChallengePwd("xxxx")
.SetDate("26.4.2024")
.SetDateAndTime("26.4.2023 10:48")
.SetLocality("Zlín")
.SetRaCode(_codeRA)
.SetRaOperator("OPRA Jakub Maňák")
.SetIdentification("700101123")
.SetAddress("Dlouhá 159, 76000 Zlín")
.SetCertificateTransparency("ANO")
.SetMpsv("NE")
.SetName("Jan")
.SetOtherDocument("LL 454544545")
.SetPrimaryDocument("IDCCZ-202080120")
.SetPublishCertificate("ANO")
.SetSecondaryDocument("CP, 12345678")
.SetSurname("Novák")
.SetSigner("Jan Novák")
.SetCardNumber("9203070100044401") // číslo karty na kterou byl klíč a žádost vygenerován
.SetChallengePwd("xxxx") // Heslo pro zneplatnění certifikátu
.SetFirmName("Firma s.r.o.")
// Údaje pro žádost QC certifikát z balíčku Twins
.SetReqId(newReqIdQc)
.SetDn(dnQc)
.SetEku(ekuQc)
.SetSan(sanQc)
// Nastavení hodnot o žádosti o komerční certifikát z páru Twins
.SetDn2(dnKc)
.SetReqId2(newReqIdKC)
.SetCertType2(_certTypeKC) // Typ komerčního certifikátu z páru Twins
.SetEku2(ekuKc)
.SetSan2(sanKc)
.Build();
var getProtocolBody = new GetProtocolBodyBuilder()
.SetPayParentId(_payParentId)
.SetLanguage("cs")
.SetBodyData(protocolData)
.SetCertType(_certTypeQc) // Používá se typ hlavního (pro Twins balíček tedy kvalifikovaný) certifikátu pro získání protokolu
.SetTemplate(BICA.GetProtocol.TemplateTypes.PROTOCOL) // šablona pro Protokol o podání žádosti
.Build();
var getProtocolReq = new GetProtocolReqBuilder()
.SetProtocolRequest(getProtocolBody)
.Build();
var protocolResp = await _bicaConnector.GetProtocolAsync(getProtocolReq);
if (protocolResp is null or { Protocol: null or { Length: 0 } })
Assert.Fail("No Protocol returned");
var protocolPdfData = Convert.FromBase64String(protocolResp.Protocol);
File.WriteAllBytes("protocol.pdf", protocolPdfData);
// 5 - Odeslání žádosti na Storage
// Protocol_Twins.pdf v adresáři test data podepište svým OPRA certem např. v Adobe a uložte do souboru Protocol_Twins_signed.pdf
var pdfProtocolData = File.ReadAllBytes(@"..\..\..\TestData\Protocol_Twins_signed.pdf");
var protocolBase64 = Convert.ToBase64String(pdfProtocolData);
var storagePutReqReq = new PutCertificateRequestReqBuilder()
.SetCertProfile(_profile)
.SetCertType(_certTypeQc) // Používá se typ kvalifikovaného certifikátu z balíčku Twins (kvalifikovaný)
// Jedná se o hodnoty QC párového certifikátu ke komerčnímu operátorskému (udávají se informace o certifikátu, kterým byl vytvořen PAdES podpis)
.SetOperatorCertificate("10098892", "16a5f56ceee98b5b95f7e0a3d01849ecf740ba9d")
.SetPayParent(_payParentId)
.SetProtocol(protocolBase64, Storage.PutCertificateRequest.StorageFileFormats.pdf)
.SetReqId(newReqIdQc)
.Build();
await _storageConnector.PutCertificateRequestAsync(storagePutReqReq);
// 6 - odeslání slave žádosti (komerční certifikát z balíčku TWINS) na komerční CA
var reqDataKc = // Vložit vlastní vygenerovanou žádost
"""
-----BEGIN CERTIFICATE REQUEST-----
MIIDVzCCAj8CAQAwQTETMBEGA1UEAwwKSmFuIE5vdsOhazEMMAoGA1UEKgwDSmFuMQ8wDQYDVQQE
DAZOb3bDoWsxCzAJBgNVBAYTAkNaMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvckW
ZKTMpTT5SXgGMYgzXPwxQFDQadEGt3FefLYcRtCYeS13CJJVpYjf0Qj1mq4Jev2d+ujyqOCCm3M3
p6wRtWIYzauaEUES3zkwPmRTlZGadspLfqESLPYxo6slfSARlde2II4Bmszy0F8KhqVuHs9gjVca
GPXrEquIA9+UwqNiQBnsipXY/L2UeW6gYM7uj5KlQAnabRDzNvccw2r1OXiNPF5ihxXZ+vPRW9o2
XAB4pdTH5g7R/YZwbm4yMvoBLmunTPb7UMN9KsEeGClW3lPcPvD42TFcjJB9aB20ARNFujivIgNm
IZJF2/nRb6mZQ4sky2a9M9DbmQxXip/WSQIDAQABoIHQMFcGCSqGSIb3DQEJDjFKMEgwFwYDVR0R
BBAwDoEMbWFuYWtAaWNhLmN6MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDBAYI
KwYBBQUHAwIwdQYKKwYBBAGBuEgECjFnMGUCAQECAioDDBVJQ0EgU3RhcmNvcyAzLjcgZVNpZ24C
AQEEEBABAAAAAAEDkgMHAQAERAEEMGTFmANwG2eAzhDDylL+yhwNjjTxjhnua5kINkLOQZKqPucl
SI2g122j0jBPwjR/NzANBgkqhkiG9w0BAQsFAAOCAQEAusnbLhIqVY2CUVNrZayDpT7joitIRLIe
6DfDKMUkLd1xTH5L59LW+t8Pqc/bHrh6ydOHeDaeDfVG3JDTdAbkYQlLmiYf2NRV/CswbBDPms+J
fDgAu/Oq5m3rkZv8IF60fbYrdb+8qQmvG3zwM6LCzafAeToNXCFTdIP4B2rABTCjZTnBcYyqlS9J
v4R0pcNQguCLooXbXGJckV3FYSCH5punLLdTcuXgeXLXbDYp/LKlrNacvC5P9tur9NHnzplpxqan
xAVPtw6YuRlzSDi2aDmdWozmMudd1nTUzOiTgiVxmIE5Z8zLlFzrESW7nuzsEzEGy87cN33u2Bfb
7h0DXA==
-----END CERTIFICATE REQUEST-----
""";
var keyAndReqDataKc = new KeyAndRequestDataBuilder()
.SetReqID(newReqIdKC.ToString())
.SetRequest(reqDataKc)
// Při odesílání na CA je potřeba odeslat specifikovat informace o tom jak má výsledné spárování v balíčku Twins vypadat. Je potřeba vždy specifikovat informace o obou certifikátech a jejich roli:
// Žádost o kvalifikovaný certifikát je vždy master, dále uvedeme typ kvalifikovaného certifikátu a ID žádosti o kvalifikovaný certifikát
// Žádost o komerční certifikát je vždy slave, dále uvedeme typ komerčního certifikátu a ID žádosti o komerční certifikát
.SetReqIDInterconnection(newReqIdQc, "master", _certTypeQc)
.SetReqIDInterconnection(newReqIdKC, "slave", _certTypeKC)
.SetCardNumber("9203070100044401")
.Build();
var certPropsKc = new PutReqCertPropsBuilder()
.SetCertChallengePassword("xxxx")
.SetCertType(_certTypeKC)
.SetMpsvik(false)
.SetCertSend(CA.PutReq.PutReqCertPropsSendCert.zip)
.Build();
var billingData = new BillingDataBuilder()
.SetPaymentType(RAConnection.CA.PutReq.BillingDataPaymentType.invoice)
.SetPayParentId(_payParentId)
.Build();
// POZOR - data vložené zde v userdata musí souhlasit s daty z předmětu žádosti, jinak dojde k
// zamítnutí vydání certifikátu
var address = new AddressBuilder()
.SetCity("Zlín")
.SetCountry("CZ")
.SetStreetNumber("159")
.SetStret("Dlouhá")
.SetZipCode("76000")
.Build();
var userData = new PutReqUserDataBuilder()
.SetAddress(address)
.SetBirthNumber("701214101")
.SetDocument("idc", "636363663", "CZ")
.SetLanguage("cs")
.SetName("Jan")
.SetSex("M")
.SetSurname("Novák")
.SetPhoneNumber("+420654987321")
.SetEmail("manak@ica.cz") // Zadejte svou emailovou adresu, měl by vám do ní dojít vydaný certifikát
.Build();
var putReq = new PutReqReqBuilder()
.SetKeyAndRequestData(keyAndReqDataKc)
.SetCertProps(certPropsKc)
.SetBillingData(billingData)
.SetUserData(userData)
.Build();
await _sicaConnector.PutReqAsync(putReq);
// 7 - odeslání master žádosti na kvalifikovanou CA
// údaje o žadateli (userData) a údaje pro účtování (billingData) jsou stejné jako u slave žádosti
var reqDataQc = // Vložit vlastní vygenerovanou žádost o kvalifikovaný certifikát z balíčku Twins
"""
-----BEGIN CERTIFICATE REQUEST-----
MIIDTTCCAjUCAQAwQTETMBEGA1UEAwwKSmFuIE5vdsOhazEMMAoGA1UEKgwDSmFuMQ8wDQYDVQQE
DAZOb3bDoWsxCzAJBgNVBAYTAkNaMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtPn8
OsO9p0dW1sLR5Jw2+YkMNLkXeaNiZzbLDBcvsfzy18uBIyd0GHfOiSmwTNkMCgVN3OwRizZgizsO
XGmxd4m/lSQSgmIma8RoKenQx/7UaD4CTyQeKwQLftPVdY5FSBjibuLyFDfmFvip7GFFs2I914L3
kN2QOkhwFDZdSsZTX+RcBqJ5Ut1EsAJqCnbegYvlmSNFXOVaxiWEc0oqIyRUBwVCaEFIuyj+8azf
pB62R2xZI7oq9kg8cpzix4eJPHv6/5Va1Rc3L8WhZbtw4yGLdlO5xShO6gYR1Wr/uIO1kKoE6ZGz
qkO3GLBJIfe8ldI8Wd1BD+3UAH4wkNxZDQIDAQABoIHGME0GCSqGSIb3DQEJDjFAMD4wFwYDVR0R
BBAwDoEMbWFuYWtAaWNhLmN6MA4GA1UdDwEB/wQEAwIGwDATBgNVHSUEDDAKBggrBgEFBQcDBDB1
BgorBgEEAYG4SAQKMWcwZQIBAQICKgMMFUlDQSBTdGFyY29zIDMuNyBlU2lnbgIBAgQQEAEAAAAA
AQOSAwcBAAREAQQwcazqLgYnAdtRszoHWez+tcF3OGKbirlaRCkbHTDq6BCPWdmRVcM/SDBrZfBu
6qFAMA0GCSqGSIb3DQEBCwUAA4IBAQCN9LWR8/rPFYEnlLLCosV4Y6q8bYLFgOtO7FHfkptHV6dK
6GSBkynD37jPHfLQz1eCYrPmiR+lCtwHkAi7L6qukg8lRa6MiYiKlH/lWb1wFvGgTMO0prNf2Z2/
IerY4vF4LE/dckaYOp+5OMpnFVlH/8HCHDKsitzHGwkQDOIecS/lUQPILE7lKvhZH6h7aUcMG5Dq
GkwVvQ3+7gr02nSpjhbyGsSICgOpmgbwJuwLeE1k5tireqDq4DnF+v42EfJ8QE/LrfuGJMEfjq5e
AvaX9uv+92lPlN2RdI7D+sEDx6auplZXTMcgOVWG8h9IDNazkMfB4AjT1Lzp8Y6DhgUc
-----END CERTIFICATE REQUEST-----
""";
var keyAndReqDataQc = new KeyAndRequestDataBuilder()
.SetReqID(newReqIdQc.ToString())
.SetRequest(reqDataQc)
// Při odesílání na CA je potřeba odeslat specifikovat informace o tom jak má výsledné spárování v balíčku Twins vypadat. Je potřeba vždy specifikovat informace o obou certifikátech a jejich roli:
// Žádost o kvalifikovaný certifikát je vždy master, dále uvedeme typ kvalifikovaného certifikátu a ID žádosti o kvalifikovaný certifikát
// Žádost o komerční certifikát je vždy slave, dále uvedeme typ komerčního certifikátu a ID žádosti o komerční certifikát
.SetReqIDInterconnection(newReqIdQc, "master", _certTypeQc)
.SetReqIDInterconnection(newReqIdKC, "slave", _certTypeKC)
.SetCardNumber("9203070100044401")
.Build();
var certPropsQc = new PutReqCertPropsBuilder()
.SetCertChallengePassword("xxxx")
.SetCertType(_certTypeQc)
.SetCertSend(CA.PutReq.PutReqCertPropsSendCert.zip)
.SetMpsvik(false)
.Build();
var putReqQc = new PutReqReqBuilder()
.SetKeyAndRequestData(keyAndReqDataQc)
.SetCertProps(certPropsQc)
.SetBillingData(billingData)
.SetUserData(userData)
.Build();
await _qicaConnector.PutReqAsync(putReqQc);
// Procesně je jedno jestli prvně odešlete žádost o kvalifikovaný certifikát nebo komerční certifikát. Když se prvně odešle žádost o komerční, celkové zpracování obou žádostí bude rychlejší,
// protože v situaci co se kvalifikovaná CA bude dotazovat na komerční CA ohledně existence párové žádosti, tak tam žádost bude již evidována a zahájí se zpracování ihned i na
// kvalifikované CA
// Pokračovat test metodou IssueCertPaperless_02_WaitForCert, kde proběhne čekání na certifikát
_log.LogInformation("IssueCertPaperless_01_SendReq SUCCESS");
}
catch (Exception ex)
{
_log.LogError(ex, "IssueCertPaperless_01_SendReq FAILED!!!");
throw;
}
}
[TestMethod]
public async Task IssueCertPaperless_02_WaitForCert()
{
try
{
_log.LogInformation("IssueCertPaperless_02_WaitForCert START");
var reqIdKc = File.ReadAllText("newReqIdKc.txt");
// 8 - Získání vydaného komerčního certifikátu z balíčku Twins ze systému CA
var getCertReqKc = new GetCertReqBodyBuilder()
.SetReqId(reqIdKc)
.Build();
GetCertRespBody respKc = null;
do
{
respKc = await _sicaConnector.GetCertificateAsync(getCertReqKc);
}
while (respKc is not null and { ReqInfo: not null and { State: CaConnector.GETCERT_STATE_INPROCESS } });
// 9 - Získání vydaného kvalifikovaného certifikátu z balíčku Twins ze systému CA
var reqIdQc = File.ReadAllText("newReqIdQc.txt");
var getCertReqQc = new GetCertReqBodyBuilder()
.SetReqId(reqIdQc)
.Build();
GetCertRespBody respQc = null;
do
{
respQc = await _qicaConnector.GetCertificateAsync(getCertReqQc);
}
while (respQc is not null and { ReqInfo: not null and { State: CaConnector.GETCERT_STATE_INPROCESS } });
// Pokračovat test metodou IssueCertpaperless_03_SignAndSave
_log.LogInformation("IssueCertPaperless_02_WaitForCert SUCCESS");
if (respKc.ReqInfo.State == CaConnector.GETCERT_STATE_CERTISSUED)
File.WriteAllText("issuedCertKc.cer", respKc.Certificate.Pem);
if (respQc.ReqInfo.State == CaConnector.GETCERT_STATE_CERTISSUED)
File.WriteAllText("issuedCertQc.cer", respQc.Certificate.Pem);
}
catch (Exception ex)
{
_log.LogError(ex, "IssueCertPaperless_02_WaitForCert FAILED!!!");
throw;
}
}
[TestMethod]
public async Task IssueCertPaperless_03_SignAndSave()
{
try
{
_log.LogInformation("IssueCertPaperless_03_SignAndSave START");
// 10 - Získání komerčního certifikátu z balíčku Twins ze systému CA
var reqIdKc = File.ReadAllText("newReqIdKc.txt");
var getCertReqKc = new GetCertReqBodyBuilder()
.SetReqId(reqIdKc)
.Build();
var getCertRespKc = await _sicaConnector.GetCertificateAsync(getCertReqKc);
// 11 - Získání kvalifikovaného certifikátu z balíčku Twins ze systému CA
var reqIdQc = File.ReadAllText("newReqIdQc.txt");
var getCertReqQc = new GetCertReqBodyBuilder()
.SetReqId(reqIdQc)
.Build();
var getCertRespQc = await _qicaConnector.GetCertificateAsync(getCertReqQc);
// 12 - získání smlouvy o vydání certifikátu
var issuedCertQc = X509Certificate2.CreateFromPem(getCertRespQc.Certificate.Pem);
var issuedCertKc = X509Certificate2.CreateFromPem(getCertRespKc.Certificate.Pem);
var dn = new GetProtocolDictionaryBuilder() // DN certifikátu je typicky stejné pro oba certifikáty
.AddItem("2.5.4.3", "Jan Novák")
.AddItem("2.5.4.4", "Novák")
.AddItem("2.5.4.5", "IDCCZ-202080120")
.AddItem("2.5.4.5", "PASCZ-123456478")
.AddItem("2.5.4.6", "CZ")
.AddItem("2.5.4.42", "Jan")
.Build();
// Vydavatelé se již liší (kvalifikovaný x komerční CA)
var issuerDnQc = new GetProtocolDictionaryBuilder() // položky načítat z IssuerName nového kvalifikovaného certifikátu
.AddItem("2.5.4.3", "I.CA Test Qualified CA/RSA 05/2022")
.AddItem("2.5.4.6", "CZ")
.AddItem("2.5.4.10", "První certifikační autorita, a.s.")
.AddItem("2.5.4.5", "NTRCZ-26439395")
.AddItem("2.5.4.11", "Vývoj")
.AddItem("2.5.4.11", "Test")
.Build();
var issuerDnKc = new GetProtocolDictionaryBuilder() // položky načítat z Issuer Name nového komerčního certifikátu
.AddItem("2.5.4.3", "I.CA Test Public CA/RSA 05/2022")
.AddItem("2.5.4.6", "CZ")
.AddItem("2.5.4.10", "První certifikační autorita, a.s.")
.AddItem("2.5.4.5", "NTRCZ-26439395")
.AddItem("2.5.4.11", "Vývoj")
.AddItem("2.5.4.11", "Test")
.Build();
var protocolData = new GetProtocolBodyDataBuilder()
// Základní společné údaje
.SetLocality("Zlín")
.SetRaCode(_codeRA)
.SetRaOperator("OPRA Jakub Maňák") // CN operátorského certifikátu
.SetIdentification("700101123")
.SetAddress("Dlouhá 159, 76000 Zlín")
.SetName("Jan")
.SetSurname("Novák")
.SetSigner("Jan Novák")
.SetFirmName("Firma, s.r.o.")
// Údaje pro QC certifikát z balíčku Twins
.SetCertDateTimeFrom(issuedCertQc.NotBefore.ToString("dd.MM.yyyy HH:mm:ss"))
.SetCertDateTimeTo(issuedCertQc.NotAfter.ToString("dd.MM.yyyy HH:mm:ss"))
.SetDate(DateTime.Now.ToString("dd.MM.yyyy"))
.SetDateAndTime(DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss"))
.SetDn(dn)
.SetSerialNumber(issuedCertQc.SerialNumber)
.SetDnIssuer(issuerDnQc)
.SetAlgorithm("RSA") // zadat podle algoritmu klíčového páru
// Údaje pro KC certifikát z balíčku Twins
.SetAlgorithm2("RSA")
.SetCertDateTimeFrom2(issuedCertKc.NotBefore.ToString("dd.MM.yyyy HH:mm:ss"))
.SetCertDateTimeTo2(issuedCertKc.NotAfter.ToString("dd.MM.yyyy HH:mm:ss"))
.SetDn2(dn)
.SetDnIssuer2(issuerDnKc)
.SetSerialNumber2(issuedCertKc.SerialNumber)
.SetCertType2(_certTypeKC)
.Build();
var getProtocolBody = new GetProtocolBodyBuilder()
.SetPayParentId(_payParentId)
.SetLanguage("cs")
.SetBodyData(protocolData)
.SetCertType(_certTypeQc) // Typ QC certifikátu z balíčku Twins je uveden zde
.SetTemplate(BICA.GetProtocol.TemplateTypes.AGREEMENT)
.Build();
var getProtocolReq = new GetProtocolReqBuilder()
.SetProtocolRequest(getProtocolBody)
.Build();
var protocolResp = await _bicaConnector.GetProtocolAsync(getProtocolReq);
if (protocolResp is null or { Protocol: null or { Length: 0 } })
Assert.Fail("No Agreement returned returned");
// Zde v procesu místo mého uložení proveďte nad smlouvou PAdES podpis operátorským QC certifikátem a nově vydaným QC certifikátem z balíčku Twins
File.WriteAllBytes("agreement.pdf", Convert.FromBase64String(protocolResp.Protocol));
// 13 - Uložení smlouvy na úložiště dokumentů STORAGE
var issuedCertDecSN = TestUtils.HexSnToDec(issuedCertQc.SerialNumber);
var issuedCertAkid = issuedCertQc.GetAkid();
// Smlouvu v adresáři TestData podepište svým OPRA QC certem a vydaným certem např. v Adobe
var pdfAgreementData = File.ReadAllBytes(@"..\..\..\TestData\Agreement_Twins_signed.pdf");
var agreementBase64 = Convert.ToBase64String(pdfAgreementData);
var putAgreementBody = new PutCertAgreementReqBuilder()
.SetAgreement(agreementBase64, Storage.PutCertificateRequest.StorageFileFormats.pdf)
.SetApplicantCertificate(issuedCertDecSN, issuedCertAkid)
.SetCertType(_certTypeQc)
.SetIssuedCertificate(issuedCertDecSN, issuedCertAkid)
// Opět údaje pro QC opra certifikát, kterým se podepsal protokol
.SetOperatorCertificate("10098892", "16a5f56ceee98b5b95f7e0a3d01849ecf740ba9d")
.SetReqId(reqIdQc)
.Build();
await _storageConnector.PutCertificateAgreementAsync(putAgreementBody);
_log.LogInformation("IssueCertPaperless_03_SignAndSave SUCCESS");
}
catch (Exception ex)
{
_log.LogError(ex, "IssueCertPaperless_03_SignAndSave FAILED!!!");
throw;
}
}
}