Source for gnu.java.security.sig.dss.DSSSignatureX509Codec

   1: /* DSSSignatureX509Codec.java -- X.509 encoder/decoder for DSS signatures
   2:    Copyright (C) 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.java.security.sig.dss;
  40: 
  41: import gnu.java.security.Registry;
  42: import gnu.java.security.der.DER;
  43: import gnu.java.security.der.DERReader;
  44: import gnu.java.security.der.DERValue;
  45: import gnu.java.security.der.DERWriter;
  46: import gnu.java.security.sig.ISignatureCodec;
  47: import gnu.java.security.util.DerUtil;
  48: 
  49: import java.io.ByteArrayOutputStream;
  50: import java.io.IOException;
  51: import java.math.BigInteger;
  52: import java.security.InvalidParameterException;
  53: import java.util.ArrayList;
  54: 
  55: /**
  56:  * An implementation of an {@link ISignatureCodec} that knows to encode and
  57:  * decode DSS signatures into the raw bytes which would constitute a DER-encoded
  58:  * form of the ASN.1 structure defined in RFC-2459, and RFC-2313 as described in
  59:  * the next paragraphs.
  60:  * <p>
  61:  * Digital signatures when transmitted in an X.509 certificates are encoded
  62:  * in DER (Distinguished Encoding Rules) as a BIT STRING; i.e.
  63:  *
  64:  * <pre>
  65:  * Certificate ::= SEQUENCE {
  66:  *   tbsCertificate       TBSCertificate,
  67:  *   signatureAlgorithm   AlgorithmIdentifier,
  68:  *   signature            BIT STRING
  69:  * }
  70:  * </pre>
  71:  * <p>
  72:  * The output of the encoder, and the input of the decoder, of this codec are
  73:  * then the <i>raw</i> bytes of such a BIT STRING; i.e. not the DER-encoded
  74:  * form itself.
  75:  * <p>
  76:  * RFC-2459 states that, for the Digital Signature Standard (DSS), which
  77:  * generates two MPIs, commonly called <code>r</code> and <code>s</code>, as the
  78:  * result of digitally signing a message, these two numbers will be transferred
  79:  * as the following ASN.1 structure:
  80:  *
  81:  * <pre>
  82:  *   Dss-Sig-Value ::= SEQUENCE {
  83:  *     r  INTEGER,
  84:  *     s  INTEGER
  85:  *   }
  86:  * </pre>
  87:  * <p>
  88:  * Client code that needs to build a DER BIT STRING <b>MUST</b> construct such
  89:  * an ASN.1 value. The following is an example of how to do this:
  90:  * <p>
  91:  * <pre>
  92:  * ...
  93:  * import gnu.java.security.der.BitString;
  94:  * import gnu.java.security.der.DER;
  95:  * import gnu.java.security.der.DERValue;
  96:  * ...
  97:  * DERValue bitString = new DERValue(DER.BIT_STRING, new BitString(sigBytes));
  98:  * ...
  99:  * </pre>
 100:  */
 101: public class DSSSignatureX509Codec
 102:     implements ISignatureCodec
 103: {
 104:   // implicit 0-arguments constructor
 105: 
 106:   public int getFormatID()
 107:   {
 108:     return Registry.X509_ENCODING_ID;
 109:   }
 110: 
 111:   /**
 112:    * Encodes a DSS Signature output as the <i>signature</i> raw bytes which can
 113:    * be used to construct an ASN.1 DER-encoded BIT STRING as defined in the
 114:    * documentation of this class.
 115:    *
 116:    * @param signature the output of the DSS signature algorithm; i.e. the value
 117:    *          returned by the invocation of
 118:    *          {@link gnu.java.security.sig.ISignature#sign()} method. In the
 119:    *          case of a DSS signature this is an array of two MPIs called
 120:    *          <code>r</code> and <code>s</code>.
 121:    * @return the raw bytes of a DSS signature which could be then used as the
 122:    *         contents of a BIT STRING as per rfc-2459.
 123:    * @throws InvalidParameterException if an exception occurs during the
 124:    *           marshalling process.
 125:    */
 126:   public byte[] encodeSignature(Object signature)
 127:   {
 128:     BigInteger[] rs = (BigInteger[]) signature;
 129: 
 130:     DERValue derR = new DERValue(DER.INTEGER, rs[0]);
 131:     DERValue derS = new DERValue(DER.INTEGER, rs[1]);
 132: 
 133:     ArrayList dssSigValue = new ArrayList(2);
 134:     dssSigValue.add(derR);
 135:     dssSigValue.add(derS);
 136:     DERValue derDssSigValue = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
 137:                                            dssSigValue);
 138:     byte[] result;
 139:     ByteArrayOutputStream baos = new ByteArrayOutputStream();
 140:     try
 141:       {
 142:         DERWriter.write(baos, derDssSigValue);
 143:         result = baos.toByteArray();
 144:       }
 145:     catch (IOException x)
 146:       {
 147:         InvalidParameterException y = new InvalidParameterException();
 148:         y.initCause(x);
 149:         throw y;
 150:       }
 151: 
 152:     return result;
 153:   }
 154: 
 155:   /**
 156:    * Decodes a <i>signature</i> as defined in the documentation of this class.
 157:    *
 158:    * @param input the byte array to unmarshall into a valid DSS signature
 159:    *          instance; i.e. an array of two MPIs. MUST NOT be null.
 160:    * @return an array of two MPIs, <code>r</code> and <code>s</code> in this
 161:    *         order, decoded from the designated <code>input</code>.
 162:    * @throw InvalidParameterException if an exception occurs during the
 163:    *        unmarshalling process.
 164:    */
 165:   public Object decodeSignature(byte[] input)
 166:   {
 167:     if (input == null)
 168:       throw new InvalidParameterException("Input bytes MUST NOT be null");
 169: 
 170:     BigInteger r, s;
 171:     DERReader der = new DERReader(input);
 172:     try
 173:       {
 174:         DERValue derDssSigValue = der.read();
 175:         DerUtil.checkIsConstructed(derDssSigValue, "Wrong Dss-Sig-Value field");
 176: 
 177:         DERValue val = der.read();
 178:         DerUtil.checkIsBigInteger(val, "Wrong R field");
 179:         r = (BigInteger) val.getValue();
 180:         val = der.read();
 181:         DerUtil.checkIsBigInteger(val, "Wrong S field");
 182:         s = (BigInteger) val.getValue();
 183:       }
 184:     catch (IOException x)
 185:       {
 186:         InvalidParameterException y = new InvalidParameterException();
 187:         y.initCause(x);
 188:         throw y;
 189:       }
 190: 
 191:     return new BigInteger[] { r, s };
 192:   }
 193: }