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
26package sun.security.ssl;
27
28import java.io.IOException;
29import java.util.ArrayList;
30import java.util.Collection;
31
32import 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 */
56final 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
136