1 /*
   2  * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.IOException;
  29 import java.util.ArrayList;
  30 import java.util.Collection;
  31 
  32 import javax.net.ssl.SSLProtocolException;
  33 
  34 /*
  35  * [RFC5246] The client uses the "signature_algorithms" extension to
  36  * indicate to the server which signature/hash algorithm pairs may be
  37  * used in digital signatures.  The "extension_data" field of this
  38  * extension contains a "supported_signature_algorithms" value.
  39  *
  40  *     enum {
  41  *         none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
  42  *         sha512(6), (255)
  43  *     } HashAlgorithm;
  44  *
  45  *     enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
  46  *       SignatureAlgorithm;
  47  *
  48  *     struct {
  49  *           HashAlgorithm hash;
  50  *           SignatureAlgorithm signature;
  51  *     } SignatureAndHashAlgorithm;
  52  *
  53  *     SignatureAndHashAlgorithm
  54  *       supported_signature_algorithms<2..2^16-2>;
  55  */
  56 final class SignatureAlgorithmsExtension extends HelloExtension {
  57 
  58     private Collection<SignatureAndHashAlgorithm> algorithms;
  59     private int algorithmsLen;  // length of supported_signature_algorithms
  60 
  61     SignatureAlgorithmsExtension(
  62             Collection<SignatureAndHashAlgorithm> signAlgs) {
  63 
  64         super(ExtensionType.EXT_SIGNATURE_ALGORITHMS);
  65 
  66         algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs);
  67         algorithmsLen =
  68             SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size();
  69     }
  70 
  71     SignatureAlgorithmsExtension(HandshakeInStream s, int len)
  72                 throws IOException {
  73         super(ExtensionType.EXT_SIGNATURE_ALGORITHMS);
  74 
  75         algorithmsLen = s.getInt16();
  76         if (algorithmsLen == 0 || algorithmsLen + 2 != len) {
  77             throw new SSLProtocolException("Invalid " + type + " extension");
  78         }
  79 
  80         algorithms = new ArrayList<SignatureAndHashAlgorithm>();
  81         int remains = algorithmsLen;
  82         int sequence = 0;
  83         while (remains > 1) {   // needs at least two bytes
  84             int hash = s.getInt8();         // hash algorithm
  85             int signature = s.getInt8();    // signature algorithm
  86 
  87             SignatureAndHashAlgorithm algorithm =
  88                 SignatureAndHashAlgorithm.valueOf(hash, signature, ++sequence);
  89             algorithms.add(algorithm);
  90             remains -= 2;  // one byte for hash, one byte for signature
  91         }
  92 
  93         if (remains != 0) {
  94             throw new SSLProtocolException("Invalid server_name extension");
  95         }
  96     }
  97 
  98     Collection<SignatureAndHashAlgorithm> getSignAlgorithms() {
  99         return algorithms;
 100     }
 101 
 102     @Override
 103     int length() {
 104         return 6 + algorithmsLen;
 105     }
 106 
 107     @Override
 108     void send(HandshakeOutStream s) throws IOException {
 109         s.putInt16(type.id);
 110         s.putInt16(algorithmsLen + 2);
 111         s.putInt16(algorithmsLen);
 112 
 113         for (SignatureAndHashAlgorithm algorithm : algorithms) {
 114             s.putInt8(algorithm.getHashValue());      // HashAlgorithm
 115             s.putInt8(algorithm.getSignatureValue()); // SignatureAlgorithm
 116         }
 117     }
 118 
 119     @Override
 120     public String toString() {
 121         StringBuilder sb = new StringBuilder();
 122         boolean opened = false;
 123         for (SignatureAndHashAlgorithm signAlg : algorithms) {
 124             if (opened) {
 125                 sb.append(", " + signAlg.getAlgorithmName());
 126             } else {
 127                 sb.append(signAlg.getAlgorithmName());
 128                 opened = true;
 129             }
 130         }
 131 
 132         return "Extension " + type + ", signature_algorithms: " + sb;
 133     }
 134 }
 135