| /* DSSSignatureX509Codec.java -- X.509 encoder/decoder for DSS signatures | |
| Copyright (C) 2006 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath 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 | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package gnu.java.security.sig.dss; | |
| import gnu.java.security.Registry; | |
| import gnu.java.security.der.DER; | |
| import gnu.java.security.der.DERReader; | |
| import gnu.java.security.der.DERValue; | |
| import gnu.java.security.der.DERWriter; | |
| import gnu.java.security.sig.ISignatureCodec; | |
| import gnu.java.security.util.DerUtil; | |
| import java.io.ByteArrayOutputStream; | |
| import java.io.IOException; | |
| import java.math.BigInteger; | |
| import java.security.InvalidParameterException; | |
| import java.util.ArrayList; | |
| /** | |
| * An implementation of an {@link ISignatureCodec} that knows to encode and | |
| * decode DSS signatures into the raw bytes which would constitute a DER-encoded | |
| * form of the ASN.1 structure defined in RFC-2459, and RFC-2313 as described in | |
| * the next paragraphs. | |
| * <p> | |
| * Digital signatures when transmitted in an X.509 certificates are encoded | |
| * in DER (Distinguished Encoding Rules) as a BIT STRING; i.e. | |
| * | |
| * <pre> | |
| * Certificate ::= SEQUENCE { | |
| * tbsCertificate TBSCertificate, | |
| * signatureAlgorithm AlgorithmIdentifier, | |
| * signature BIT STRING | |
| * } | |
| * </pre> | |
| * <p> | |
| * The output of the encoder, and the input of the decoder, of this codec are | |
| * then the <i>raw</i> bytes of such a BIT STRING; i.e. not the DER-encoded | |
| * form itself. | |
| * <p> | |
| * RFC-2459 states that, for the Digital Signature Standard (DSS), which | |
| * generates two MPIs, commonly called <code>r</code> and <code>s</code>, as the | |
| * result of digitally signing a message, these two numbers will be transferred | |
| * as the following ASN.1 structure: | |
| * | |
| * <pre> | |
| * Dss-Sig-Value ::= SEQUENCE { | |
| * r INTEGER, | |
| * s INTEGER | |
| * } | |
| * </pre> | |
| * <p> | |
| * Client code that needs to build a DER BIT STRING <b>MUST</b> construct such | |
| * an ASN.1 value. The following is an example of how to do this: | |
| * <p> | |
| * <pre> | |
| * ... | |
| * import gnu.java.security.der.BitString; | |
| * import gnu.java.security.der.DER; | |
| * import gnu.java.security.der.DERValue; | |
| * ... | |
| * DERValue bitString = new DERValue(DER.BIT_STRING, new BitString(sigBytes)); | |
| * ... | |
| * </pre> | |
| */ | |
| public class DSSSignatureX509Codec | |
| implements ISignatureCodec | |
| { | |
| // implicit 0-arguments constructor | |
| public int getFormatID() | |
| { | |
| return Registry.X509_ENCODING_ID; | |
| } | |
| /** | |
| * Encodes a DSS Signature output as the <i>signature</i> raw bytes which can | |
| * be used to construct an ASN.1 DER-encoded BIT STRING as defined in the | |
| * documentation of this class. | |
| * | |
| * @param signature the output of the DSS signature algorithm; i.e. the value | |
| * returned by the invocation of | |
| * {@link gnu.java.security.sig.ISignature#sign()} method. In the | |
| * case of a DSS signature this is an array of two MPIs called | |
| * <code>r</code> and <code>s</code>. | |
| * @return the raw bytes of a DSS signature which could be then used as the | |
| * contents of a BIT STRING as per rfc-2459. | |
| * @throws InvalidParameterException if an exception occurs during the | |
| * marshalling process. | |
| */ | |
| public byte[] encodeSignature(Object signature) | |
| { | |
| BigInteger[] rs = (BigInteger[]) signature; | |
| DERValue derR = new DERValue(DER.INTEGER, rs[0]); | |
| DERValue derS = new DERValue(DER.INTEGER, rs[1]); | |
| ArrayList dssSigValue = new ArrayList(2); | |
| dssSigValue.add(derR); | |
| dssSigValue.add(derS); | |
| DERValue derDssSigValue = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, | |
| dssSigValue); | |
| byte[] result; | |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
| try | |
| { | |
| DERWriter.write(baos, derDssSigValue); | |
| result = baos.toByteArray(); | |
| } | |
| catch (IOException x) | |
| { | |
| InvalidParameterException y = new InvalidParameterException(); | |
| y.initCause(x); | |
| throw y; | |
| } | |
| return result; | |
| } | |
| /** | |
| * Decodes a <i>signature</i> as defined in the documentation of this class. | |
| * | |
| * @param input the byte array to unmarshall into a valid DSS signature | |
| * instance; i.e. an array of two MPIs. MUST NOT be null. | |
| * @return an array of two MPIs, <code>r</code> and <code>s</code> in this | |
| * order, decoded from the designated <code>input</code>. | |
| * @throw InvalidParameterException if an exception occurs during the | |
| * unmarshalling process. | |
| */ | |
| public Object decodeSignature(byte[] input) | |
| { | |
| if (input == null) | |
| throw new InvalidParameterException("Input bytes MUST NOT be null"); | |
| BigInteger r, s; | |
| DERReader der = new DERReader(input); | |
| try | |
| { | |
| DERValue derDssSigValue = der.read(); | |
| DerUtil.checkIsConstructed(derDssSigValue, "Wrong Dss-Sig-Value field"); | |
| DERValue val = der.read(); | |
| DerUtil.checkIsBigInteger(val, "Wrong R field"); | |
| r = (BigInteger) val.getValue(); | |
| val = der.read(); | |
| DerUtil.checkIsBigInteger(val, "Wrong S field"); | |
| s = (BigInteger) val.getValue(); | |
| } | |
| catch (IOException x) | |
| { | |
| InvalidParameterException y = new InvalidParameterException(); | |
| y.initCause(x); | |
| throw y; | |
| } | |
| return new BigInteger[] { r, s }; | |
| } | |
| } |