/*
*
* If an error request is send back from BKU, an error message is generated an
* an exception is thrown.
*
* @param sigType
* the type of the SignatureObject that should be returned
* @param userName
* the name of the user calling this method
* @param signText
* the text that shoulf be signed from BKU
* @return the complete SingatureObject of the given type filled by values
* from the BKU-Request
* @throws SignatureException
* @see SignatureObject
*/
public SignatureObject doSign(String sigType, String userName, String signText) throws SignatureException
{
String request_string = prepareSignRequest(userName, signText, sigType);
String sign_url = getSignURL(sigType);
String response_string = sendRequest(sign_url, request_string);
return analyzeSignResponse(response_string, sigType);
}
/**
* This method generates the BKU verify prozess. It checks if the given
* SignatureObject is signed by MOA or BKU. The verify template string is
* filled out by the corresponding method.
*
* @param normalizedText
* the normalized text to verify
* @param sigObject
* the SignatureObject holding the singature values
* @return a SignatureResponse object if the verify prozess does not fails
* @throws SignatureException
* @see SignatureResponse
*/
public SignatureResponse doVerify(String normalizedText,
SignatureObject sigObject) throws SignatureException
{
String request_string = prepareVerifyRequest(normalizedText, sigObject);
String verify_url = getVerifyURL(sigObject.getSignationType());
String response_string = sendRequest(verify_url, request_string);
return analyzeVerifyResponse(response_string);
}
/**
* This method parses the BKU-Response string. It separates the
* SignatureValue, X509IssuerName, SigningTime, X509SerialNumber,
* X509Certificate, CertDigest, DigestValue and the signation id-s. If the
* X509Certificate is extracted it would be stored in the certificates
* directory.
*
* @param xmlResponse
* the response string from the BKU sign-request
* @param sigObj
* the SignatureObject that should be filled
* @throws SignatureException
* ErrorCode (303, 304)
* @see SignatureObject
* @see CodingHelper
* @see X509Cert
*/
private void parseCreateXMLResponse(String xmlResponse, SignatureObject sigObj) throws SignatureException
{
Pattern sig_val_p_s = Pattern.compile("<[\\w]*:?SignatureValue>");
Pattern sig_val_p_e = Pattern.compile("[\\w]*:?SignatureValue>");
Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName>");
Pattern iss_nam_p_e = Pattern.compile("[\\w]*:?X509IssuerName>");
Pattern sig_tim_p_s = Pattern.compile("<[\\w]*:?SigningTime>");
Pattern sig_tim_p_e = Pattern.compile("[\\w]*:?SigningTime>");
Pattern ser_num_p_s = Pattern.compile("<[\\w]*:?X509SerialNumber>");
Pattern ser_num_p_e = Pattern.compile("[\\w]*:?X509SerialNumber>");
Pattern sig_cer_p_s = Pattern.compile("<[\\w]*:?X509Certificate>");
Pattern sig_cer_p_e = Pattern.compile("[\\w]*:?X509Certificate>");
Pattern sig_cer_d_p_s = Pattern.compile("<[\\w]*:?CertDigest>");
Pattern sig_cer_d_p_e = Pattern.compile("[\\w]*:?CertDigest>");
Pattern dig_val_p_s = Pattern.compile("<[\\w]*:?DigestValue>");
Pattern dig_val_p_e = Pattern.compile("[\\w]*:?DigestValue>");
Matcher sig_val_m_s = sig_val_p_s.matcher(xmlResponse);
Matcher sig_val_m_e = sig_val_p_e.matcher(xmlResponse);
Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse);
Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse);
Matcher sig_tim_m_s = sig_tim_p_s.matcher(xmlResponse);
Matcher sig_tim_m_e = sig_tim_p_e.matcher(xmlResponse);
Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse);
Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse);
Matcher sig_cer_m_s = sig_cer_p_s.matcher(xmlResponse);
Matcher sig_cer_m_e = sig_cer_p_e.matcher(xmlResponse);
Matcher sig_cer_d_m_s = sig_cer_d_p_s.matcher(xmlResponse);
Matcher sig_cer_d_m_e = sig_cer_d_p_e.matcher(xmlResponse);
String sig_val = "";
String iss_nam = "";
String ser_num = "";
String sig_tim = "";
String sig_cer = "";
String sig_dig = "";
// SignatureValue
if (sig_val_m_s.find() && sig_val_m_e.find())
{
sig_val = xmlResponse.substring(sig_val_m_s.end(), sig_val_m_e.start());
sig_val = sig_val.replaceAll("\\s", "");
sigObj.setSignationValue(sig_val);
}
// X509IssuerName
if (iss_nam_m_s.find() && iss_nam_m_e.find())
{
iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start());
sigObj.setSignationIssuer(iss_nam);
}
// X509SerialNumber
if (ser_num_m_s.find() && ser_num_m_e.find())
{
ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start());
sigObj.setSignationSerialNumber(ser_num);
}
// SigningTime
if (sig_tim_m_s.find() && sig_tim_m_e.find())
{
sig_tim = xmlResponse.substring(sig_tim_m_s.end(), sig_tim_m_e.start());
sigObj.setSignationDate(sig_tim);
}
// CertDigest
if (sig_cer_d_m_s.find() && sig_cer_d_m_e.find())
{
String cert_digest = xmlResponse.substring(sig_cer_d_m_s.end(), sig_cer_d_m_e.start());
Matcher dig_val_m_s = dig_val_p_s.matcher(cert_digest);
Matcher dig_val_m_e = dig_val_p_e.matcher(cert_digest);
if (dig_val_m_s.find() && dig_val_m_e.find())
{
sig_dig = cert_digest.substring(dig_val_m_s.end(), dig_val_m_e.start());
sigObj.setX509CertificateDigest(sig_dig);
}
}
// extract Subject Name from X509Certificate
if (sig_cer_m_s.find() && sig_cer_m_e.find())
{
sig_cer = xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start());
sig_cer = sig_cer.replaceAll("\\s", "");
sigObj.setX509Certificate(sig_cer);
X509Cert cert = X509Cert.initByString(sig_cer);
if (cert.isX509Cert())
{
sigObj.setX509Certificate(cert.getCertString());
String serial_num = cert.getSerialNumber();
String subject_name = cert.getSubjectName();
if (!ser_num.equals(serial_num))
{
SignatureException se = new SignatureException(303, "Serialnumber of certificate and tag X509SerialNumber differs!");
throw se;
}
sigObj.setSignationName(subject_name);
}
}
// extract Signature Id's
String[] ids = new String[5];
ids[0] = extractId(xmlResponse, "signature-");
ids[1] = extractId(xmlResponse, "signed-data-reference-");
ids[2] = extractId(xmlResponse, "signed-data-object-");
ids[3] = extractId(xmlResponse, "etsi-data-reference-");
ids[4] = extractId(xmlResponse, "etsi-data-object-");
sigObj.setSignationIDs(ids);
}
/**
* This emthod extracts id-values from a text. The id is given by the name.
*
* @param text
* the id-value that should extract from
* @param name
* the id-key
* @return the value of the given key in the text
*/
private String extractId(String text, String name)
{
String id = null;
int start_idx = text.indexOf(name) + name.length();
int end_idx = text.indexOf("\"", start_idx);
id = text.substring(start_idx, end_idx);
if (logger_.isDebugEnabled())
{
logger_.debug("extract id:" + name + id);
}
return id;
}
/**
* This method reads the verify template from the file system and fills out
* the template with the SignatureObject values.
*
* @param normalizedText
* the normalized text to veryfied
* @param sigObject
* the SignatureObject holding the singature values
* @return the filled verify template string
* @throws SignatureException
* ErrorCode (311, 312, 313)
* @see SignatureObject
* @see CodingHelper
*/
public String getVerifyTemplate(String normalizedText,
SignatureObject sigObject) throws SignatureException
{
try
{
if (normalizedText == null || normalizedText.length() == 0)
{
SignatureException se = new SignatureException(311, "Document can not be verified because normalized text is empty.");
throw se;
}
if (sigObject == null)
{
SignatureException se = new SignatureException(312, "Document can not be verified because no signature object are set.");
throw se;
}
String verify_template = getVerifyTemplateFileName(sigObject.getSignationType());
String sig_prop_filename = getSigPropFileName(sigObject.getSignationType());
String ver_temp_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_template));
String sig_prop_str = FileHelper.readFromFile(SettingsReader.relocateFile(sig_prop_filename));
if (logger_.isDebugEnabled())
{
//logger_.debug(verify_template);
logger_.debug(sig_prop_filename);
}
String x509_cert_string = sigObject.getX509CertificateString();
if (x509_cert_string == null)
{
SignatureException se = new SignatureException(313, "Document certificate is not defined.");
throw se;
}
String cert_alg = settings_.getValueFromKey("cert.alg.ecdsa");
X509Cert x509_cert = sigObject.getX509Cert();
if (x509_cert.isRSA())
{
cert_alg = settings_.getValueFromKey("cert.alg.rsa");
}
String[] ids = sigObject.getSignationIds();
sig_prop_str = sig_prop_str.replaceFirst("SigningTimeReplace", sigObject.getSignationDate());
String issuer_name = sigObject.getSignationIssuer();
// The issuer is already unicode, so it mustn't be encoded again.
//byte[] issuer_name = CodingHelper.encodeUTF8(sigObject.getSignationIssuer());
// new String(issuer_name); // this would double encode the String, not to mention the missing encoding
sig_prop_str = sig_prop_str.replaceFirst("X509IssuerNameReplace", issuer_name);
sig_prop_str = sig_prop_str.replaceFirst("X509SerialNumberReplace", sigObject.getSignationSerialNumber());
sig_prop_str = sig_prop_str.replaceFirst("DigestValueX509CertificateReplace", sigObject.getX509CertificateDigest());
sig_prop_str = sig_prop_str.replaceFirst("SigIdReplace", ids[0]);
sig_prop_str = sig_prop_str.replaceFirst("SigDataRefReplace", ids[1]);
ver_temp_str = ver_temp_str.replaceFirst("CertAlgReplace", cert_alg);
ver_temp_str = ver_temp_str.replaceFirst("TemplateQualifyingPropertiesReplace", sig_prop_str);
byte[] sig_prop_code = CodingHelper.buildDigest(sig_prop_str.getBytes("UTF-8"));
String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code);
ver_temp_str = ver_temp_str.replaceFirst("DigestValueSignedPropertiesReplace", sig_prop_hash);
if (logger_.isDebugEnabled())
{
logger_.debug("build digest from QualifyingProperties:start");
//logger_.debug("DATA :" + sig_prop_str);
logger_.debug("DIGEST:" + sig_prop_hash);
logger_.debug("build digest from QualifyingProperties:end");
}
ver_temp_str = ver_temp_str.replaceFirst("SignatureValueReplace", sigObject.getSignationValue());
ver_temp_str = ver_temp_str.replaceFirst("X509CertificateReplace", x509_cert_string);
byte[] data_value = normalizedText.getBytes("UTF-8");
byte[] data_value_hash = CodingHelper.buildDigest(data_value);
String object_data_hash = CodingHelper.encodeBase64(data_value_hash);
// String object_data = new String(data_value);
if (logger_.isDebugEnabled())
{
logger_.debug("build digest from data object:start");
//logger_.debug("DATA :" + normalizedText);
logger_.debug("DIGEST:" + object_data_hash);
logger_.debug("build digest from data object:end");
}
//String raw_b64 = CodingHelper.encodeUTF8AsBase64(normalizedText);
String raw_b64 = CodingHelper.encodeBase64(data_value);
ver_temp_str = ver_temp_str.replaceFirst("Base64ContentReplace", raw_b64);
ver_temp_str = ver_temp_str.replaceFirst("DigestValueSignedDataReplace", object_data_hash);
ver_temp_str = ver_temp_str.replaceAll("SigIdReplace", ids[0]);
ver_temp_str = ver_temp_str.replaceAll("SigDataRefReplace", ids[1]);
ver_temp_str = ver_temp_str.replaceAll("SigDataObjURIReplace", ids[2]);
ver_temp_str = ver_temp_str.replaceAll("EtsiDataRefReplace", ids[3]);
ver_temp_str = ver_temp_str.replaceAll("EtsiDataObjURIReplace", ids[4]);
if (logger_.isDebugEnabled())
{
//logger_.debug("VERIFY REQUEST:" + ver_temp_str);
}
return ver_temp_str;
}
catch (UnsupportedEncodingException e)
{
throw new SignatureException(310, e);
}
}
/**
* This method parses the verify response string and return a
* SignatureResponse object. The SignatureResponse object is filled out by the
* response values from the BKU-response.
*
* @param xmlResponse
* the response values from the BKU-verify request
* @return SignatureResponse object
* @see SignatureResponse
*/
private SignatureResponse parseVerifyXMLResponse(String xmlResponse)
{
if (logger_.isInfoEnabled())
{
logger_.info("Try parsing the verify response");
}
Pattern sub_nam_p_s = Pattern.compile("
* All settings keys will be prefixed by this type. So to reuse the BKU * connector, a deriving class has to implement this method specifying an own * type. *
* * @return Returns the type of this BKU-like connector. */ protected String getType() { return CONNECTOR_INFORMATION.getIdentifier(); } }