/*
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.ssl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import javax.net.ssl.SSLProtocolException;
/*
* [RFC5246] The client uses the "signature_algorithms" extension to
* indicate to the server which signature/hash algorithm pairs may be
* used in digital signatures. The "extension_data" field of this
* extension contains a "supported_signature_algorithms" value.
*
* enum {
* none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
* sha512(6), (255)
* } HashAlgorithm;
*
* enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
* SignatureAlgorithm;
*
* struct {
* HashAlgorithm hash;
* SignatureAlgorithm signature;
* } SignatureAndHashAlgorithm;
*
* SignatureAndHashAlgorithm
* supported_signature_algorithms<2..2^16-2>;
*/
final class SignatureAlgorithmsExtension extends HelloExtension {
private Collection<SignatureAndHashAlgorithm> algorithms;
private int algorithmsLen; // length of supported_signature_algorithms
SignatureAlgorithmsExtension(
Collection<SignatureAndHashAlgorithm> signAlgs) {
super(ExtensionType.EXT_SIGNATURE_ALGORITHMS);
algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs);
algorithmsLen =
SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size();
}
SignatureAlgorithmsExtension(HandshakeInStream s, int len)
throws IOException {
super(ExtensionType.EXT_SIGNATURE_ALGORITHMS);
algorithmsLen = s.getInt16();
if (algorithmsLen == 0 || algorithmsLen + 2 != len) {
throw new SSLProtocolException("Invalid " + type + " extension");
}
algorithms = new ArrayList<SignatureAndHashAlgorithm>();
int remains = algorithmsLen;
int sequence = 0;
while (remains > 1) { // needs at least two bytes
int hash = s.getInt8(); // hash algorithm
int signature = s.getInt8(); // signature algorithm
SignatureAndHashAlgorithm algorithm =
SignatureAndHashAlgorithm.valueOf(hash, signature, ++sequence);
algorithms.add(algorithm);
remains -= 2; // one byte for hash, one byte for signature
}
if (remains != 0) {
throw new SSLProtocolException("Invalid server_name extension");
}
}
Collection<SignatureAndHashAlgorithm> getSignAlgorithms() {
return algorithms;
}
@Override
int length() {
return 6 + algorithmsLen;
}
@Override
void send(HandshakeOutStream s) throws IOException {
s.putInt16(type.id);
s.putInt16(algorithmsLen + 2);
s.putInt16(algorithmsLen);
for (SignatureAndHashAlgorithm algorithm : algorithms) {
s.putInt8(algorithm.getHashValue()); // HashAlgorithm
s.putInt8(algorithm.getSignatureValue()); // SignatureAlgorithm
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
boolean opened = false;
for (SignatureAndHashAlgorithm signAlg : algorithms) {
if (opened) {
sb.append(", " + signAlg.getAlgorithmName());
} else {
sb.append(signAlg.getAlgorithmName());
opened = true;
}
}
return "Extension " + type + ", signature_algorithms: " + sb;
}
}