PKI Signering
Her finner du dokumentasjon på hva en IPS signering er og fungerer, hvordan du bygger opp en signerings forespørselen og tolker responsen. Du finner også informasjon om de forskjellige signeringsformatene som er støttet, hvordan dette brukes og hvordan man trygt kan overføre dokumentet til klientsiden.
Merk at eksempelkodene i denne siden er kun ment som illustrasjonseksempeler på kjernemekanismene, og bør "robustifieres"/justeres med feilhåndtering og/eller andre nødvendige tilpasninger før en ev. produksjonssetting.
Hva er en IPS signering?
En signering gjennom IPS gir en sluttbruker mulighet for å se på og signere et dokument med sin PKI. Dokumentet tilgjengeliggjøres på brukerstedets server, og lastes ned til klienten. På klienten kan sluttbrukeren se på dokumentet gjennom sin installerte "viewer" for det aktuelle dokumentformatet før det signeres. Når dokumentet er signert, vil IPS verifisere signaturen, og returnere signatur og sertifikat tilbake til brukerstedet. På brukerstedssiden vil brukerstedet kunne sette sammen den angitte SDO typen basert på disse elementene, og verifisere signaturen/SDO'en om ønskelig. Signaturformatene støttes gjennom en SignatureProvider plugin arkitektur. Etter hvert som det tilkommer støtte for flere signaturformater, kan disse lastes ned fra disse sidene. Man kan også implementere egne plugins hvis ønskelig, men kravet til input data til eventuelle egenutviklede plugins må samsvare med en av de eksisterende SignatureProvider plugin'ene.
Hvordan er prinsippene ift What-you-see-is-what-you-sign implementert i IPS ?
For å kunne sannsynliggjøre at det du ser er det du signerer (WYSIWYS-prinsippet), er det viktig å ha en så nære knyttning som mulig mellom "se-på prosessen" og signeringsprosessen. Helst bør dette skje i en egen ekstern "signerings-terminal" som er lukket og beskyttet fra PC'en ellers. Allikevel må man ha tilitt til denne signerings-terminalen, og det får man gjerne gjennom dokumentasjon, sertifiseringer og andre bekreftelser fra anerkjente leverandører.
For å kunne tilby en signeringsløsning på Internet uten en slik "signerings-terminal", er det viktig at de som bruker signeringsløsningen og de som tilbyr signering gjennom en slik løsning, kjenner til hvordan man i størst mulig grad sannsynliggjør at det du faktisk ser er det du faktisk signerer. Derfor er det viktig at denne informasjonen er tilgjengelig, og at man da selv kan ta stilling til om man syntes disse mekanismene sannsynliggjør dette i tilstrekkelig grad.
I IPS er dette sannsynliggjort ved at dokumentet lastes ned på klienten, og inn i samme prosess som skal styre den faktiske signeringen mot Smartkortet. Dataene fra samme prosess tilgjengeliggjøres for visning, sammen med mime-typen brukerstedet selv har angitt for innholdet (f.eks. "application/pdf"). På denne måten startes så det aktuelle programmet sluttbrukeren har installert for den gitte mime-typen (f.eks. Adobe Reader), og dokumentet vises i dette programmet. Når sluttbrukeren har sett på dokumentet/filen som skal signeres, taster brukeren PIN-kode, og korrekt preprosessert DTBS (Data-To-Be-Signed) i forhold til angitt signaturformat over de samme dataene signeres.
SignatureProvider plugin
Signaturformatsøttten i integrasjonsbibliotekene er implementert gjennom en såkalt SignatureProvider plugin arkitektur. En SignatureProvider plugin tilbyr encoding og verifisering av sine relevante formater og delstrukturer. F.eks. vil BPESIG0101 plugin, som støtter basic PKCS#7 SDO'er, tilby støtte for encoding av alle relevante delstrukturer som brukes i en basic PKCS#7 signering. Det samme gjelder for de andre signaturformatene.
SignatureProvider kode pattern for SDO generering vil være slik:
// get the correct provider instance SignatureProvider sp = SignatureProvider.getInstance([format]); sp.initializeForEncode([encoding mode]); // add all required parameters sp.setParam([dataparam name-1],[value-1]); .. sp.setParam([dataparam name-n],[value-n]); // encode the given structure byte[] encodedData = sp.encode();
SignatureProvider kode pattern for SDO verifisering vil være slik:
// get the correct provider instance SignatureProvider sp = SignatureProvider.getInstance([format]); sp.initializeForVerify([verification mode]); // add all required parameters sp.setParam([dataparam name-1],[value-1]); .. sp.setParam([dataparam name-n],[value-n]); // verify the given structure boolean verifiedOk = sp.verify();
Under følger en global liste over alle dataparameter typer.
Følgende dataparametere er felles for alle BPESIG SignatureProvider plugins
Parameter | Type | Beskrivelse |
---|---|---|
DTBS | byte[] | Data-To-Be-Signed - dette er de faktiske binære dataene som signeres etter all nødvendig preprosessering, uten padding. |
CONTENT | byte[] | Eksakt binær representasjon av dokumentet/filen som skal signeres. |
CONTENT_SHA1_DIGEST | byte[] | Hash av CONTENT i henhold til spesifisert hash-algoritme |
CMS_SIGNED_ATTRIBUTES | byte[] | CMS SignedAttributes. Den binære representasjonen av en PKCS#7 v1.5 SignedAttributes som skal brukes ved signering/verifisering. |
CLAIMED_SIGNING_TIME | Date (Java)/ DateTime (.NET) | Datoobjekt som representerer brukerstedets oppfatning av tidspunkt for signering. |
CERTIFICATE | byte[] | Binær representasjon av X509 Sertifikatet som skal brukes ved signering. |
SIGNATURE | byte[] | Binør representasjon av signaturen. For en 1024 bits RSA signering vil denne eksempelvis være 128 bytes lang. |
CMS_SIGNED_DATA_OBJECT | byte[] | CMS SignedDataObject. Den binære representasjon av en PKCS#7 v1.5 SignedDataObject som skal brukes ved signering/verifisering. |
SEID_INCLUDE_SIGNEDOBJECT | String ("1"/"0") | 1 hvis CONTENT skal være med i SEID_SDO'en, 0 hvis ikke |
SEID_INCLUDE_HASHEDDATA | String ("1"/"0") | 1 hvis HashedData elementet skal være med i SEID_SDO'en, 0 hvis ikke |
PDF_SIGNED | ||
SIGNATURE_CONTEXT | cnl.wips.remote.tools.crypto.SignatureContext | Tilstandsholder objekt gjennom de forskjellige fasene av encoding. Et tomt SignatureContext objekt opprettes gjennom å kalle SignatureProvider.createSignatureContext() på den aktuelle SignatureProvideren |
VISIBLE_SIGNATURE_PAGE | String | Side nummer som den synlige signaturen skal ligge på |
VISIBLE_SIGNATURE_X | String | Den horisontale posisjonen til den synlige signaturen |
VISIBLE_SIGNATURE_Y | String | Den vertikale posisjonen til den synlige signaturen |
VISIBLE_SIGNATURE_WIDTH | String | Bredden til den synlige signaturen |
VISIBLE_SIGNATURE_HEIGHT | String | Høyden til den synlige signaturen |
REASON | String | Tekstlig beskrivelse av grunn/årsak til at signaturen lages. |
SIGNED_LOCATION | String | Tekstlig beskrivelse av signeringssted. |
Under følger en global liste over alle encoding modes
Følgende encoding mode identifikatorere er felles for alle BPESIG SignatureProvider plugins
Parameter | Beskrivelse |
---|---|
DTBS | Data-To-Be-Signed - genererer de faktiske binære dataene som signeres etter all nødvendig preprosessering, uten padding. |
CMS_SIGNED_ATTRIBUTES | CMS SignedAttributes. Genererer den binære represenatsjonen av en PKCS#7 v1.5 SignedAttributes som skal brukes ved signering. |
CMS_SIGNED_DATA_OBJECT | CMS SignedDataObject. Genererer den binære represenatsjonen av en PKCS#7 v1.5 SignedDataObject som skal brukes ved signering. |
SEID_SDO_BASIC | Genererer den binære representasjonen av en SEID_SDO_Basic XML struktur. |
PDF_SIGNED | Genererer den signerte PDF'en. |
Under følger en global liste over alle verification modes
Følgende verification mode identifikatorere er felles for alle BPESIG SignatureProvider plugins
Parameter | Beskrivelse |
---|---|
CMS_SIGNED_DATA_OBJECT_INTEGRITY | Verifiserer signatur objektets integritet. Dvs at strukturen i seg selv blir verifisert; signatur mot innhold og innhold i signed attributes, integretet og levetid på sertifikat, men ingen revokeringssjekk. |
SEID_SDO_BASIC_CMS_INTEGRITY | Verifiserer det interne CMS signatur objektets integritet i SEID_SDO'en. Dvs at den interne CMS strukturen i seg selv blir verifisert; signatur mot innhold og innhold i signed attributes, integretet og levetid på sertifikat, men ingen revokeringssjekk. |
PDF_SIGNED | Verifiserer det interne PDF dokumentet opp mot signaturen, integretet og levetid på sertifikat, men ingen revokeringssjekk eller sjekk mot CA sertifikat. |
Signaturformater
Følgende signatur formater støttes av IPS:
Verdi | Fra versjon | Beskrivelse |
---|---|---|
BPESIG0101 | 1.0.1 | CMS basert signatur basert på PKCS#7, v1.5. Gir mulighet for å inkludere claimed signing-time i signatur grunnlaget (signed-attributes) |
BPESIG0201 | 1.0.1 | CMS basert signatur basert på ETSI 101 733 v1.7.3. Dataene signeres og formateres iht CAdES-BES formatert signaturer. Gir mulighet for å inkludere claimed signing-time i signatur grunnlaget. |
BPESIG0301 | 1.0.1 | CMS og XML basert signatur. Dataene signeres og formateres iht SEID SDO Basic (Type 1) profilen. |
BPESIG0401 | 1.0.3 | Adobe PDF signatur, usynlig signatur. |
BPESIG0402 | 1.0.3 | Adobe PDF signatur, visuelt synlig signatur i dokumentet |
Du finner mer informasjon om de ulike signaturformatene lenger ned.
Dokumentformater
IPS har ikke noe teknisk forhold til formatet på dokumentet utover mime-typen som anngis for det for det aktuelle formatet av brukerstedet selv. Dette betyr at man i prinsippet står fritt til å signere alle type dokumenter/filer, fra PDF'er og Word dokumenter til .exe filer og .zip filer. "Viewer" prosessen blir da håndtert slik den aktuelle applikasjonen for den gitte mime-typen håndterer det. Av sikkerhetsmessige årsaker har Buypass begrenset IPS til å kun signere PDF (application/pdf) og rene tekstfiler (text/plain). Hvis det er behov for å kunne signere andre type formater, kontakt Buypass for videre diskusjon.
Nedlasting av dokumenter til sluttbruker
Som tidligere nevnt, lastes det aktuelle dokumentet over til kundens PC i forkant av selve signeringen. Det finnes det flere varianter å tilgjengeliggjøre dokumentet på. Dokumentet må på en eller annen måte tilgjengeliggjøres for signeringsappleten, slik at denne kan lastes ned for visning- og signering. Det finnes følgende alternativer for tilgjengeliggjøring:
- Tilgjengeliggjøre dokumentet på åpen, ikke-gjettbar/uforutsigbar, URL
- Tilgjengeliggjøre dokumentet på en sesjonsbasert URL. Sesjonscookien sendes da med i forespørselen til IPS
- Tilgjengeliggjøre en kryptert (3DES/168bit) utgave dokumentet på en åpen eller sesjonsbasert URL. Dekrypteringsnøkkelen (og ev. sesjonscookien) sendes da med i forespørselen til IPS. WIRI tilbyr støttefunksjonalitet for kryptering, nøkkelgenering og base64 encoding av dokumenter som tilgjengeliggjøres på denne måten.
- Sende dokumentet med i forespørselen til IPS. Dette anbefales kun for små dokumenter. Total maks størrelse på en forespørsel til IPS er 256kb, men det anbefales uansett ikke å sende større dokumenter enn 3-5kb via IPS, da dokumentet må lastes opp (x1) og ned (x2) 3 ganger før det er "fremme" hos sluttbrukeren.
Hvis dokumentet tilgjengeliggjøres på Internet, bør dokumentet tilgjengeliggjøres på en SSL adresse. Alternativt krypteres som i alternativ 3), og tilgjengeliggjøres over http.
SignaturFormat BPESIG0101 - PKCS#7 v1.5 SDO
BPESIG0101 som signaturformat er basert på PKCS#7 v1.5 / RFC 2315. Utover det som er påkrevd, inkluderes også såkalt Claimed Signing Time som i dette tilfellet er brukerstedets oppfatning av signeringstidspunktet.
Tabellen under viser hvilke felter som er påkrevd for de forskjellige relevante operasjonene for BPESIG0101 SignatureProvider. Se kapittelet om SignatureProvider for detaljert beskrivelse av hva de forskjellige parameterne betyr.
Modus | Encoding/Verification name | Påkrevde Felter | Overordnet beskrivelse |
---|---|---|---|
Encoding | CMS_SIGNED_DATA_OBJECT | CONTENT CLAIMED_SIGNING_TIME CERTIFICATE SIGNATURE | Genrerer hele PKCS#7 SDO'en |
Verifisering | CMS_SIGNED_DATA_OBJECT_INTEGRITY | CMS_SIGNED_DATA_OBJECT | Verifiserer integriteten i PKCS#7 SDO'en (ingen revokeringssjekk) |
Under er et kodeeksempel på sammensetting av en PKCS#7. Eksempelet er basert på at man har fått tilbake signatur og sertifikat etter signering, og at man har det signerte dokumentet og signeringstidspunkt tilgjengelig.
byte[] document = // the document byte[] signature = // the signature byte[] certificate = // the encoded certificate Date signingTime = // the given signingTime // get the BPESIG0101 signature provider SignatureProvider sp = SignatureProvider.getInstance("BPESIG0101"); // initialize for encoding of the PKCS#7 signature SDO sp.initializeForEncode("CMS_SIGNED_DATA_OBJECT"); // add required parameters sp.setParam("CONTENT", document); // the excact binary representation sp.setParam("CLAIMED_SIGNING_TIME", signingTime); // same as the SigningTime sent to IPS sp.setParam("CERTIFICATE", certificate); // certificate from IPS sp.setParam("SIGNATURE", signature); // signature from IPS // get the encoded PKCS#7 signature SDO byte[] pkcs7 = sp.encode(); Under er et kodeeksempel på verifisering av et signert dokument (verifisering av PKCS#7'en). byte[] pkcs7 = // the signature, or from previous sample // get the BPESIG0101 signature provider SignatureProvider sp = SignatureProvider.getInstance("BPESIG0101"); // initialize for signature verification of the PKCS#7 signature SDO sp.initializeForVerify("CMS_SIGNED_DATA_OBJECT_INTEGRITY"); // add required parameters (the signature) sp.setParam("CMS_SIGNED_DATA_OBJECT", pkcs7); // verify SDO integrity boolean verifiedOk = sp.verify();
SignaturFormat BPESIG0201 - ETSI TS 101 733 CAdES-BES SDO
BPESIG0201 som signaturformat er basert på PKCS#7 v1.5 / RFC 2315, men inkluderer i tillegg påkrevde elementer for å være konform med ETSI TS 101 733 CAdES-BES. Tilleggs elementene er hentet fra ESS RFC263 (Enhanced Security Servies), og består av signing-certificate
elementet eller other-signing-certificate
. IPS inkluderer signing-certificate
elementet, som kort fortalt består av en SHA-1 Hash over signerers sertifikat. Dette inkluderes i signaturgrunnlaget for å sikre en entydig knytning mellom signatur og et faktiske sertifikatet som ble brukt. Utover det som er påkrevd, inkluderes også Claimed Signing Time som i dette tilfellet er brukerstedets oppfatning av signeringstidspunktet.
Tabellen under viser hvilke felter som er påkrevd for de forskjellige relevante operasjonene for BPESIG0201 SignatureProvider. Se kapittelet om SignatureProvider for detaljert beskrivelse av hva de forskjellige parameterne betyr.
Modus | Encoding/Verification name | Påkrevde Felter | Overordnet beskrivelse |
---|---|---|---|
Encoding | CMS_SIGNED_DATA_OBJECT | CONTENT CLAIMED_SIGNING_TIME CERTIFICATE SIGNATURE | Genrerer hele CAdES-BES SDO'en |
Verifisering | CMS_SIGNED_DATA_OBJECT_INTEGRITY | CMS_SIGNED_DATA_OBJECT | Verifiserer integriteten i CAdES-BES SDO'en (ingen revokeringssjekk) |
Under er et kodeeksempel på sammensetting av en CAdES-BES SDO. Eksempelet er basert på at man har fått tilbake signatur og sertifikat etter signering, og at man har det signerte dokumentet og signeringstidspunkt tilgjengelig.
byte[] document = // the document byte[] signature = // the signature byte[] certificate = // the encoded certificate Date signingTime = // the given signingTime // get the BPESIG0201 signature provider SignatureProvider sp = SignatureProvider.getInstance("BPESIG0201"); // initialize for encoding of the CAdES-BES signature SDO sp.initializeForEncode("CMS_SIGNED_DATA_OBJECT"); // add required parameters sp.setParam("CONTENT", document); // the excact binary representation sp.setParam("CLAIMED_SIGNING_TIME", signingTime); // same as the SigningTime sent to IPS sp.setParam("CERTIFICATE", certificate); // certificate from IPS sp.setParam("SIGNATURE", signature); // signature from IPS // get the encoded CAdES-BES SDO byte[] pkcs7 = sp.encode();
Under er et kodeeksempel på verifisering av et signert dokument (verifisering av CAdES-BES SDO'en).
byte[] pkcs7 = // the signature, or from previous sample // get the BPESIG0201 signature provider SignatureProvider sp = SignatureProvider.getInstance("BPESIG0201"); // initialize for signature verification of the CAdES-BES signature SDO sp.initializeForVerify("CMS_SIGNED_DATA_OBJECT_INTEGRITY"); // add required parameters (the signature) sp.setParam("CMS_SIGNED_DATA_OBJECT", pkcs7); // verify SDO integrity boolean verifiedOk = sp.verify();
SignaturFormat BPESIG0301 - SEID-SDO-Basic
BPESIG0301 som signaturformat er basert på SEID-SDO-Basic profilen, som igjen er basert på PKCS#7 v1.5 / RFC 2315, men inkluderer i tillegg påkrevde elementer for å være konform med ETSI TS 101 733 CAdES-BES - som er påkrevd i SEID standarden. Tilleggs elementene er hentet fra ESS RFC263 (Enhanced Security Servies), og består av signing-certificate
elementet eller other-signing-certificate
. IPS inkluderer signing-certificate
elementet, som kort fortalt består av en SHA-1 Hash over signerers sertifikat. Dette inkluderes i signaturgrunnlaget for å sikre en entydig knytning mellom signatur og et faktiske sertifikatet som ble brukt. Utover det som er påkrevd, inkluderes også Claimed Signing Time som i dette tilfellet er brukerstedets oppfatning av signeringstidspunktet.
SEID spesifiserer flere sett med profiler. BPESIG0301 er i.h.t. SEID-SDO-Basic profilen.
Tabellen under viser hvilke felter som er påkrevd for de forskjellige relevante operasjonene for BPESIG0301 SignatureProvider. Se kapittelet om SignatureProvider for detaljert beskrivelse av hva de forskjellige parameterne betyr.
Modus | Encoding/Verification name | Påkrevde Felter | Overordnet beskrivelse |
---|---|---|---|
Encoding | SEID_SDO_BASIC | CONTENT CLAIMED_SIGNING_TIME CERTIFICATE SIGNATURE MIME_TYPE MERCHANT_DESC CHARACTER_ENCODING (SEID_INCLUDE_HASHEDDATA) (SEID_INCLUDE_SIGNEDOBJECT) | Genrerer hele SEID SDO'en (XML) |
Verifisering | SEID_SDO_BASIC_CMS_INTEGRITY | SEID_SDO_BASIC | Verifiserer integriteten i CMS delen av SDO'en (ingen revokeringssjekk) |
Under er et kodeeksempel på sammensetting av en SEID SDO. Eksempelet er basert på at man har fått tilbake signatur og sertifikat etter signering, og at man har det signerte dokumentet og signeringstidspunkt tilgjengelig.
byte[] document = // the document byte[] signature = // the signature byte[] certificate = // the encoded certificate Date signingTime = // the given signingTime // get the BPESIG0301 signature provider SignatureProvider sp = SignatureProvider.getInstance("BPESIG0301"); // initialize for encoding of the SEID SDO sp.initializeForEncode("SEID_SDO_BASIC"); // add required parameters sp.setParam("CONTENT", document); // the excact binary representation sp.setParam("CLAIMED_SIGNING_TIME", signingTime); // same as the SigningTime sent to IPS sp.setParam("CERTIFICATE", certificate); // certificate from IPS sp.setParam("SIGNATURE", signature); // signature from IPS sp.setParam("MIME_TYPE", "application/pdf"); // the content is a PDF document sp.setParam("MERCHANT_DESC", "Same description as shown in the IPS GUI"); sp.setParam("CHARACTER_ENCODING", "UTF-8"); // we want UTF-8 XML encoding sp.setParam("SEID_INCLUDE_HASHEDDATA","1"); // we want to include the HashedData element sp.setParam("SEID_INCLUDE_SIGNEDOBJECT","0"); // we dont want to include the doc // get the encoded SEID SDO byte[] seidSDO = sp.encode(); // seidSDO is the SEID-SDO XML - convert it to a string, for joy String theXML = new String(seidSDO, "UTF-8"); Under er et kodeeksempel på verifisering av et signert dokument (verifisering av CMS delen av SEID SDO'en). byte[] seidSDO = // the signature, or from previous sample // get the BPESIG0301 signature provider SignatureProvider sp = SignatureProvider.getInstance("BPESIG0301"); // initialize for signature verification of the CMS part of the SDO sp.initializeForVerify("SEID_SDO_BASIC_CMS_INTEGRITY"); // add required parameters (the signature/SDO) sp.setParam("SEID_SDO_BASIC", seidSDO); // verify SDO integrity boolean verifiedOk = sp.verify();
SignaturFormat BPESIG0401 - PDF signatur, usynlig signatur
BPESIG0401 som signaturformat er basert på Adobes PDF signeringsformat. Signaturene som er opprettet ved hjelp av BPESIG0401 er ikke synlige i dokumentet ved f.eks. print, men sjekkes/verifiseres gjennom en PDF viewer (som Adobe Reader).
SignaturFormat BPESIG0402 - PDF signatur, synlig signatur
BPESIG0402 som signaturformat er basert på Adobes PDF signeringsformat. Signaturene som er opprettet ved hjelp av BPESIG0402 er synlige i dokumentet ved f.eks. print, og kan sjekkes/verifiseres gjennom en PDF viewer (som Adobe Reader).
Sammensetting av forespørselen
Sammensetting av signeringsforespørselen skjer typisk når en sluttbruker ønsker å signere noe. Ved sammensetting av en signeringsforespørsel, er det flere ting man må ta stilling til:
- Hvordan skal dokumentet tilgjengeliggjøres for sluttbrukeren?
- Påstått signeringstidspunkt
- Signaturformat
- Dokumentformat/MIME-type
- Hvilke returverdier du ønsker om sluttbrukeren
- Hvilket brukergrensesnitt du ønsker å bruke
- Retur URL (ved redirigerte forespørseler)
Pr des-08 er det kun Smartkort med PKI som kan brukes til signering.
Påstått signeringstidspunkt anngis gjennom MerchantSigningTime
elementet.
Brukergrensesnitt kode anngis gjennom RequestAttribute
elementet.
Retur URL anngis i ResponseUrl
elementet.
Returverdier anngis gjennom ResponseAttribute
elementet. Data om brukeren blir returnert gjennom IdToken elementet i responsen.
Støttebiblioteket vil hjelpe deg med de resterende påkrevde elementene.
Under er et JSP eksempel på en komplett sammensatt forespørsel, hvor vi tilgjengeliggjør dokumentet på en sesjonsbasert URL, kryptert. Nøkkelen og sesjonscookien utveksels i forespørselen til IPS, slik at innholdet i praksis kun kan leses av IPS klienten. Vi ønsker å få fødselsnummeret i retur, og vi ønsker også å bruke et "FULLSIZE" brukergrensesnitt, og må derfor anngi dette gjennom RequestAttribute elementet. Dokumentet er et PDF dokument, og vi bruker derfor mime-typen "application/pdf". Eksempelet under spesifiserer et BPESIG0201 signaturformat, som er komform med ETSI 101 733 CAdES-BES signaturer.
byte[] document = buf; // the excact binary representation of the document String sessionId = request.getSession().getId(); String sessionCookie = "JSESSIONID=" + sessionId; // generate a required SHA-1 hash for the document MessageDigest dig = MessageDigest.getInstance("SHA1"); dig.update(document); byte[] hash = dig.digest(); // generate a base64 encoded encryption key // that we're gonna use to encrypt the document String b64EncryptionKey = BxCrypto.generateBase64EncodedKey(); // encrypt the document byte[] encryptedDocument = BxCrypto. encryptDataWithBase64EncodedKey(b64EncryptionKey, document); // make the document available on session, so that the // getcontent.jsp can reach it request.getSession().setAttribute("document", encryptedDocument); request.getSession().setAttribute("document-type", "application/pdf"); // build request data BxElement srd = new BxElement("SignRequestData"); srd.addElement("RequestId", BxCrypto.generateUid()); srd.addElement("ResponseUrl", "http://mysite.com/processsignresponse.do"); // choose fullsize GUI srd.addElement("RequestAttribute", new String[] {"name"}, new String[] {"ips:GUI"}); srd.getElement("RequestAttribute", 0).setValue("WIPSGUI-FULLSIZE"); // add the transfer encryption key srd.addElement("TransferEncryptionKey", new String[] {"Encoding"}, new String[] {"ips:Base64"}); srd.getElement("TransferEncryptionKey", 0). setValue(b64EncryptionKey); // add the session cookie srd.addElement("ContentCookie", sessionCookie); // add the current time String claimedSigningTime = BxElement.getDatTime(); srd.addElement("MerchantSigningTime", claimedSigningTime); // add the signature format, we need compliance with // ETSI 101 733 CAdES-BES signatures srd.addElement("SignatureFormat", "BPESIG0201"); // add the document format/mime-type srd.addElement("ContentMimeType", "application/pdf"); // add the document URL srd.addElement("ContentUri", "http://mysite.com/getcontent.jsp?what=document"); // add the SHA-1 hash over the document srd.addElement("ContentHash", new String[] {"Encoding"}, new String[] {"ips:HexEncoding"}); // If we want to use SHA2, the Algorithm attribute must be added, so use instead: //srd.addElement("ContentHash", // new String[] {"Encoding", "Algorithm"}, // new String[] {"ips:HexEncoding", "ips:SHA256"}); srd.getElement("ContentHash", 0). setValue(StrFormat.hexify(hash)); // add the description srd.addElement("ContentDescription", new String[] {"Encoding"}, new String[] {"ips:Plain"}); srd.getElement("ContentDescription", 0). setValue("Signering av et eksempel dok"); BxRequest req = new BxRequest("SignRequest", srd, true); // get the form data String pse = req.getPSE(); String e = req.getE(); // make request object available on session request.getSession().setAttribute("signreq", req);
Relevante elementer å forholde seg til ifm sammensetting av en signeringsforespørsel er:
- SignRequest
- SignRequestData
- SignResponseData
- ResponseURL
- RequestAttribute
- ResponseAttribute
Tilgjengeliggjøring av dokumentet for sluttbrukeren
Dokumentet må tilgjengeliggjøres for signeringsklienten som nevnt over. Under er et eksempel på hvordan en "getcontent.jsp", som det refereres til i eksempelet over, kan se ut. Eksempelet er en JSP fil, som kjøres på Tomcat (ref work-around for tomcat i eksempelet under). Koden under er kun ment som et eksempel og for å komplettere forståelsen av sammenhengen i de vedlagte eksempelkodene.
getcontent.jsp <% // get content and content type from session, // based on the "what" request parameter byte[] content = (byte[])request.getSession(). getAttribute(request.getParameter("what")); String contentType = (String)request.getSession(). getAttribute(request.getParameter("what") + "-type"); if(content == null){ response.sendError(404, "requested content not found"); return; } // reset header to get around charset bug 24970 for tomact 4.1.x // (http://www.mail-archive.com/tomcat-dev@jakarta.apache.org/msg61011.html) response.reset(); response.setContentType(contentType); response.setContentLength(content.length); response.getOutputStream().write(content); response.getOutputStream().flush(); %>
Redirigering/sending av forespørselen til IPS
Når signeringsforespørselen er satt sammen og klar, må den sendes til IPS. Dette gjøres ved å sende PSE og E parameteren til IPS, sammen med OP (operasjonstype) og M (merchantID) parameterene i en HTML form. HTML form'en returneres tilbake til nettleseren, og sendes automatisk til IPS (v.h.a. "auto-submit"/submit på body-on-load eventen). Under er et eksempel på en side som gjør dette basert på "pse" og "e" variablene fra det første eksempelet over. I eksempelet under er merchantID=32.
<html> <body onload="javascript:document.getElementById('signForm').submit()"> <form id="signForm" action="https://secure.test4.buypass.no/wips/service" method="POST"> <input type="hidden" name="PSE" value="<%=pse%>"> <input type="hidden" name="E" value="<%=e%>"> <input type="hidden" name="M" value="32"> <input type="hidden" name="op" value="BXSIGN"> </form> </body> </html>
Javascript støtte er påkrevd i nettleseren for bruk av IPS.
Mottak og tolking av responsen
Returdataene fra signeringen "kommer tilbake" til brukerstedet på samme måte som de ble sendt til IPS. Det vil si at IPS vil returnere signeringsresponsen tilbake til nettleseren, som vil bli POST'et tilbake til brukerstedet på anngitt adresse (ResponseUrl).
Parameteren som inneholder returverdiene heter PE. Denne leses typisk ved å kalle
String pe = request.getParameter("PE");
i en JSP fil. For å kunne dekryptere denne, må det korresponderende BxRequest objektet være tilgjengelig. I eksempelene over, ble dette lagt på sesjonsobjektet for å kunne brukes til dekryptering av responsen. Her er et eksempel på lesing, dekryptering og parsing:
// parse response data BxResponse res = new BxResponse(request.getParameter("PE")); res.setRequestContext((BxRequest)request.getSession(). getAttribute("signreq")); res.parse();
I koden over har nå BxRequest objektet fra sesjonen blitt tilordnet responsen, og responsen er dekryptert og parset. Neste steg blir å lese ut dataene fra responseobjektene.
// get id response object BxElement signResponseData = res.getElement("SignResponseData"); // get response status String status = signResponseData.getElement("ResponseCode").getValue(); out.println("Status: " + status + ""); if(status.equals("ips:SUCCESS")){ // get the base64 encoded certifcate from response String scert = signResponseData.getElementValue("Certificate"); // get the base64 encoded signature from response String ssign = signResponseData.getElementValue("Signature"); }
Sertifikat og signatur er nå hentet ut å ligger i scert
og ssign
variablene.
Sammensetting og verifisering av signaturobjektene
Under er et eksempel på sammensetning av SDO'en basert på response dataene fra eksempelet over. Etter å ha lest ut response dataene (i eksempelet over), bruker vi sertifikatet, signaturen, dokumentet og signeringstidspunktet til å generere PKCS#7 strukturen. Deretter verifiseres denne.
byte[] content = // the document Date signingTime = // the signing time // ... if(status.equals("ips:SUCCESS")){ // we want to encode a PKCS#7/CAdES-BES signature SignatureProvider ep = SignatureProvider.getInstance("BPESIG0201"); ep.initializeForEncode("CMS_SIGNED_DATA_OBJECT"); // add all required parameters ep.setParam("CONTENT", content); ep.setParam("CLAIMED_SIGNING_TIME", signingTime); ep.setParam("CERTIFICATE", (byte[])Base64Util.decodeBase64(scert)); ep.setParam("SIGNATURE", (byte[])Base64Util.decodeBase64(ssign)); // encode the structure byte[] pkcs7 = ep.encode(); // we also want to verify the pkcs7 signature SignatureProvider vp = SignatureProvider.getInstance("BPESIG0201"); vp.initializeForVerify("CMS_SIGNED_DATA_OBJECT_INTEGRITY"); vp.setParam("CMS_SIGNED_DATA_OBJECT", pkcs7); boolean verifiedOk = vp.verify(); BxElement idTokenData = null; BxElement idToken = signResponseData.getElement("IdToken"); idTokenData = idToken.getElement("IdTokenData"); // dump results out.println("Signed by " + idTokenData.getElement("FirstName"). getValue() + " " + idTokenData.getElement("LastName"). getValue() + ""); out.println("Signature verified OK: " + verifiedOk+ ""); out.println("PKCS7 size: " + pkcs7.length + ""); }