/*
* DSS - Digital Signature Services
*
* Copyright (C) 2013 European Commission, Directorate-General Internal Market and Services (DG MARKT), B-1049 Bruxelles/Brussel
*
* Developed by: 2013 ARHS Developments S.A. (rue Nicolas Bové 2B, L-1253 Luxembourg) http://www.arhs-developments.com
*
* This file is part of the "DSS - Digital Signature Services" project.
*
* "DSS - Digital Signature Services" is free software: you can redistribute it and/or modify it under the terms of
* the GNU Lesser General Public License as published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* DSS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* "DSS - Digital Signature Services". If not, see <http://www.gnu.org/licenses/>.
*/
package eu.europa.ec.markt.dss.signature;
import java.io.IOException;
import eu.europa.ec.markt.dss.EncryptionAlgorithm;
import eu.europa.ec.markt.dss.exception.DSSException;
/**
* This is the utility class to manipulate different signature types.
*
* @author bielecro
*/
public final class DSSSignatureUtils {
private DSSSignatureUtils() {
}
/**
* Converts the binary signature value to the Xml DSig format in function of used algorithm
*
* @param algorithm Signature algorithm used to create the signatureValue
* @param signatureValue
* @return
*/
public static byte[] convertToXmlDSig(final EncryptionAlgorithm algorithm, byte[] signatureValue) {
try {
if (algorithm == EncryptionAlgorithm.ECDSA) {
return DSSSignatureUtils.convertECDSAASN1toXMLDSIG(signatureValue);
} else if (algorithm == EncryptionAlgorithm.DSA) {
return DSSSignatureUtils.convertDSAASN1toXMLDSIG(signatureValue);
}
return signatureValue;
} catch (IOException e) {
throw new DSSException(e);
}
}
/**
* Converts an ASN.1 DSA value to a XML Signature DSA Value.
* <p/>
* The JAVA JCE DSA Signature algorithm creates ASN.1 encoded (r,s) value pairs; the XML Signature requires the core
* BigInteger values.
*
* @param asn1Bytes
* @return the decode bytes
* @throws IOException
* @see <A HREF="http://www.w3.org/TR/xmldsig-core/#dsa-sha1">6.4.1 DSA</A>
*/
public static byte[] convertDSAASN1toXMLDSIG(final byte asn1Bytes[]) throws IOException {
// Using BC to deal with BigInt DSA signature value
// ByteArrayInputStream bIn = new ByteArrayInputStream(asn1Bytes);
// ASN1InputStream aIn = new ASN1InputStream(bIn);
// ASN1Sequence asn1Sequence = (ASN1Sequence) aIn.readObject();
//
//
// final DERInteger rDERInteger = (DERInteger) asn1Sequence.getObjectAt(0);
// final BigInteger r = rDERInteger.getValue();
// final byte[] rBytes = r.toByteArray();
//
// final DERInteger sDERInteger = (DERInteger) asn1Sequence.getObjectAt(1);
// final BigInteger s = sDERInteger.getValue();
// final byte[] sBytes = s.toByteArray();
final byte rLength = asn1Bytes[3];
int ii = rLength;
for (; (ii > 0) && (asn1Bytes[(4 + rLength) - ii] == 0); ii--) {
// System.out.println((4 + rLength) - ii + ": " + asn1Bytes[(4 + rLength) - ii]);
}
final byte sLength = asn1Bytes[5 + rLength];
int jj;
for (jj = sLength; (jj > 0) && (asn1Bytes[(6 + rLength + sLength) - jj] == 0); jj--) {
}
if ((asn1Bytes[0] != 48) || (asn1Bytes[1] != asn1Bytes.length - 2) || (asn1Bytes[2] != 2) || (ii > 20) || (asn1Bytes[4 + rLength] != 2) || (jj > 20)) {
throw new IOException("Invalid ASN.1 format of DSA signature");
}
byte xmlDsigBytes[] = new byte[40];
System.arraycopy(asn1Bytes, (4 + rLength) - ii, xmlDsigBytes, 20 - ii, ii);
System.arraycopy(asn1Bytes, (6 + rLength + sLength) - jj, xmlDsigBytes, 40 - jj, jj);
// byte xmlDsigBytes[] = new byte[rBytes.length + sBytes.length];
// System.arraycopy(rBytes, 0, xmlDsigBytes, 0, rBytes.length);
// System.arraycopy(sBytes, 0, xmlDsigBytes, rBytes.length, sBytes.length);
return xmlDsigBytes;
}
/**
* Converts an ASN.1 ECDSA value to a XML Signature ECDSA Value.
* <p/>
* The JAVA JCE ECDSA Signature algorithm creates ASN.1 encoded (r,s) value pairs; the XML Signature requires the
* core BigInteger values.
*
* @param asn1Bytes
* @return the decode bytes
* @throws IOException
* @see <A HREF="http://www.w3.org/TR/xmldsig-core/#dsa-sha1">6.4.1 DSA</A>
* @see <A HREF="ftp://ftp.rfc-editor.org/in-notes/rfc4050.txt">3.3. ECDSA Signatures</A>
*/
public static byte[] convertECDSAASN1toXMLDSIG(byte asn1Bytes[]) throws IOException {
if (asn1Bytes.length < 8 || asn1Bytes[0] != 48) {
throw new IOException("Invalid ASN.1 format of ECDSA signature");
}
int offset;
if (asn1Bytes[1] > 0) {
offset = 2;
} else if (asn1Bytes[1] == (byte) 0x81) {
offset = 3;
} else {
throw new IOException("Invalid ASN.1 format of ECDSA signature");
}
byte rLength = asn1Bytes[offset + 1];
int i;
for (i = rLength; (i > 0) && (asn1Bytes[(offset + 2 + rLength) - i] == 0); i--) {
}
byte sLength = asn1Bytes[offset + 2 + rLength + 1];
int j;
for (j = sLength; (j > 0) && (asn1Bytes[(offset + 2 + rLength + 2 + sLength) - j] == 0); j--) {
}
int rawLen = Math.max(i, j);
if ((asn1Bytes[offset - 1] & 0xff) != asn1Bytes.length - offset || (asn1Bytes[offset - 1] & 0xff) != 2 + rLength + 2 + sLength || asn1Bytes[offset] != 2 || asn1Bytes[offset + 2 + rLength] != 2) {
throw new IOException("Invalid ASN.1 format of ECDSA signature");
}
byte xmldsigBytes[] = new byte[2 * rawLen];
System.arraycopy(asn1Bytes, (offset + 2 + rLength) - i, xmldsigBytes, rawLen - i, i);
System.arraycopy(asn1Bytes, (offset + 2 + rLength + 2 + sLength) - j, xmldsigBytes, 2 * rawLen - j, j);
return xmldsigBytes;
}
}