Using BankID Java Server
Application start-up code
Initialising BankID Java Server includes the following:
- Registering a HSM PKCS#11 driver (If using HSM).
- Loading/Registering merchant contexts. This must be done for each merchant that is supposed to use the same instance of BankID J Server.
- Retrieving a "no.bbs.server.implementation.BIDFacade" instance for each merchant. This is the "handle" which exposes the BankID Server API methods to use.
The merchant application needs to perform the following actions.
- Get the BIDFactory instance
- For each merchant to configure call one of the following two methods:
- loadBankIDContext(...) If using a configuration file
- registerBankIDContext(...) If NOT using a configuration file
// Get the BIDFactory instance BIDFactory factory = BIDFactory.getInstance(); // Registering a PCKS#11 driver in BankID Server. The loadPKCS11Adapter // method takes the fully qualified path of the NativeCryptoki.dll(.so) // and the PKCS#11 driver as input. // NativeCryptoki.dll (.so) is the JNI-wrapper module used by BankID // Server. NativeCryptoki loads the input PKCS#11 driver. This PKCS#11 // driver (or so-file) must be the PKCS#11 driver to the HSM that the // merchant keys are stored in. If you are not using HSM's to store your // keys then ignore this line. // This method MUST ONLY be called once. 1 BankID Server process may only // load 1 PKCS#11 driver. This is to avoid conflicts, and means that the // BankID Server can only communicate with HSM's from 1 vendor at a time. factory.loadPKCS11Adapter("/opt/drivers/NativeCryptoki.dll", "/opt/drivers/bp201w32HSM.dll"); try { // Configuring a merchant that has its BankID settings in a property // file merchant.props. The first parameter (value="/opt/merchant/") is // the directory where "merchant" has placed its configuration files. If // this value is null then merchant.props MUST be located in BankID // Server's classpath. factory.loadBankIDContext("/opt/merchant/", "merchant", "merchant_pwd"); // OR // Configuring a merchant passing all the mandatory configuration // parameters through the API. No configuration file is needed when // calling thefollowing method. MerchantConfig mConfig = new MerchantConfig(); mConfig.setGrantedPolicies("2.16.578.1.16.1.9.1,2.16.578.1.16.1.11.2.1"); mConfig.setKeystorePassword("minbank_pwd"); mConfig.setMerchantKeystore("/opt/merchant/merchant.bid"); mConfig.setMerchantName("merchant"); mConfig.setWebAddresses("www.merchant.com,192.168.0.1"); mConfig.setCommTimeout("20000"); // Communication Socket timeout mConfig.setTokenUserPIN("123456"); // Only if merchant is using HSM // the following two params can be added to enable logging //mConfig.setLogPropFileLocation("/opt/log/log4j.props"); //mConfig.setLogAppender("Merchant1Appender"); ContextInfo minBankContextInfo = factory.registerBankIDContext(mConfig); } catch(BIDException be) { int errorCode = be.getErrorCode(); String errorMessage = be.getMessage(); String methodIdentifier = be.getMethodIdentifier(); } // To start using the BankID Server API on behalf of "merchant" the // merchant application has to get a // "no.bbs.server.implementation.BIDFacade" passing the merchant context // key (which is the merchantName "merchant") BIDFacade minFacade = factory.getFacade("merchant");
Authentication and Signing processes
Every BankID use-case, authentication or signing, starts with the merchant will retrieve a helper uri and a clientID, see [IMPLW].
Please see [IMPL] for a full description of the authentication and signing processes.
Authentication process – BankID on Mobile
// BankID authentication. This example builds upon the earlier code excerpts using // "merchant" // step 1: Initialising the mobile phone communication // A user enters the phone number and phone alias on www.merchant.com. try { // collect end-users phone number and alias from the web application String phoneNumber="collected from webSite"; String phoneAlias="collected from webSite"; String merchantReference=myFacade.generateMerchantReference("no_NO"); // show the merchantReferanse to the end-user MobileInfo mobileInfo=new MobileInfo(); mobileInfo.setAction("auth"); mobileInfo.setMerchantReference(merchantReference); // URL must be the same hostname as the merchantConfig webAddresses configuration: mobileInfo.setUrl("https://www.merchant.com/BankID"); //The expected sessionID during callbacks to the web application: mobileInfo.setSid("sessionID"); mobileInfo.setPhoneNumber(phoneNumber); mobileInfo.setPhoneAlias(phoneAlias); // be aware that the following call can cause a hang for up to 3 minutes while the // end-user processes messages on the cell phone.At the same time the web application // must expect callbacks on the specified URL TransactionAndStatus ts=myFacade.requestMobileAction(mobileInfo); } catch(BIDException be) { int errorCode=be.getErrorCode(); String errorMessage=be.getMessage(); String methodIdentifier=be.getMethodIdentifier(); } // step 2: Handle initAuth callback from the mobile infrastructure String operation=request.getParameter("operation"); String sid=request.getParameter("sid"); String encKey=request.getParameter("encKey"); String encData=request.getParameter("encData"); String encAuth=request.getParameter("encAuth"); BIDSessionData sessionData=new BIDSessionData(); try { String responseToClient=myFacade.initTransaction(operation,encKey,encData,encAuth,sid,sessionData); // store the sessionData in local session store for later use } catch(BIDException be){ int errorCode=be.getErrorCode(); String errorMessage=be.getMessage(); String methodIdentifier=be.getMethodIdentifier(); } // step 3: Handle verifyAuth callback from the mobile infrastructure String operation=request.getParameter("operation"); String sid=request.getParameter("sid"); String encKey=request.getParameter("encKey"); String encData=request.getParameter("encData"); String encAuth=request.getParameter("encAuth"); // get the sessionData from local session store try { myFacade.verifyTransactionRequest(operation,encKey,encData,encAuth,sid,sessionData); } catch (BIDException be) { int errorCode=be.getErrorCode(); String errorMessage=be.getMessage(); String methodIdentifier=be.getMethodIdentifier(); if(errorCode==ErrorConstants.ERRCODE_BIDFACADE_VERIFY_TRANSACTION_REQ_FAILED_GETCERTSTATUS) { // Inform user that certificate is not valid } // Handle the exception } // nextUrl required but ignored when BankID on mobile sessionData.setNextURL("https://www.merchant.com/authenticated"); try { String responseToClient=myFacade.verifyTransactionReponse(sessionData); // return the response to the client, and update user session as authenticated }catch(BIDException be){ int errorCode=be.getErrorCode(); String errorMessage=be.getMessage(); String methodIdentifier=be.getMethodIdentifier(); // Handle the exception }
Authentication process - BankID Web-client 2.0
// BankID authentication. This example builds upon the earlier code excerpts using // "merchant" // step 1: Calling initSession to get the helper URI and the clientID // A user clicks on the login-button on www.merchant.com. The merchant-application // registers this action and sends an initSession to the BankID COI. In response the // merchant gets a link to the BankID helper and a clientID. // try { InitSessionInfo initSessionInfo = new InitSessionInfo(); initSessionInfo.setAction("auth"); initSessionInfo.setUserAgent("userHttpHeaderUserAgent"); initSessionInfo.setMerchantURL("https://www.merchant.com/BankID"); initSessionInfo.setLocaleId("nb"); initSessionInfo.setSid("sid"); initSessionInfo.setSuppressBroadcast("N"); initSessionInfo.setCertType("ALL"); initSessionInfo.setTimeout("40000"); initSessionInfo.setNextURL("https://www.merchant.com/BankID"); initSessionInfo.setMerchantFEDomain("merchantFEDomain"); initSessionInfo.setWithCredentials("N"); initSessionInfo = minFacade.initSession(initSessionInfo); // Return parameters of interest String clientID = initSessionInfo.getClientID(); String helperURI = initSessionInfo.getHelperURI(); String traceID = initSessionInfo.getTraceID(); // store the traceID in local session store for later use } catch(BIDException be) { // Handle Error Situation } // Now redirect the user to a page where the helperURI javascript is sourced. // Call the init() function in the BankID helper javascript, to start the process of // retrieving the BankID Web-client. // step 2: // The BankID Web-client initialises and sends the following parameters to the merchant // application: operation, encKey, encData, encAuth and sid String operation = request.getParameter("operation"); String sid = request.getParameter("sid"); String encKey = request.getParameter("encKey"); String encData = request.getParameter("encData"); String encAuth = request.getParameter("encAuth"); // Get the traceID from local session store String traceId = <the traceId from initSession>; // Create a BIDSessionData object to use during the whole authentication process. // Supply the traceID as input to the constructor. BIDSessionData sessionData = new BIDSessionData(traceId); try { String responseToClient = minFacade.initTransaction(operation, encKey, encData, encAuth, sid, sessionData); // store the sessionData in local session store for later use } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } // step 3: // The end-user has signed the server challenge. The BankID Client returns the encKey, encData and encAuth to the merchant application String operation = request.getParameter("operation"); String sid = request.getParameter("sid"); String encKey = request.getParameter("encKey"); String encData = request.getParameter("encData"); String encAuth = request.getParameter("encAuth"); // get the sessionData form local session store try { minFacade.verifyTransactionRequest(operation, encKey, encData, encAuth, sid, sessionData); } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } // step 4: // The merchant application may want to get some information from the // end-user's certificate for authorization purposes or to connect the authenticated // user to e.g. a customer database. try { // Get the certificate information by passing the clientSignature String // recieved from the BIDSessionData object CertificateInfo certInfo = minFacade.getCertificateInfo(sessionData.getClientSignature()); String issuerName = certInfo.getIssuerName(); String subjectName = certInfo.getSubjectName(); Date validFrom = certInfo.getValidFrom(); Date validTo = certInfo.getValidTo(); String versionNumber = certInfo.getVersionNumber(); String serialNumber = certInfo.getSerialNumber(); String keyAlgorithm = certInfo.getKeyAlgorithm(); String keySize = certInfo.getKeySize(); String policyOIDInfo = certInfo.getPolicyOID(); String originator = certInfo.getOriginator(); Date dateOfBirth = certInfo.getDateOfBirth(); String bankName = certInfo.getBankName(); String uniqueId = certInfo.getUniqueId(); String commonName = certInfo.getCommonName(); String emailAddress = certInfo.getEmailAddress(); String isCertQualified = certInfo.isQualified(); String monetaryLimitAmount = certInfo.getQcValueLimitAmount(); // Only if isQualified String monetaryLimitCurrency = certInfo.getQcValueLimitCurrency(); // Only if isQualified } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } RESPONSE TO THE BANKID CLIENT *********************** return verifyTransactionResponse(sessionData);
Authentication process - BankID Web-client 2.1
// BankID authentication. This example builds upon the earlier code excerpts using // "merchant" // step 1: Calling initSession to get the helper URI and the clientID // A user clicks on the login-button on www.merchant.com. The merchant-application // registers this action and sends an initSession to the BankID COI. In response the // merchant gets a link to the BankID helper and a clientID. // try { initSessionInfo initSessionInfo = new InitSessionInfo(); initSessionInfo.setAction("auth"); initSessionInfo.setUserAgent("userHttpHeaderUserAgent"); initSessionInfo.setMerchantURL("https://www.merchant.com/BankID"); initSessionInfo.setLocaleId("nb"); initSessionInfo.setSid("sid"); initSessionInfo.setSuppressBroadcast("N"); initSessionInfo.setCertType("ALL"); initSessionInfo.setTimeout("40000"); initSessionInfo.setNextURL("https://www.merchant.com/BankID"); initSessionInfo.setMerchantFEDomain("merchantFEDomain"); initSessionInfo.setWithCredentials("N"); initSessionInfo.setMerchantFEAncestors("domain1 domain2 ... domainN"); initSessionInfo.setClientSessionTimeout("1800000"); initSessionInfo.setClientVersion("2.1"); initSessionInfo = minFacade.initSession(initSessionInfo); // Return parameters of interest String clientID = initSessionInfo.getClientID(); String helperURI = initSessionInfo.getHelperURI(); String traceID = initSessionInfo.getTraceID(); // store the traceID in local session store for later use } catch(BIDException be) { // Handle Error Situation } // Now redirect the user to a page where the helperURI javascript is sourced. // Call the init() function in the BankID helper javascript, to start the process of // retrieving the BankID Web-client. // step 2: // The BankID Web-client initialises and sends the following parameters to the merchant // application: operation, encKey, encData, encAuth and sid String operation = request.getParameter("operation"); String sid = request.getParameter("sid"); String encKey = request.getParameter("encKey"); String encData = request.getParameter("encData"); String encAuth = request.getParameter("encAuth"); // Get the traceID from local session store String traceId = <the traceId from initSession>; // Create a BIDSessionData object to use during the whole authentication process. // Supply the traceID as input to the constructor. BIDSessionData sessionData = new BIDSessionData(traceId); try { String responseToClient = minFacade.initTransaction(operation, encKey, encData, encAuth, sid, sessionData); // store the sessionData in local session store for later use } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } // step 3: // The end-user has signed the server challenge. The BankID Client returns the encKey, encData and encAuth to the merchant application String operation = request.getParameter("operation"); String sid = request.getParameter("sid"); String encKey = request.getParameter("encKey"); String encData = request.getParameter("encData"); String encAuth = request.getParameter("encAuth"); // get the sessionData form local session store try { minFacade.verifyTransactionRequest(operation, encKey, encData, encAuth, sid, sessionData); } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } // step 4: // The merchant application may want to get some information from the // end-user's certificate for authorization purposes or to connect the authenticated // user to e.g. a customer database. try { // Get the certificate information by passing the clientSignature String // recieved from the BIDSessionData object CertificateInfo certInfo = minFacade.getCertificateInfo(sessionData.getClientSignature()); String issuerName = certInfo.getIssuerName(); String subjectName = certInfo.getSubjectName(); Date validFrom = certInfo.getValidFrom(); Date validTo = certInfo.getValidTo(); String versionNumber = certInfo.getVersionNumber(); String serialNumber = certInfo.getSerialNumber(); String keyAlgorithm = certInfo.getKeyAlgorithm(); String keySize = certInfo.getKeySize(); String policyOIDInfo = certInfo.getPolicyOID(); String originator = certInfo.getOriginator(); Date dateOfBirth = certInfo.getDateOfBirth(); String bankName = certInfo.getBankName(); String uniqueId = certInfo.getUniqueId(); String commonName = certInfo.getCommonName(); String emailAddress = certInfo.getEmailAddress(); String isCertQualified = certInfo.isQualified(); String monetaryLimitAmount = certInfo.getQcValueLimitAmount(); // Only if isQualified String monetaryLimitCurrency = certInfo.getQcValueLimitCurrency(); // Only if isQualified } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } RESPONSE TO THE BANKID CLIENT *********************** return verifyTransactionResponse(sessionData);
Signing process, no SEID SDO – BankID on Mobile
// Step 1,2 and 3 are the same as in the authentication process. Except that // mobileInfo.setAction("sign") should be set instead of mobileInfo.setAction("auth") // BankID Signing process without creating a SEID SDO (Signed Data Object) // The BankID Client initiates the client-merchant dialogue by sending // "operation=initSign" // The end-user and the merchant agrees upon signing a contract. String encKey = request.getParameter("encKey"); String encData = request.getParameter("encData"); String encAuth = request.getParameter("encAuth"); String operation = request.getParameter("operation"); String sid = request.getParameter("sid"); // create a BIDSessionData object to use during the whole signing process. BIDSessionData sessionData = new BIDSessionData(); String contract = <read the contract from somewhere>; sessionData.setDataToBeSigned(contract); sessionData.setDataToBeSignedMimeType("plain/text"); sessionData.setDataDescription("Some description"); try { String response = minFacade.initTransaction(operation, encKey, encData, encAuth, sid, sessionData); // Store the sessionData object in locale session store for later use } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } // The mobile device signs the data and returns its own signature. Verify the end user // signature. The mobile infrastructure returns the following // (operation=verifySign&encKey=<theEncKey>&encData=<theEncData>&encAuth=<theEncAuth>) String encKey = request.getParameter("encKey"); String encData = request.getParameter("encData"); String encAuth = request.getParameter("encAuth"); String operation = request.getParameter("operation"); String sid = request.getParameter("sid"); // Get the sessionData from the locale session store try { // The merchant must verify the end user signature. minFacade.verifyTransactionRequest(operation, encKey, encData, encAuth, sid, sessionData); return verifyTransactionResponse(sessionData); } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation }
Signing process, no SEID SDO – BankID Web-client 2.0
// Step 1 is the same as in the authentication process. Except for some of the initSession // parameters specific for the signing process. initSessionInfo.setAction("sign"); initSessionInfo.setShowUnderstanding("Y"); initSessionInfo.setShowConfirmation("Y"); initSessionInfo.setDocDisplayMode("interior"); // set domain to load PDF if appropriate initSessionInfo.setExtPDFDomain("www.merchant.com"); // BankID Signing process without creating a SEID SDO (Signed Data Object) // The BankID Client initiates the client-merchant dialogue by sending // "operation=initSign" // step 2: // The end-user and the merchant agrees upon signing a contract. String encKey = request.getParameter("encKey"); String encData = request.getParameter("encData"); String encAuth = request.getParameter("encAuth"); String operation = request.getParameter("operation"); String sid = request.getParameter("sid"); // Get the traceID from local session store String traceID = <the traceID from initSession>; // create a BIDSessionData object to use during the whole signing process. BIDSessionData sessionData = new BIDSessionData(traceID); String contract = <read the contract from somewhere>; sessionData.setDataToBeSigned(contract); sessionData.setDataToBeSignedMimeType(<theMimeType>); sessionData.setDataDescription("Some description"); // if signing a PDF, supply the url to load the PDF from as well sessionData.setExtPDFUrl(" https://www.mercant.com/pdf "); try { String response = minFacade.initTransaction(operation, encKey, encData, encAuth, sid, sessionData); // Store the sessionData object in locale session store for later use } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } // step 3: // The client signs the data and returns its own signature. Verify the client // signature. The client returns the following // (operation=verifySign&encKey=<theEncKey>&encData=<theEncData>&encAuth=<theEncAuth>) String encKey = request.getParameter("encKey"); String encData = request.getParameter("encData"); String encAuth = request.getParameter("encAuth"); String operation = request.getParameter("operation"); String sid = request.getParameter("sid"); // Get the sessionData from the locale session store try { // The merchant must verify the client signature. minFacade.verifyTransactionRequest(operation, encKey, encData, encAuth, sid, sessionData); return verifyTransactionResponse(sessionData); } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation }
Signing process, no SEID SDO – BankID Web-client 2.1
// Step 1 is the same as in the authentication process. Except for some of the initSession // parameters specific for the signing process. initSessionInfo.setAction(“sign”); initSessionInfo.setShowUnderstanding(“Y”); initSessionInfo.setShowConfirmation(“Y”); initSessionInfo.setDocDisplayMode(“one of interior,window or overlay”); // BankID Signing process without creating a SEID SDO (Signed Data Object) // The BankID Client initiates the client-merchant dialogue by sending // “operation=initSign” // step 2: // The end-user and the merchant agrees upon signing a contract. String encKey = request.getParameter(“encKey”); String encData = request.getParameter(“encData”); String encAuth = request.getParameter(“encAuth”); String operation = request.getParameter(“operation”); String sid = request.getParameter(“sid”); // Get the traceID from local session store String traceID = ; // create a BIDSessionData object to use during the whole signing process. BIDSessionData sessionData = new BIDSessionData(traceID); // Add a text document sessionData.addTextDocument(“Text to sign”, "Test-data for signering"); // Add a PDF document sessionData.addTextDocument(<PDF bytes to sign>, "Test-data for signering"); // Add an XML document sessionData.addXMLDocument(“<XML to sign>”, “<XSL string>”, "Test-data for signering"); try { String response = minFacade.initTransaction(operation, encKey, encData, encAuth, sid, sessionData); // Store the sessionData object in locale session store for later use } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } // step 3: // The client signs the data and returns its own signature. Verify the client // signature. The client returns the following // (operation=verifySign&encKey=<the encKey>&encData=<the encData>&encAuth=<theEncAuth>) String encKey = request.getParameter(“encKey”); String encData = request.getParameter(“encData”); String encAuth = request.getParameter(“encAuth”); String operation = request.getParameter(“operation”); String sid = request.getParameter(“sid”); // Get the sessionData from the locale session store try { // The merchant must verify the client signature. minFacade.verifyTransactionRequest(operation, encKey, encData, encAuth, sid, sessionData); return verifyTransactionResponse(sessionData); } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation }
Signing process with SEID SDO, BankID Web-Client 2.0 and Mobile
The example in the code below is valid for all BankID clients except for the BankID Web-Client 2.1. The example is threrefore also valid for BankID on Mobile.
// BankID Signing process creating a SEID SDO (Signed Data Object) // The BankID Client initiates the client-merchant dialogue by sending // "operation=initSign" // step 1: // The end-user and the merchant agrees upon signing a contract. String encKey = request.getParameter("encKey"); String encData = request.getParameter("encData"); String encAuth = request.getParameter("encAuth"); String operation = request.getParameter("operation"); String sid = request.getParameter("sid"); // create a BIDSessionData object to use during the whole signing process. BIDSessionData sessionData = new BIDSessionData(); try { String contract = <read the contract from somewhere>; sessionData.setDataToBeSigned(contract); sessionData.setDataToBeSignedMimeType(<theMimeType>); sessionData.setDataDescription("The merchants description of the signed data"); String response = minFacade.initTransaction(operation, encKey, encData, encAuth, sid, sessionData); //Store sessionData for later use } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } // step 2: // The client signs the data and returns its own signature. Verify the client // signature. The client returns the following // (operation=verifySign&encKey=<theEncKey>&encData=<theEncData>&encAuth=<theEncAuth>) String encKey = request.getParameter("encKey"); String encData = request.getParameter("encData"); String encAuth = request.getParameter("encAuth"); String operation = request.getParameter("operation"); String sid = request.getParameter("sid"); // Get the sessionData from locale store try { // The merchant must verify the client signature. minFacade.verifyTransactionRequest(operation, encKey, encData, encAuth, sid, sessionData); } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } // step 3: // Call createSDO try { SEID_SDO seidSDO = minFacade.createSDO( sessionData.getClientSignatureBytes (), sessionData.getMerchantSignatureBytes (), sessionData.getSignedDataBytes (), sessionData.getDataToBeSignedMimeType(), sessionData.getMerchantOCSPBytes (), sessionData.getClientOCSPBytes (), sessionData.getDataDescription()); sessionData.setSdo(seidSDO); // seidSDO.toXml() gives the result, UTF-8 encoded return verifyTransactionResponse(sessionData); } catch(BIDException be) { String errorMessage = be.getMessage(); // Handle error situation }
Signing process with SEID SDO with multiple signatures
// In this scenario we imagine that a merchant signs a document and makes several end- // users sign it as well BEFORE creating a SEID_SDO try { // For 1..N end-users the merchant initiates the signing process. Please refer to earlier // examples to see how that is done. // The merchant has received the end-user (client) PKCS#7. The merchant validates the // signature calling the verify(…) method and then gets the certificate status.The end-user // PKCS#7 and OCSPResponse (CertificateStatus) is stored in a PKCS7WithOCSPResponse instance // Do this for ALL end-users that are supposed to sign the "contract" CertificateStatus status = sessionData.getCertificateStatus(); PKCS7WithOCSPResponse clientPKCS7AndOCSP = new PKCS7WithOCSPResponse(); clientPKCS7AndOCSP.setB64OCSPResponse(status.getB64OCSPResponse()); clientPKCS7AndOCSP.setB64PKCS7(b64ClientPKCS7); //…store the clientPKCS7AndOCSP for later processing // Now let's assume that the merchant has a PKCS7WithOCSPResponse[] with all // signatures. // The merchant must add its own signature as well (the merchant doesn't have to but in // this example it does.) // The merchant always has to sign the data first during a sign operation in BankID. // So we assume that the merchant signature (merchantPKCS#7) is available. The OCSP // for the merchant is always returned to the merchant application from the BankIDClient. PKCS7WithOCSPResponse merchantPKCS7AndOCSP = new PKCS7WithOCSPResponse(); merchantPKCS7AndOCSP.setB64OCSPResponse(sessionData.getMerchantOCSP()); merchantPKCS7AndOCSP.setB64PKCS7(sessionData.getMerchantSignature()); // Add the merchantPKCS7AndOCSP (PKCS7WithOCSPResponse) to // PKCS7WithOCSPResponse[]allSignaturesAndOCSPs PKCS7WithOCSPResponse[] allSignaturesAndOCSPs = …; // Merchant and end-users signatures // Create a SEID_SDO holding ALL the signatures and OCSPReponses in the input // PKCS7WithOCSPResponse[]. The PKCS7WithOCSPResponse[] must have at least 1 entry SEID_SDO seidSDO = minFacade.createDynamicSDO ( allSignaturesAndOCSPs, signedDataBytes, "text/plain" // OR "application/pdf" OR text/BIDXML "Multiple Signature SEID_SDO" ); // The SEID_SDO result object is NOT Sealed. This means that the merchant application has // to call the createSDOSeal method when all parties have provided their signature // NOTE: "Sealing" a SEID_SDO means signing the content of the SEID_SDO. This also means // that the Seal-signature must also include the merchant CertificateStatus at the time // the SEID_SDO is sealed. CertificateStatus merchantCertStatusAtSealingTime = bidFacade.getOwnCertificateStatus(); seidSDO = bidFacade.createSDOSeal( seidSDO, merchantCertStatusAtSealingTime.getB64OCSPResponse() ); // Let's add the data to the SEID_SDO before storing it seidSDO.addSignedDataRaw(signedData); // Store the SEID_SDO to file for later use store2File("/SDO/sdo.sdo",seidSDO.toXML()); // NOTE: UTF-8 bytes of the SEID_SDO is stored // Let's assume that the merchant wants to to add a new client signature to the SEID_SDO // that is stored. byte[] utf8_SEID_SDO_XML_Bytes = readutf8File(("/SDO/sdo.sdo")); // We validate the dynamic SEID_SDO (multiple signature SEID_SDO), The inputs are // the SEID_SDO XML bytes (UTF-8), the signedData or NULL if the SEID_SDO already // has the data stored in it. The integer 0 telling that we do NOT expect any number of // signature. NOTE: If the integer is for example 4 then this method EXPECTS there to be // 4 signature in the SEID_SDO. Passing the 0 integer tells the method to ignore the // number of signature in the SEID_SDO (we do not expect any number). But keep in mind that // the SEID_SDO MUST contain at least 1 signature with its corresponding OCSP Response. // The Boolean "true" tells the method that the SEID_SDO is sealed. SO check the validity // of the Seal signature as well. bidFacade.validateDynamicSDO(utf8_SEID_SDO_XML_Bytes, signedData, 0, true); // SOME CONVIENIENCE METHODS / EXAMPLES // If you want to create a SEID_SDO instance then do the following SEID_SDO sdo = new SEID_SDO(utf8_SEID_SDO_XML_Bytes); // If you want to retrieve the signedData for other end-users to sign byte[] signedDataFromSDO = sdo.getSEID_SDOElement(0).getSignedObject().getSignedDataRaw() OR byte[] b64SignedDataFromSDO = sdo.getSEID_SDOElement(0).getSignedObject().getB64SignedData(); // Precondition: // We already have a new client PKCS#7 and OCSP stored in a PKCS7WithOCSPResponse located // in a PKCS7WithOCSPResponse[] PKCS7WithOCSPResponse[] clientSignature2Add = … // NOTE: Adding new PKCS7WithOCSPResponse entries to the SEID_SDO invalidates the Seal // signature. This means that the resulting sdo does NOT contain the seal signature sdo = bidFacade.addSDOSignature(sdo, clientSignature2Add, signedDataFromSDO); // Seal the SEID_SDO CertificateStatus merchantCertStatusAtSealingTime = bidFacade.getOwnCertificateStatus(); sdo = bidFacade.createSDOSeal(sdo,merchantCertStatusAtSealingTime.getB64OCSPResponse()); store2File("/SDO/newsdo.sdo",sdo.toXML()); // NOTE: UTF-8 bytes of the SEID_SDO is stored } catch(BIDException be) { String errorMessage = be.getMessage(); // Handle error situation }
Signing process with SEID SDO – BankID Web-client 2.1
// Step 1 is the same as in the authentication process. Except for some of the initSession // parameters specific for the signing process. initSessionInfo.setAction(“sign”); initSessionInfo.setShowUnderstanding(“Y”); initSessionInfo.setShowConfirmation(“Y”); initSessionInfo.setDocDisplayMode(“one of interior,window or overlay”); // BankID Signing process without creating a SEID SDO (Signed Data Object) // The BankID Client initiates the client-merchant dialogue by sending // “operation=initSign” // step 2: // The end-user and the merchant agrees upon signing a contract. String encKey = request.getParameter(“encKey”); String encData = request.getParameter(“encData”); String encAuth = request.getParameter(“encAuth”); String operation = request.getParameter(“operation”); String sid = request.getParameter(“sid”); // Get the traceID from local session store String traceID = ; // create a BIDSessionData object to use during the whole signing process. BIDSessionData sessionData = new BIDSessionData(traceID); // Add a text document sessionData.addTextDocument(“Text to sign”, "Test-data for signering"); // Add a PDF document sessionData.addTextDocument(<PDF bytes to sign>, "Test-data for signering"); // Add an XML document sessionData.addXMLDocument(“<XML to sign>”, “<XSL string>”, "Test-data for signering"); try { String response = minFacade.initTransaction(operation, encKey, encData, encAuth, sid, sessionData); // Store the sessionData object in locale session store for later use } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } // step 3: // The client signs the data and returns its own signature. Verify the client // signature. The client returns the following // (operation=verifySign&encKey=<the encKey>&encData=<the encData>&encAuth=<theEncAuth>) String encKey = request.getParameter(“encKey”); String encData = request.getParameter(“encData”); String encAuth = request.getParameter(“encAuth”); String operation = request.getParameter(“operation”); String sid = request.getParameter(“sid”); // Get the sessionData from the locale session store try { // The merchant must verify the client signature. minFacade.verifyTransactionRequest(operation, encKey, encData, encAuth, sid, sessionData); // Create SDO(s) List<SEID_SDO> sdoList = new ArrayList<>(); for (DocumentToSign doc : sessionData.getDocuments()) { SEID_SDO seidSDO = bidFacade.createSDO( doc.getClientSignatureBytes(), doc.getMerchantSignatureBytes(), doc.getSignedDataBytes(), doc.getMimeTypeValue(), sessionData.getMerchantOCSPBytes(), doc.getClientOCSPBytes(), doc.getDescription()); sdoList.add(seidSDO); // seidSDO.toXml() gives the result, UTF-8 encoded } return verifyTransactionResponse(sessionData); } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation }
PAdES serial signing of PDF documents
Note: It is not possible to mix serial and parallell signing in the same scenario.
In PAdES serial signing, the order in which the signatories sign the document matters (this is the "serial" part), and signatures and validation data is embedded in the document. The PAdES signed documents can additionally contain visual seals representing the signatures.
Generation of visual seals and generation of validation data can be done either by the COI or the merchant application. When the COI does it, it's referred to as "turnkey", while if the merchant application does it itself, it's referred to as "self-assembly/-ed/-er/-ing". Generation of seals and generation of validation data are independent, and all combinations of turnkey and self-assembly flows are supported, as detailed in this table, along with which functions must be called to enable each flow:
Turnkey seals | Self-assembled seals | |
---|---|---|
Turnkey validation | COI generates seals and validation data. Use | Merchant generates seals, COI generates validation data. Use |
Self-assembled validation | COI generates seals, merchant generates validation data. Use | Merchant generates seals and validation data. Use |
Signing process, serial (PAdES), turnkey solution – BankID Web-client 2.1
For serial signing, it is not possible to mix text, xml and pdf files in one BankID signing session. All documents should be pdfs.
// Step 1 is the same as in the authentication process. Except for some of the initSession // parameters specific for the signing process. initSessionInfo.setAction(“sign”); initSessionInfo.setShowUnderstanding(“Y”); initSessionInfo.setShowConfirmation(“Y”); initSessionInfo.setDocDisplayMode(“one of interior,window or overlay”); // Step 2: // The BankID Client initiates the client-merchant dialogue by sending “operation=initSign” // Merchant needs to build a session with serialSigningProperty and with one or more pdf documents // marked for serial signing String encKey = request.getParameter(“encKey”); String encData = request.getParameter(“encData”); String encAuth = request.getParameter(“encAuth”); String operation = request.getParameter(“operation”); String sid = request.getParameter(“sid”); // Get the traceID from local session store String traceID = ; // create a BIDSessionData object to use during the whole signing process. BIDSessionData sessionData = new BIDSessionData(traceID); // setting of PAdES specific properties // Set CMS and OCSP format to be PAdES compatible sessionData.setCmsFormat(CMSFormat.PKCS7_ISO320001); sessionData.setOcspFormat(OCSPFormat.OCSP_RFC6960_COMPATIBLE); // Set turnKey sealbuilding and turnKey validation increment building // Alternatives are: // 1.SerialSerialSigningProperties.turnkey() // 2.SerialSerialSigningProperties.turnkeyWithInvisibleSeals() // 3.SerialSerialSigningProperties.selfAssembler() // and all these may be followed by .withSelfAssembledValidation() // sessionData.setSerialSigningProperties(SerialSigningProperties.turnkey()); // Add a PDF document, signing kind serial will give PAdES signed by both merchant and endUser. // signing kind serialEndUserOnly will give PAdES signed by endUser only sessionData.addPdfDocument(<PDF bytes to sign>, "Test-data for signering") .setSigningKind(SigningKind.serial) .setMerchantSealPos(new SealPosition(xPos,yPos,pageNo)) // Optional position .setEndUserSealPos(new SealPosition(xPos,yPos + 15,pageNo)); // handle the "operation"="initSign" bidFacade.initTransaction(operation, encKey, encData, encAuth, sid, sessionData); // step 3: BankID Client generate and returns all merchantseals for serial documents. // Merchant must sing these seals. // operation=initSignSignMerchantSeal&encKey=<the encKey>&encData=<the encData>&encAuth=<theEncAuth> String encKey = request.getParameter(“encKey”); String encData = request.getParameter(“encData”); String encAuth = request.getParameter(“encAuth”); String operation = request.getParameter(“operation”); String sid = request.getParameter(“sid”); // Get the sessionData from the local session store, and sign the seals. // Session is internally updated with the now signed seals. Response contains the signature try { String response = bidFacade.initSignSignMerchantSeals(operation, encKey, encData, encAuth, sid, sessionData); // Store the sessionData object in locale session store for later use } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } // step 4: // The client signs the data and returns the end user signature(s) and visual seal(s). // The merchant validates these signatures, then the merchant must either assemble // validation data into the PAdES itself or let the BankID client do it. // In our case we let the BankID client do it, this will make step 5 happen // (operation=verifySign&encKey=<the encKey>&encData=<the encData>&encAuth=<theEncAuth>) String encKey = request.getParameter(“encKey”); String encData = request.getParameter(“encData”); String encAuth = request.getParameter(“encAuth”); String operation = request.getParameter(“operation”); String sid = request.getParameter(“sid”); // Get the sessionData from the local session store try { // The merchant must verify the client signature. minFacade.verifyTransactionRequest(operation, encKey, encData, encAuth, sid, sessionData); // If needed get PDFReport, SSN or enduser certificate information here return verifyTransactionResponse(sessionData); } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } // step 5: // The client receives certificates and OCSP responses from merchant and adds them as an incremental update to the PDF. // This incremental update is returned back to merchant here // (operation=verifySignAddDSS&encKey=<the encKey>&encData=<the encData>&encAuth=<theEncAuth>) String encKey = request.getParameter(“encKey”); String encData = request.getParameter(“encData”); String encAuth = request.getParameter(“encAuth”); String operation = request.getParameter(“operation”); String sid = request.getParameter(“sid”); // Get the sessionData from the locale session store try { // The merchant must add validation data to its PAdES-es String retval = minFacade.verifySignAddDSS(operation, encKey, encData, encAuth, sid, sessionData); // Get the finished PAdESes for (DocumentToSign doc : sessionData.getDocuments()) { listOfPadesDocumentInBytes.add(doc.getSignedDocumentBytesIncludingIncrementalUpdates()); } return retval; } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation }
Signing process, serial (PAdES), self assembling merchant solution – BankID Web-client 2.1
For serial signing, it is not possible to mix text, xml and pdf files in one BankID signing session. All documents should be pdfs.
Self assembling merchants add incremental updates to the PDF. These updates consist of both a merchantseal and an endUserseal. BankID server's role is to perform the signing of these seals and place this information into the seal structure. BankID server extracts some useful data from the BankID session and calls a merchant-supplied function when the seals are needed.
// Step 1 is the same as in the authentication process. Except for some of the initSession // parameters specific for the signing process. initSessionInfo.setAction(“sign”); initSessionInfo.setShowUnderstanding(“Y”); initSessionInfo.setShowConfirmation(“Y”); initSessionInfo.setDocDisplayMode(“one of interior,window or overlay”); // Step 2: // The BankID Client initiates the client-merchant dialogue by sending “operation=initSign” // Merchant needs to build a session with serialSigningProperty and with one or more pdf documents // marked for serial signing. // Merchant also needs, for each document to insert a visual seal for the merchant. String encKey = request.getParameter(“encKey”); String encData = request.getParameter(“encData”); String encAuth = request.getParameter(“encAuth”); String operation = request.getParameter(“operation”); String sid = request.getParameter(“sid”); // Get the traceID from local session store String traceID = ; // create a BIDSessionData object to use during the whole signing process. BIDSessionData sessionData = new BIDSessionData(traceID); // setting of PAdES specific properties // Set CMS and OCSP format to be PAdES compatible sessionData.setCmsFormat(CMSFormat.PKCS7_ISO320001); sessionData.setOcspFormat(OCSPFormat.OCSP_RFC6960_COMPATIBLE); // Set selfassembling sealbuilding and selfAssembling validation // Alternatives are: // 1.SerialSerialSigningProperties.turnkey() // 2.SerialSerialSigningProperties.turnkeyWithInvisibleSeals() // 3.SerialSerialSigningProperties.selfAssembler() // and all these may be followed by .withSelfAssembledValidation() // sessionData.setSerialSigningProperties(SerialSigningProperties.selfAssembler()); // Add a PDF document, signing kind serial will give PAdES signed by both merchant and endUser. // signing kind serialEndUserOnly will give PAdES signed by endUser only sessionData.addPdfDocument(<PDF bytes to sign>, "Test-data for signering") .setSigningKind(SigningKind.serial) .setMerchantSealPos(new SealPosition(xPos,yPos,pageNo)) // Optional position .setEndUserSealPos(new SealPosition(xPos,yPos + 15,pageNo)); // handle the "operation"="initSign" String response = bidFacade.initTransactionSelfAssembler(operation, encKey, encData, encAuth, sid, sessionData, buildMerchantSealIncrement); // step 3: BankID Client let the user sign each documents. For EACH document in turn, the client will ask the // merchant for a graphic representation of the endUser seal // operation=initSignBuildEndUserSeal&encKey=<the encKey>&encData=<the encData>&encAuth=<theEncAuth> String encKey = request.getParameter(“encKey”); String encData = request.getParameter(“encData”); String encAuth = request.getParameter(“encAuth”); String operation = request.getParameter(“operation”); String sid = request.getParameter(“sid”); // Get the sessionData from the locale session store, and sign the seals. // Session is internally updated with the now signed seals. Response contains the signature try { String response = bidFacade.initSignBuildEndUserSeal(operation, encKey, encData, encAuth, sid, sessionData, buildEndUserSealIncrement); // Store the sessionData object in locale session store for later use } catch(BIDException be) { String errorMessage = be.getMessage(); int errorCode = be.getErrorCode(); // Handle error situation } // step 4 and step 5 as PAdES turnkey example
PAdES visual seal generation for self assembling merchants
Below is an example how a merchant may implement the callback function needed to add visual seals to a document. apache.PDFBox is used as the PDF library.
Remark that BankID servers allows the returned ByteRangeWithData with data to be either the incremental update only or the complete pdf including the incremental update.
In example below only the incremental update is returned.
When signature is computed over this seal, BankID server will insert the signature into the ByteRangeWithData returned
When these callbackfunctions throw an exception it may be hard too see that it comes from these functions, therefore a catch all block which logs and "rethrows" is useful.
ByteRangeWithData buildMerchantSealIncrement(String sid, int docIndex, byte[] pdfBytes, VisualSealCertData merchantOrEnduser) { try { // if needed, get session using sid, get document to sign from BIDSessionData using docIndex DocumentToSign documentToSign = bidSessionData.getDocuments().get(docIndex); try (PDDocument originalPdf = PDDocument.load(pdfBytes);) { SignatureOptions signatureOptions = getSignatureOptions(originalPdf, sessionSequenceInfo.getVisualMerchantSeal(), documentToSign.getMerchantSealPos()); PDSignature pdSignature = getPdSignature(merchantOrEnduser.getOrganization()); originalPdf.addSignature(pdSignature, signatureOptions); return buildSealIncrement(originalPdf, pdfBytes.length); } } catch (Exception e) { throw new RuntimeException("Merchant Failed to create document", e); } } ByteRangeWithData buildEndUserSealIncrement(String sid, int docIndex, byte[] pdfBytes, VisualSealCertData merchantOrEnduser) { try { // if needed, get session using sid, get document to sign from BIDSessionData using docIndex DocumentToSign documentToSign = bidSessionData.getDocuments().get(docIndex); try (PDDocument originalPdf = PDDocument.load(pdfBytes);) { SignatureOptions signatureOptions = getSignatureOptions(originalPdf, sessionSequenceInfo.getVisualEndUserSeal(), documentToSign.getEndUserSealPos()); PDSignature pdSignature = getPdSignature(merchantOrEnduser.getOrganization()); originalPdf.addSignature(pdSignature, signatureOptions); return buildSealIncrement(originalPdf, pdfBytes.length); } } catch (Exception e) { throw new RuntimeException("Merchant failed to create document", e); } } ByteRangeWithData buildSealIncrement(PDDocument originalPdf, int originalDocumentLength) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); ExternalSigningSupport externalSigning = originalPdf.saveIncrementalForExternalSigning(output); byte[] signature = new byte[0]; externalSigning.setSignature(signature); //Set an empty signature to reserve space for BankID server to place its signature byte[] documentWithSignatureBytes = output.toByteArray(); try (PDDocument signedPDF = PDDocument.load(documentWithSignatureBytes);) { int[] byteRangeArr = signedPDF.getLastSignatureDictionary().getByteRange(); int sealLength = documentWithSignatureBytes.length - originalDocumentLength; byte[] sealBytes = new byte[sealLength]; System.arraycopy(documentWithSignatureBytes, originalDocumentLength, sealBytes, 0, sealLength); return ByteRangeWithData.createAt(ByteRange.createBasic( originalDocumentLength, byteRangeArr[1] - originalDocumentLength, byteRangeArr[2], byteRangeArr[3]), endUserSeal); } }
PAdES turnkey or self assembling validation data
BankID adds by default an incremental update consisting of validation data to the PAdES. This incremental update consist of certificates and corresponding OCSP responses. The merchant may override this and supply it's own for example to add timestamps. A merchantsupplied function is called when this increment is needed. BankID server supplies the certificates and ocsp responses needed.
Below is a self assembling example:
// Modify step 2: add .withSelfAssembler() to the BIDSessionData's serialSigningProperties sessionData.setSerialSigningProperties(SerialSigningProperties.turnKey().withSelfAssembledValidation()); // Modify step 4 by calling verifyTransactionRequestSelfAssembler instead of verifyTransactionRequest // and extract complete pdfs in the "operation=verifySign" handler // The merchant-added increments will be sent to client in response generated by verifyTransactionResponse // such that the enduser may download the finished PAdES in the client. bidFacade.verifyTransactionRequestSelfAssembler(operation, encKey, encData, encAuth, sid, sessionData, buildValidationDataIncrement); for (DocumentToSign doc : sessionData.getDocuments()) { listOfPadesDocumentInBytes.add(doc.getSignedDocumentBytesIncludingIncrementalUpdates()); } // remove handling of "operation=verifySignAddDSS" // implement the buildValidationDataIncrement function, see below
PAdES validationgeneration for self assembling merchants
Below is an example of how a merchant might implement the callback function needed to add an incremental update containing validation data to a document.
apache.PDFBox is used as the PDF library.
Note that BankID server allows the returned ByteRangeWithData with data to be either the incremental update only or the complete PDF including the incremental update. In this example the whole PDF is returned.
When this callback function throws an exception it may be hard too see that it comes from this function, therefore a catch all block which logs and "rethrows" is useful.
ByteRangeWithData buildValidationDataIncrement(String sessionId, int docIndex, byte[] pdfBytes, OCSPResp endUserOcspResp, X509Certificate[] endUserCertificates, Optional<OCSPResp> optMerchantOcspResp, Optional<X509Certificate[]> optMerchantCertificates) { try (PDDocument originalPdf = PDDocument.load(pdfBytes)) { PDDocumentCatalog catalog = originalPdf.getDocumentCatalog(); COSDictionary catalogDictionary = catalog.getCOSObject(); List<byte[]> ocspResponses = new ArrayList<>(); // This is said to be best practice, all earlier ocsps will be referenced from this newest DSS Optional<COSArray> previousOcsps = Optional .ofNullable((COSDictionary) catalog.getCOSObject().getDictionaryObject("DSS")) .map(cosDictionary -> (COSArray) cosDictionary.getDictionaryObject("OCSPs")); // Best practice is to also add and do the same with the "Certs" object, but this step is omitted here. ocspResponses.add(endUserOcspResp.getEncoded()); if (optMerchantOcspResp.isPresent()) { OCSPResp merchantOcsp = optMerchantOcspResp.get(); ocspResponses.add(merchantOcsp.getEncoded()); } COSDictionary dssDictionary = createDssDictionary(ocspResponses, previousOcsps); catalogDictionary.setNeedToBeUpdated(true); catalogDictionary.setItem(COSName.getPDFName("DSS"), dssDictionary); ByteArrayOutputStream output = new ByteArrayOutputStream(); originalPdf.saveIncremental(output); byte[] bytes = output.toByteArray(); return ByteRangeWithData.createAt0(bytes); } catch (IOException e) { throw new RuntimeException("Failed to add OCSP Response to document", e); } catch (Exception e) { throw new RuntimeException("Merchant failed to add validation data", e); } }
Retrieve additional information from VA
A call to verifyTransactionRequest includes a call to VA to get the client certificate status. The CertificateStatus object can be retrieved by calling sessionData.getCertificateStatus() after a call to verifyTransactionRequest.
The code below shows an example of how to get the status of a certificate and at the same time retrieve additional information (AI) about the certificate holder.
//If additional information is wanted about the client, and an agreement to obtain //such information exists with the bank, the following infoitems may also be requested: ArrayList additionalInfos = new ArrayList(); //To retrieve the account number of the client, if it exists additionalInfos.add(JServerConstants.LABEL_OID_OCSP_ACCOUNT); //To retrieve the social security number of the client, if it exists additionalInfos.add(JServerConstants.LABEL_OID_OCSP_SSN); //To retrieve the org.number of the client, if the client is a merchant and it exists additionalInfos.add(JServerConstants.LABEL_OID_OCSP_ORGNO); sessionData.setAdditionalInfoList(additionalInfos); bankIDFacade.verifyTransactionRequest(operation, encKey, encData, encAuth, sid, sessionData); //End-user is now successfully authenticated // If the infoitems for AI (additional information) from the VA is set, the following // will be available at the CertificateStatus object: CertificateStatus certStatus = sessionData.getCertificateStatus(); if(certStatus.getAddInfoSSNErr() != null) System.out.println("User's SSN not found: " + certStatus.getAddInfoSSNErr()); else System.out.println("Found the user's SSN: " + certStatus.getAddInfoSSN()); // For multiple document signing AdditionalInformation ai = sessionData.getAdditionalInformation(); if(ai.getAddInfoSSNErr() != null) System.out.println("User's SSN not found: " + ai.getAddInfoSSNErr()); else System.out.println("Found the user's SSN: " + ai.getAddInfoSSN());
Since the verifyTransactionRequest method includes a check of the client certificate status, the getCertificateStatus method is not necessary to call explisitly.
For multiple document signing the request for AI will be sent for the first document only. As described in the example above, the AI will be accessible to the merchant in the AdditionalInformation object in BidSessionData. The same information can also be found in the CertificateStatus of the first document in the document list.